학습 2: 하나의 작은 데이터베이스 탄생

13564 단어 learningrustjourney
안녕하세요!오늘 밤 우리는 스페인 무르시아에서 온 하도리를 한 잔 마셔야 하기 때문에 나의 조국을 향해 소리를 질렀다. 네가 견지할 수 있기를 바란다. 나는 최근 상황이 그리 좋지 않다고 들었다.특별히 복잡하지 않다면, 그것은 사람을 즐겁게 하는 건조함으로 바삭바삭한 푸른 사과처럼 맛볼 수 있다.
특별히 복잡하지 않을 또 다른 일은 내가 이 프로젝트의 다음 계획에 대한 것이다.지난번에 나는 Rust에서 VCS 버전 제어 시스템, 예를 들어Git나Mercurial을 만들어 보겠다고 말했다.우리는 파일을 읽고 내용을 출력할 수 있을 정도로 일을 실행할 수 있기 때문에 그리 멀지 않다.오늘 나는 언어에 대한 농락에서 벗어나 내가 실현할 수 없는 것이 아니라 적어도 이론적으로 유용한 것을 만들 수 있는지를 보고 싶다.큰 프로젝트를 처리할 때, 특히 유일한 동기가 공부를 하거나 어리석은 블로그 글을 쓸 때, 중요한 것은 서로 추진하는 작은 이정표가 있어야 한다. 그러면 진도를 평가하고 배우면서 배울 수 있다.
나의 첫 번째 이정표는 비분지, 고객 전용 투기를 만드는 것이라고 나는 결정했다.당신에게git 저장소가 있는 것처럼, 당신은 당신의 주 지점만 있고, 원격 전송은 없습니다.저장소의 이전 상태를 모두 보고 롤백할 수 있지만 공동 작업 기능은 없기 때문에 여전히 유용합니다.이것은 매우 간단한 시작이지만, 또한 더욱 충실한 투기의 중요한 구성 부분이기도 하다.규모가 아무리 크더라도 지점의 역사를 추적해야 한다.
이런 시스템의 체계 구조는 매우 간단할 수 있다. 저장소는 시간순으로 배열된 수정 목록으로 구성되어 있으며, 각 수정은 하나 이상의 변경 사항을 포함한다.모든 변경 사항은 파일에 적용되는 변환입니다.최소한 처음부터, 우리는 모든 변경 모델링을 완전히 파일을 바꾸는 이전 상태로 만들 것입니다. 왜냐하면 우리가 협동 기능이 없을 때 차이와 합병을 할 필요가 없기 때문입니다.우리는 다양한 방식으로 이 모든 내용을 저장할 수 있지만, 나는 SQLite가 합리적으로 확장할 수 있는 해결 방안으로 bindings for Rust 사용할 수 있을 것 같다고 생각한다.나는 데이터베이스 연결을 수동으로 관리하는 것을 기대하지 않지만, 이것은 학습의 일부분이다.
첫 번째 단계로, 나는 SQLite 상자를 내 화물에 추가해서 그것을 설치했다.톰:
[dependencies]
rusqlite = "0.24.0"
나는 뛴다cargo build.화물 추출과 건조에는 문제가 없기 때문에, 지금은 우리 저장소의 상태를 저장할 수 있는 데이터베이스를 만들 수 있을 것이다.git에서 영감을 얻어 나는 그것을 .ribbit/repo.db에 저장했다.이제 효과가 있는지 살펴보겠습니다.
use rusqlite::Connection;

fn create_database() -> rusqlite::Result<Connection> {
    let path = "./.ribbit/repo.db";
    let db = Connection::open(&path)?;
    return Ok(db);
}

fn main() -> rusqlite::Result<()> {
    let db = create_database()?;

    Ok(())
}
나는 데이터베이스 생성 논리를 자신의 함수에 넣었다.나는 내가 쓴 논리를 천천히 함수로 나누기 시작하고 싶다.최종적으로, 나는 여러 개의 판자 상자를 만들어서 코드를 관련 모듈에 구성할 것이다. 만약 모든 내용이 하나의 큰main () 함수에 없다면, 이것은 더욱 쉽다.
내가 그것을 실행하려고 시도할 때, 컴파일러가 'sqlite3.lib' 를 찾을 수 없다고 불평하는 오류가 발생할 것입니다.나는 내 기계에 SQLite가 설치되어 있지 않다고 생각한다.나는 이미 그것의 존재에 익숙해졌지만, 나는 틀림없이 이 노트북의 어떤 항목에서도 그것을 사용한 적이 없을 것이다.나는 초콜릿을 통해 설치했지만 여전히 안 된다.나는 정말 밤에 C 라이브러리를 Windows에서 어떻게 실행하는지 배우고 싶지 않다. 그래서 나는 rusqlite 자술 파일의 조언에 따라 내 화물의 원본 코드에서 SQLite를 컴파일하는 옵션을 사용한다.톰:
[dependencies.rusqlite]
version = "0.24.0"
features = ["bundled"]
Ribbit이 다시 컴파일되었지만 데이터베이스 파일을 열 수 없는 오류가 반환되었습니다.나는 Connection::open 데이터베이스 파일을 만드는 데 사용되는 것이 확실하지만, 만약 데이터베이스 파일이 존재하지 않는다면, 데이터베이스 파일이 있어야 할 폴더를 만들지 못할 수도 있기 때문에, 어떻게 폴더를 만드는지 알아야 한다.나는 std::fs crate에서 필요한 함수를 찾았지만 천진난만한 실현은 컴파일할 수 없었다.
fn create_database() -> rusqlite::Result<Connection> {
    fs::create_dir("./.ribbit")?;
    let db = Connection::open("./.ribbit/repo.db")?;
    return Ok(db);
}
사실이 증명하듯이, fs 박스에서 되돌아오는 오류는rusqlite 박스에서 되돌아오는 오류와 다르기 때문에, 나는 ? 다음에 create_dir를 붙일 수 없고, 오류가 되돌아올 때 단락을 기대할 수 없다.사용자 정의 결과 형식을 만들 수 있습니다. 오류가 있을 수 있지만, 저장소 데이터를 저장할 디렉터리를 만들 수 없으면 프로그램에 다른 기능이 없을 것 같습니다. 그래서 .unwrap() 방법을 사용하기로 결정했습니다. 오류가 발생하면 프로그램의 실행이 중단될 수 있습니다.프로그램이 종료되었기 때문에, 공황은 유형 시스템에서 처리할 필요가 없지만, 이것은 확실히 앞으로 오류를 포착할 수 없다는 것을 의미한다.
fn create_database() -> rusqlite::Result<Connection> {
    fs::create_dir("./.ribbit").unwrap();
    let db = Connection::open("./.ribbit/repo.db")?;
    return Ok(db);
}
이것은 쓸모가 있다!빈 "/.ribbit/repo.db"파일을 만들었습니다. .ribbit 를 데이터베이스에 추가해야 한다는 것을 알려 줍니다.gitignore 파일입니다.그러나 내가 코드를 다시 실행하려고 시도했을 때, 나는 문제를 발견했다.프로그램은 존재하는 디렉터리를 만들 수 없기 때문에 공황에 빠졌다.데이터베이스를 계속 만들 수 있기 때문에 실행을 중지하는 어리석은 이유입니다. 만들기 전에 디렉터리가 있는지 확인해야 합니다.
fn create_database() -> rusqlite::Result<Connection> {
    let ribbit_path = "./.ribbit";
    match fs::metadata(&ribbit_path) {
        Ok(_) => (),
        Err(error) => match error.kind() {
            io::ErrorKind::AlreadyExists => fs::create_dir(&ribbit_path).unwrap(),
            other_error => panic!(other_error),
        },
    };
    let db = Connection::open("./.ribbit/repo.db")?;
    return Ok(db);
}
수정 증가 2020-08-31
이 코드는 잘못된 것이다.일치하는 오류 형식은 존재하지 않는 파일입니다. 존재하는 파일이 아닙니다.이것들은 모두 심야 인코딩의 위험이다. 나는 내가 하고 있는 일을 헷갈린 후에 그것을 정확하게 테스트하지 못했다.본 시리즈의 일부 목표는 학습 과정에서 언제, 왜 오류가 발생했는지 보여주는 것입니다. 그래서 저는 다음 호에서 복구하기 전에 이 코드를 여기에 남기고 싶지 않습니다. 그러나 이 코드를 복제하는 사람은 아무도 원하지 않습니다. 이 코드가 설명한 대로 작동해야 한다고 생각합니다.
말단 교정
이것은 내가 몇 년 전에 Elixir에서 배운 언어 특성 중 하나인 패턴 일치를 사용했다.일치하는 입력이 왼쪽과 일치하고 일치에 선언된 변수가 구조의 해당 위치에 값을 저장하는 경우에만 일치 블록의 브랜치가 실행됩니다.이것은 설명하기 어렵지만, 쓰기에 매우 직관적이어서, 우리는 결과에서 오류를 쉽게 추출하고, 그 유형과 일치시킬 수 있다.현재 부족한 유일한 단계는 우리가 필요로 하는 데이터베이스 테이블을 만드는 것이다.
fn create_database() -> rusqlite::Result<Connection> {
    let ribbit_path = "./.ribbit";
    match fs::metadata(&ribbit_path) {
        Ok(_) => (),
        Err(error) => match error.kind() {
            io::ErrorKind::AlreadyExists => fs::create_dir(&ribbit_path).unwrap(),
            other_error => panic!(other_error),
        },
    };
    let db = Connection::open("./.ribbit/repo.db")?;
    db.execute(
        "create table if not exists changes (
            id text primary key,
            date_created integer not null,
            revision_id text not null,
            file_path text not null
        )",
        rusqlite::NO_PARAMS,
    )?;
    return Ok(db);
}
미래에 나는 우리가 최소한 수정을 해야만 자신의 표를 만들 수 있다는 것을 확신한다. 그러면 그들이 이와 관련된 소식을 얻을 수 있을 것이다. 그러나 현재 수정과 문서는 변경표의 ID로만 존재하면 충분하다.나는 SQLEctron에서 데이터베이스를 열고 테이블이 만들어졌는지 확인함으로써 이 코드가 유효한지 확인한다.
이 밤이면 충분해.비록 나의 대부분의 코드는 여전히 각종 문서 원본에서 나온 복사와 붙여넣기 예시 코드를 수정함으로써 작성되었지만, 나는 Rust의 문법에 대해 갈수록 자신감을 느낀다.다음에는 ribbit에 명령을 추가하기 위해 명령줄 파라미터를 읽는 방법을 연구하고 저장소를 초기화할 뿐만 아니라 수정된 부분도 저장할 것입니다.

좋은 웹페이지 즐겨찾기