🦥

Node.jsネイティブSQLiteモジュールどうでしょう

に公開

はじめに

https://nodejs.org/api/sqlite.html

Node.js v22.5.0で、待望のネイティブSQLiteモジュール(node:sqlite)が導入されました。
これまでNode.jsでSQLiteを扱うにはbetter-sqlite3node-sqlite3といった外部ライブラリのインストールが必須でしたが、これからはNode.js本体だけでSQLiteデータベースを手軽に利用できます。

このモジュールは執筆時点ではアクティブな開発(Stability: 1.1 - Active development)段階にあり、新しいバージョンがリリースされるたびに意欲的な機能追加や改善が続けられています。

この記事では、node:sqliteモジュールの基本的な使い方から始め、v22.5.0からv24.11.0までのアップデートの歴史を詳細に追い、このモジュールがどのように進化してきたのか、その全貌を明らかにします。

基本的な使い方

node:sqliteを利用するのに、追加のnpm installは不要です。
Node.js v22.5.0以降の環境であれば、node:スキームを使ってすぐにインポートできます。

基本的な使い方は非常に直感的です。

import { DatabaseSync } from 'node:sqlite';
const database = new DatabaseSync(':memory:');

// Execute SQL statements from strings.
database.exec(`
  CREATE TABLE data(
    key INTEGER PRIMARY KEY,
    value TEXT
  ) STRICT
`);
// Create a prepared statement to insert data into the database.
const insert = database.prepare('INSERT INTO data (key, value) VALUES (?, ?)');
// Execute the prepared statement with bound values.
insert.run(1, 'hello');
insert.run(2, 'world');
// Create a prepared statement to read data from the database.
const query = database.prepare('SELECT * FROM data ORDER BY key');
// Execute the prepared statement and log the result set.
console.log(query.all());
// Prints: [ { key: 1, value: 'hello' }, { key: 2, value: 'world' } ]

node:sqlite詳細アップデート全史

ここからが本題です。
node:sqliteがどのように機能を追加し、洗練されていったのか、バージョンごとにその歩みを詳しく見ていきましょう。

v22.5.0: すべてはここから始まった

記念すべき最初のリリースです。
このバージョンで、同期的なデータベース操作の基盤となるクラスとメソッドが導入されました。

Class: DatabaseSyncが登場

  • new DatabaseSync(path[, options]): データベース接続をインスタンス化します。
  • database.close(): 接続を閉じます。
  • database.exec(sql): 結果を返さないSQL文(複数可)を実行します。
  • database.open(): コンストラクタで開かなかった場合に手動で接続を開きます。
  • database.prepare(sql): SQL文をコンパイルし、StatementSyncオブジェクトを返します。

Class: StatementSyncが登場

  • statement.all(): 全ての結果行をオブジェクトの配列として返します。
  • statement.get(): 最初の1行をオブジェクトとして返します。
  • statement.run(): INSERT, UPDATE, DELETEなどを実行し、影響を与えた行数などを返します。
  • statement.setAllowBareNamedParameters(enabled): 名前付きパラメータのプレフィックス(:@など)をJavaScript側で省略可能にするか設定します。
  • statement.setReadBigInts(enabled): INTEGER型をJavaScriptのBigIntとして読み込むか設定します。
  • statement.expandedSQL (プロパティ): 最後にバインドされた値を含むSQL文を取得します。
  • statement.sourceSQL (プロパティ): 元のSQL文を取得します。

v22.12.0 / v23.3.0: Sessionクラスの追加

早くも高度な機能が追加されます。
データベースへの変更を追跡し、その差分(チェンジセット)を生成・適用するSessionクラスが導入されました。
オフラインアプリのデータ同期など、高度なユースケースへの扉が開かれました。

Class: Sessionが登場

  • データベースへの変更を追跡し、差分を生成するためのクラスです。

DatabaseSyncへの追加機能

  • database.createSession([options]): 変更を追跡するための新しいセッションを作成します。
  • database.applyChangeset(changeset[, options]): 他のデータベースで生成されたチェンジセットを適用します。

Sessionクラスのメソッド

  • session.changeset(): 追跡中の変更をバイナリのチェンジセットとして生成します。
  • session.patchset(): チェンジセットよりもコンパクトなパッチセットを生成します。

v22.13.0 / v23.5.0: イテレータと機能拡張

巨大な結果セットを効率的に扱うためのイテレータが導入され、さらにSQLiteの強力なエコシステムを活用し、独自のロジックをSQLに組み込むための機能が追加されました。

StatementSyncへの追加機能 (v22.13.0 / v23.4.0)

  • statement.iterate(): 結果セットを一行ずつ処理できるイテレータを返します。巨大な結果セットを扱う際にメモリを節約できます。

DatabaseSyncへの追加機能 (v22.13.0 / v23.5.0)

  • database.loadExtension(path): SQLite拡張(共有ライブラリ)をロードします。
  • database.enableLoadExtension(allow): 拡張機能のロードを許可/禁止します。
  • database.function(name[, options], function): JavaScript関数をカスタムSQL関数としてデータベースに登録します。

モジュールへの追加 (v22.13.0 / v23.5.0)

  • sqlite.constants: SQLITE_OKなどのSQLite定数を含むオブジェクトが利用可能になりました。

v22.14.0 / v23.7.0: パラメータ型の強化

プリペアドステートメントで扱えるデータ型が拡充され、バイナリデータなどをより効率的に扱えるようになりました。

StatementSyncの改善

  • statement.all(), statement.get(), statement.iterate(), statement.run() の各メソッドで、匿名パラメータとしてDataViewおよび型付き配列オブジェクト(Uint8Arrayなど)がサポートされました。

v22.15.0 / v23.11.0: 利便性とAPIの洗練

ファイルパスの扱いが柔軟になり、データベースやステートメントの状態を取得するAPIが追加されました。

パス引数のサポート拡充 (v22.15.0 / v23.10.0)

  • new DatabaseSync()path引数でBufferURLオブジェクトがサポートされました。

DatabaseSyncへの追加機能 (v22.15.0 / v23.11.0)

  • database.isOpen (プロパティ): データベース接続が開いているかを示すboolean値を取得できます。
  • database[Symbol.dispose](): using[1]宣言によるリソースの自動解放をサポートするメソッドが(実験的に)追加されました。

StatementSyncへの追加機能 (v22.15.0 / v23.11.0)

  • statement.columns(): 結果セットの各列に関する詳細情報(名前、型、由来するテーブルなど)を取得できます。
  • statement.setAllowUnknownNamedParameters(enabled): バインド時にオブジェクトに未知のプロパティが存在した場合にエラーとせず無視するか設定します。

v22.16.0 / v24.0.0: 実用機能の拡充

バックアップや集計関数など、より実践的な機能が大幅に強化されました。

モジュールへの追加 (v22.16.0 / v23.8.0)

  • sqlite.backup(sourceDb, path[, options]): データベースをオンライン(稼働中)のまま別のファイルにバックアップする非同期関数が追加されました。

DatabaseSyncへの追加機能 (v22.16.0 / v24.0.0)

  • new DatabaseSync()timeoutオプションが追加され、データベースロック時の待機時間をミリ秒で指定できるようになりました。
  • database.aggregate(name, options): カスタムの集計関数(SUMAVGのようなもの)をJavaScriptで定義できます。
  • database.location([dbName]) (プロパティ): データベースファイルの場所を取得します。
  • database.isTransaction (プロパティ): 現在トランザクション内であるかを示すboolean値を取得できます。

StatementSyncへの追加機能 (v22.16.0 / v24.0.0)

  • statement.setReturnArrays(enabled): 結果行をオブジェクトではなく配列として返すように設定できます。

v24.2.0: Symbol.disposeの安定化

以前のバージョンで実験的に導入されたSymbol.disposeが正式機能となり、using[2]構文を使った安全で確実なリソース管理が公式にサポートされるようになりました。

DatabaseSyncの改善

  • database[Symbol.dispose]() が実験的な機能ではなくなり、正式にサポートされました。

v22.18.0 / v24.4.0: データベースオプションの追加

new DatabaseSync() コンストラクタで指定できるオプションが増え、より細かいデータベース接続の制御が可能になりました。

DatabaseSyncの改善

  • new DatabaseSync() に、さらに新しいSQLiteデータベースオプションが追加されました。

v24.9.0: SQLTagStoreの劇的な登場

このバージョンでは、開発体験を大きく向上させるSQLTagStoreが導入されました。
タグ付きテンプレートリテラルを使ってSQLを記述することで、プリペアドステートメントのキャッシュとパラメータのバインドを自動的に、かつ安全に行ってくれます。

Class: SQLTagStoreが登場

  • タグ付きテンプレートリテラルで記述されたSQLを効率的に管理・実行するためのクラスです。

DatabaseSyncへの追加機能

  • database.createTagStore([maxSize]): プリペアドステートメントをキャッシュするSQLTagStoreインスタンスを生成します。

SQLTagStoreクラスのメソッド

  • sql.all, sql.get, sql.iterate, sql.run など、StatementSyncのメソッドに対応するテンプレートリテラル関数が提供されます。
  • sql.size(), sql.capacity, sql.reset() など、キャッシュを管理するメソッドも揃っています。
import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync(':memory:');
const sql = db.createTagStore();

db.exec('CREATE TABLE users (id INT, name TEXT)');

// Using the 'run' method to insert data.
// The tagged literal is used to identify the prepared statement.
sql.run`INSERT INTO users VALUES (1, 'Alice')`;
sql.run`INSERT INTO users VALUES (2, 'Bob')`;

// Using the 'get' method to retrieve a single row.
const id = 1;
const user = sql.get`SELECT * FROM users WHERE id = ${id}`;
console.log(user); // { id: 1, name: 'Alice' }

// Using the 'all' method to retrieve all rows.
const allUsers = sql.all`SELECT * FROM users ORDER BY id`;
console.log(allUsers);
// [
//   { id: 1, name: 'Alice' },
//   { id: 2, name: 'Bob' }
// ]

v24.10.0: setAuthorizerの追加

データベース操作に対するきめ細やかなアクセス制御を可能にするオーソライザー機能が追加されました。

DatabaseSyncへの追加機能

  • database.setAuthorizer(callback): SQLコマンド(SQLITE_INSERT, SQLITE_CREATE_TABLEなど)が実行される直前に呼び出されるコールバック関数を設定します。このコールバックの戻り値によって、その操作を許可(SQLITE_OK)、拒否(SQLITE_DENY)、または無視(SQLITE_IGNORE)するかを制御できます。

まとめ

node:sqliteは、わずかな期間で単なる基本的なデータベースドライバから、差分同期、オンラインバックアップ、高度なカスタマイズ、セキュリティ制御、そしてモダンで開発者フレンドリーなAPI(SQLTagStore)を備えた、非常に高機能なモジュールへと進化を遂げました。

この詳細なアップデート履歴を追うことで、Node.jsチームがこのモジュールにどれだけ力を入れているか、そして今後どのような発展を遂げていくのかが垣間見えたのではないでしょうか。

外部ライブラリのインストールやネイティブモジュールのコンパイルに悩まされることなく、Node.jsのコア機能として安定したデータベースアクセスが手に入る時代が到来しました。
ぜひ、あなたの次のプロジェクトでこのパワフルなnode:sqliteを活用してみてください。

クレジット

https://nodejs.org/api/sqlite.md

Node.js is available under the MIT License. Node.js also includes external libraries that are available under a variety of licenses. See LICENSE for the full license text.

脚注
  1. usingはNode.js v24.0.0以降でなければ使用できません https://node.green/#ESNEXT-Stage-3-Explicit-Resource-Management ↩︎

  2. usingはNode.js v24.0.0以降でなければ使用できません https://node.green/#ESNEXT-Stage-3-Explicit-Resource-Management ↩︎

Discussion