Docsの目次

SQLite

目次 · 前:HTTPとHTML · 関数の引数:組み込み関数

このページの目次

最初の読み書き

保存する型をclassで定義し、db_openでDBを開き、db_execでテーブルを作ります。DBの操作は非同期で、失敗し得るためtry awaitを使います。

次のコードをdatabase.nagiとして保存し、nagic run database.nagiで実行します。メモリ内のDBへ1件追加し、保存した名前を表示します。

class User:
    id: i64
    name: str
    age: i32

async def main() -> Result[unit, Error]:
    db = try await db_open(":memory:")
    try await db_exec(db, "CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER NOT NULL)")
    user = try await db_insert[User](db, "INSERT INTO users(name, age) VALUES (?1, ?2) RETURNING id, name, age", "Nagi", 18)
    print(user.name)
    return ok(print("保存できた"))

ファイルに保存するならdb_open("app.sqlite")にします。相対DBパスはプログラムを実行したディレクトリが基準です。ソースを基準にするimportやinclude_textとは異なります。

db_insert[User]の[User]は返したい型です。RETURNINGの列名と型をclassに合わせます。値は?1などへbindし、SQL文字列へ連結しないでください。

行を返す関数の型引数にはclassを指定します。db_all[i64]やdb_query[str]は使えず、checkでエラーになります。1列だけ読む場合も、その列を持つclassを定義してください。

操作 書き方 await後の戻り値
テーブル作成など db_exec(db, sql) Result[i64, Error]
全行読む db_all[User](db, sql) Result[List[User], Error]
1行読む db_query[User](db, sql, id) Result[User?, Error]
追加 db_insert[User](db, sql, name, age) Result[User, Error]
更新 db_update[User](db, sql, id, name, age) Result[User, Error]
削除など db_write(db, sql, id) Result[i64, Error]

db_execの行数は、その呼び出しで実行したSQL全体の変更件数です。テーブル作成やSELECTだけなら0を返します。複数の文の変更を合計し、トリガーや外部キー制約による変更もSQLiteの集計に従って含めます。

現時点ではbind引数の形が固定です。query / writeはi64が1つ、allはなし、insertはstrとi32、updateはi64・str・i32です。name / ageという列名は必須ではなく、同じ引数型を持つ別のテーブルにも使えます。

APIから読む

SQLの値は引数として渡します。文字列を連結してSQLを組み立てる必要はありません。読み込んだ行は、指定したclassのフィールドへ入ります。

次は上のUser型を使ったhandlerの断片です。

async def get_user(db: Db, id: i64) -> Result[User?, Error]:
    return await db_query[User](db, "SELECT id, name, age FROM users WHERE id = ?1", id)

classのListをforで走査する場合、現在はCopy classのみ対応します。上のUserは所有strを持つため、そのままfor user in usersとは書けません。HTTP handlerでreturn await db_all[User](...)と返してJSON配列にすることはできます。完成例はCRUD APIやタスク管理を参照してください。

実装と制約

SQLiteへの操作は専用のスレッドで順に実行します。待ち行列は64件までです。Nagi側は非同期に結果を待ちますが、SQLiteそのものの読み書きはそのスレッドで行います。

SQLの準備結果と列名の解決結果を再利用します。文字列やバイト列を返すときは、行の処理が終わったあとも保持できるよう、所有する値を作ります。

任意個数のSQL引数、トランザクション専用API、接続プール、ビルド時のスキーマ検査は未対応です。SQLや列の名前・型に問題がある場合は、実行時にResultのエラーになります。

HTTPの待機期限が切れても、すでに受け付けたDB操作が完了し、書き込みが保存される場合があります。呼び出し元のキャンセルで、書き込みが取り消される保証はありません。

Nagi 0.1のドキュメントこのページのソース