database.createModule(name, options)
name<string> 虚拟表模块的名称。这个名称用于CREATE VIRTUAL TABLE ... USING name语句中,并且用作同名表的名称。options<Object> 模块配置设置。columns<Array> 一组列定义数组。每个元素都是一个对象,具有以下属性:rows<Function> 当虚拟表被查询时,会调用一个函数来生成行。该函数会接收隐藏列(参数)的值作为参数,顺序按照它们被定义的顺序。必须返回一个可迭代对象(比如数组或生成器),其中每个元素都是一组列值数组。directOnly<boolean> 如果true,虚拟表只能在顶层 SQL 语句中使用,不能在触发器或视图中使用。 默认值:false。useBigIntArguments<boolean> 如果true,传递给rows的整数参数会被转换为BigInt。默认值:false。
在数据库中注册一个虚拟表模块。这个方法是 sqlite3_create_module_v2() 的一个封装。虚拟表允许 JavaScript 代码为 SQL 表提供后台数据。注册的模块可以有两种使用方式:
🌐 Registers a virtual table module with the database. This method is a wrapper
around sqlite3_create_module_v2(). Virtual tables allow JavaScript code
to provide the backing data for SQL tables. The registered module can be used
in two ways:
- 同名表:直接查询模块名称而不创建表(例如,
SELECT * FROM module_name)。 - 命名虚拟表:使用
CREATE VIRTUAL TABLE t USING module_name来创建一个持久的虚拟表。
隐藏列可以用来通过表值函数语法(例如 SELECT * FROM module_name(param1, param2))向 rows 函数传递参数。
🌐 Hidden columns can be used to pass parameters to the rows function using
table-valued function syntax (e.g., SELECT * FROM module_name(param1, param2)).
rows 产生的值遵循 JavaScript 和 SQLite 之间的类型转换 中的转换规则:一个 <number> 被存储为 REAL,一个 <bigint> 被存储为 INTEGER,不管列声明的 type 是什么。和普通表不一样,虚拟表不会对返回的值应用列类型偏好,所以在某列需要 INTEGER 存储时,返回一个 <bigint>:
🌐 Values yielded by rows follow the conversion rules in Type conversion between
JavaScript and SQLite: a <number> is stored as REAL and a <bigint> is
stored as INTEGER, regardless of the column's declared type. Unlike an
ordinary table, a virtual table does not apply column affinity to the values it
returns, so yield a <bigint> when a column needs INTEGER storage:
db.createModule('counter', {
columns: [{ name: 'value', type: 'INTEGER' }],
*rows() {
yield [1]; // typeof(value) is 'real'
yield [2n]; // typeof(value) is 'integer'
},
}); const { Database } = require('node:sqlite');
const db = new Database(':memory:');
db.createModule('generate_series', {
columns: [
{ name: 'value', type: 'INTEGER' },
{ name: 'start', type: 'INTEGER', hidden: true },
{ name: 'stop', type: 'INTEGER', hidden: true },
{ name: 'step', type: 'INTEGER', hidden: true },
],
*rows(start, stop, step) {
start ??= 0;
stop ??= 10;
step ??= 1;
for (let i = start; i <= stop; i += step) {
yield [i];
}
},
});
console.log(db.prepare('SELECT * FROM generate_series(1, 5, 1)').all());
// Prints: [ { value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }, { value: 5 } ]import { Database } from 'node:sqlite';
const db = new Database(':memory:');
db.createModule('generate_series', {
columns: [
{ name: 'value', type: 'INTEGER' },
{ name: 'start', type: 'INTEGER', hidden: true },
{ name: 'stop', type: 'INTEGER', hidden: true },
{ name: 'step', type: 'INTEGER', hidden: true },
],
*rows(start, stop, step) {
start ??= 0;
stop ??= 10;
step ??= 1;
for (let i = start; i <= stop; i += step) {
yield [i];
}
},
});
console.log(db.prepare('SELECT * FROM generate_series(1, 5, 1)').all());
// Prints: [ { value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }, { value: 5 } ]