bare-sqlite
Advanced tools
| import DatabaseSync from './lib/database-sync' | ||
| import StatementSync from './lib/statement-sync' | ||
| import TagStore from './lib/tag-store' | ||
| import errors from './lib/errors' | ||
| export { DatabaseSync, StatementSync, TagStore, errors } |
| import StatementSync from './statement-sync' | ||
| import TagStore from './tag-store' | ||
| interface SQLiteDatabaseSync { | ||
| readonly isOpen: boolean | ||
| open(): void | ||
| close(): void | ||
| exec(sql: string): void | ||
| prepare(sql: string): StatementSync | ||
| createTagStore(maxSize?: number): TagStore | ||
| enableLoadExtension(allow: boolean): void | ||
| loadExtension(path: string, entryPoint?: string | null): void | ||
| [Symbol.dispose](): void | ||
| } | ||
| declare class SQLiteDatabaseSync { | ||
| constructor(location: string, opts?: SQLiteDatabaseSync.Options) | ||
| } | ||
| declare namespace SQLiteDatabaseSync { | ||
| export interface Options { | ||
| open?: boolean | ||
| readOnly?: boolean | ||
| enableForeignKeyConstraints?: boolean | ||
| enableDoubleQuotedStringLiterals?: boolean | ||
| allowExtension?: boolean | ||
| timeout?: number | ||
| } | ||
| } | ||
| export = SQLiteDatabaseSync |
| interface SQLiteError extends Error { | ||
| readonly code: string | ||
| } | ||
| declare class SQLiteError {} | ||
| export = SQLiteError |
| import Buffer from 'bare-buffer' | ||
| interface SQLiteStatementSync { | ||
| readonly sourceSQL: string | ||
| readonly expandedSQL: string | null | ||
| all<T extends SQLiteStatementSync.Row = SQLiteStatementSync.Row>( | ||
| ...params: SQLiteStatementSync.Parameters | ||
| ): T[] | ||
| values<T extends SQLiteStatementSync.Value[] = SQLiteStatementSync.Value[]>( | ||
| ...params: SQLiteStatementSync.Parameters | ||
| ): T[] | ||
| get<T extends SQLiteStatementSync.Row = SQLiteStatementSync.Row>( | ||
| ...params: SQLiteStatementSync.Parameters | ||
| ): T | undefined | ||
| run(...params: SQLiteStatementSync.Parameters): SQLiteStatementSync.RunResult | ||
| iterate<T extends SQLiteStatementSync.Row = SQLiteStatementSync.Row>( | ||
| ...params: SQLiteStatementSync.Parameters | ||
| ): IterableIterator<T> | ||
| columns(): SQLiteStatementSync.Column[] | ||
| setAllowBareNamedParameters(allow: boolean): void | ||
| setAllowUnknownNamedParameters(allow: boolean): void | ||
| setReadBigInts(enabled: boolean): void | ||
| [Symbol.dispose](): void | ||
| } | ||
| declare class SQLiteStatementSync {} | ||
| declare namespace SQLiteStatementSync { | ||
| export type Value = null | number | bigint | string | Buffer | ||
| export type BindValue = | ||
| | null | ||
| | undefined | ||
| | number | ||
| | bigint | ||
| | string | ||
| | ArrayBuffer | ||
| | ArrayBufferView | ||
| export type Row = Record<string, Value> | ||
| export type NamedParameters = Record<string, BindValue> | ||
| export type Parameters = [NamedParameters, ...BindValue[]] | BindValue[] | ||
| export interface RunResult { | ||
| changes: number | bigint | ||
| lastInsertRowid: number | bigint | ||
| } | ||
| export interface Column { | ||
| column: string | null | ||
| name: string | null | ||
| database: string | null | ||
| table: string | null | ||
| type: string | null | ||
| } | ||
| } | ||
| export = SQLiteStatementSync |
| import DatabaseSync from './database-sync' | ||
| import StatementSync from './statement-sync' | ||
| interface SQLiteTagStore { | ||
| readonly db: DatabaseSync | ||
| readonly size: number | ||
| readonly capacity: number | ||
| all<T extends StatementSync.Row = StatementSync.Row>( | ||
| strings: readonly string[], | ||
| ...params: StatementSync.BindValue[] | ||
| ): T[] | ||
| values<T extends StatementSync.Value[] = StatementSync.Value[]>( | ||
| strings: readonly string[], | ||
| ...params: StatementSync.BindValue[] | ||
| ): T[] | ||
| get<T extends StatementSync.Row = StatementSync.Row>( | ||
| strings: readonly string[], | ||
| ...params: StatementSync.BindValue[] | ||
| ): T | undefined | ||
| iterate<T extends StatementSync.Row = StatementSync.Row>( | ||
| strings: readonly string[], | ||
| ...params: StatementSync.BindValue[] | ||
| ): IterableIterator<T> | ||
| run(strings: readonly string[], ...params: StatementSync.BindValue[]): StatementSync.RunResult | ||
| clear(): void | ||
| } | ||
| declare class SQLiteTagStore {} | ||
| export = SQLiteTagStore |
| const errors = require('./errors') | ||
| module.exports = class SQLiteTagStore { | ||
| constructor(db, maxSize = 1000) { | ||
| if (typeof maxSize !== 'number' || !Number.isInteger(maxSize) || maxSize <= 0) { | ||
| throw errors.INVALID_ARGUMENT('maxSize must be a positive integer') | ||
| } | ||
| this._db = db | ||
| this._maxSize = maxSize | ||
| this._cache = new Map() | ||
| } | ||
| get db() { | ||
| return this._db | ||
| } | ||
| get size() { | ||
| return this._cache.size | ||
| } | ||
| get capacity() { | ||
| return this._maxSize | ||
| } | ||
| clear() { | ||
| this._cache.clear() | ||
| } | ||
| all(strings, ...params) { | ||
| return this._lookup(strings).all({}, ...params) | ||
| } | ||
| values(strings, ...params) { | ||
| return this._lookup(strings).values({}, ...params) | ||
| } | ||
| get(strings, ...params) { | ||
| return this._lookup(strings).get({}, ...params) | ||
| } | ||
| iterate(strings, ...params) { | ||
| return this._lookup(strings).iterate({}, ...params) | ||
| } | ||
| run(strings, ...params) { | ||
| return this._lookup(strings).run({}, ...params) | ||
| } | ||
| _lookup(strings) { | ||
| const sql = strings.join('?') | ||
| let stmt = this._cache.get(sql) | ||
| if (stmt !== undefined) { | ||
| this._cache.delete(sql) | ||
| this._cache.set(sql, stmt) | ||
| return stmt | ||
| } | ||
| stmt = this._db.prepare(sql) | ||
| this._cache.set(sql, stmt) | ||
| if (this._cache.size > this._maxSize) { | ||
| const oldest = this._cache.keys().next().value | ||
| this._cache.delete(oldest) | ||
| } | ||
| return stmt | ||
| } | ||
| } |
+80
-2
@@ -587,3 +587,5 @@ #include <assert.h> | ||
| if (name == NULL) { | ||
| if (pos_idx >= pos_len) continue; | ||
| if (pos_idx >= pos_len) { | ||
| return js_throw_type_error(env, NULL, "Missing positional parameter"); | ||
| } | ||
@@ -617,3 +619,5 @@ js_value_t *value; | ||
| if (!found) continue; | ||
| if (!found) { | ||
| return js_throw_type_error(env, NULL, "Missing named parameter"); | ||
| } | ||
@@ -628,2 +632,6 @@ js_value_t *value; | ||
| if (pos_idx < pos_len) { | ||
| return js_throw_type_error(env, NULL, "Too many positional parameters"); | ||
| } | ||
| if (has_named && !stmt->allow_unknown_named_parameters) { | ||
@@ -732,2 +740,23 @@ js_value_t *keys; | ||
| static int | ||
| bare_sqlite__build_row_values(js_env_t *env, bare_sqlite_statement_t *stmt, js_value_t **result) { | ||
| int err; | ||
| err = js_create_array(env, result); | ||
| if (err < 0) return err; | ||
| int n = sqlite3_column_count(stmt->handle); | ||
| for (int i = 0; i < n; i++) { | ||
| js_value_t *value; | ||
| err = bare_sqlite__column_value(env, stmt, i, &value); | ||
| if (err < 0) return err; | ||
| err = js_set_element(env, *result, (uint32_t) i, value); | ||
| if (err < 0) return err; | ||
| } | ||
| return 0; | ||
| } | ||
| static js_value_t * | ||
@@ -1161,2 +1190,50 @@ bare_sqlite_bind(js_env_t *env, js_callback_info_t *info) { | ||
| static js_value_t * | ||
| bare_sqlite_values(js_env_t *env, js_callback_info_t *info) { | ||
| int err; | ||
| size_t argc = 3; | ||
| js_value_t *argv[3]; | ||
| err = js_get_callback_info(env, info, &argc, argv, NULL, NULL); | ||
| assert(err == 0); | ||
| assert(argc == 3); | ||
| bare_sqlite_statement_t *stmt; | ||
| err = js_get_value_external(env, argv[0], (void **) &stmt); | ||
| assert(err == 0); | ||
| sqlite3_reset(stmt->handle); | ||
| sqlite3_clear_bindings(stmt->handle); | ||
| err = bare_sqlite__bind_params(env, stmt, argv[1], argv[2]); | ||
| if (err < 0) return NULL; | ||
| js_value_t *rows; | ||
| err = js_create_array(env, &rows); | ||
| assert(err == 0); | ||
| int status; | ||
| uint32_t i = 0; | ||
| while ((status = sqlite3_step(stmt->handle)) == SQLITE_ROW) { | ||
| js_value_t *row; | ||
| err = bare_sqlite__build_row_values(env, stmt, &row); | ||
| if (err < 0) return NULL; | ||
| err = js_set_element(env, rows, i++, row); | ||
| assert(err == 0); | ||
| } | ||
| if (status != SQLITE_DONE) { | ||
| err = bare_sqlite__throw_error(env, status, sqlite3_errmsg(sqlite3_db_handle(stmt->handle))); | ||
| assert(err == 0); | ||
| return NULL; | ||
| } | ||
| return rows; | ||
| } | ||
| static js_value_t * | ||
| bare_sqlite_exports(js_env_t *env, js_value_t *exports) { | ||
@@ -1192,2 +1269,3 @@ int err; | ||
| V("all", bare_sqlite_all) | ||
| V("values", bare_sqlite_values) | ||
| #undef V | ||
@@ -1194,0 +1272,0 @@ |
+2
-0
| const DatabaseSync = require('./lib/database-sync') | ||
| const StatementSync = require('./lib/statement-sync') | ||
| const TagStore = require('./lib/tag-store') | ||
| const errors = require('./lib/errors') | ||
@@ -7,3 +8,4 @@ | ||
| exports.StatementSync = StatementSync | ||
| exports.TagStore = TagStore | ||
| exports.errors = errors |
| const binding = require('../binding') | ||
| const StatementSync = require('./statement-sync') | ||
| const TagStore = require('./tag-store') | ||
| const errors = require('./errors') | ||
@@ -93,2 +94,10 @@ | ||
| createTagStore(maxSize) { | ||
| if (this._handle === null) { | ||
| throw errors.DATABASE_NOT_OPEN('Database is not open') | ||
| } | ||
| return new TagStore(this, maxSize) | ||
| } | ||
| function(name, opts, fn) { | ||
@@ -95,0 +104,0 @@ throw errors.NOT_IMPLEMENTED('function is not implemented') |
+30
-11
@@ -16,9 +16,2 @@ const binding = require('../binding') | ||
| [Symbol.dispose]() { | ||
| if (this._handle === null) return | ||
| binding.finalize(this._handle) | ||
| this._handle = null | ||
| } | ||
| get sourceSQL() { | ||
@@ -37,3 +30,3 @@ return this._sourceSQL | ||
| const rows = binding.all(this._handle, named, positional) | ||
| for (const row of rows) wrapBlobs(row) | ||
| for (const row of rows) wrapBlobRow(row) | ||
| return rows | ||
@@ -45,2 +38,14 @@ } catch (err) { | ||
| values(...params) { | ||
| const [named, positional] = splitParameters(params) | ||
| try { | ||
| const rows = binding.values(this._handle, named, positional) | ||
| for (const row of rows) wrapBlobValues(row) | ||
| return rows | ||
| } catch (err) { | ||
| throw errors.from(err) | ||
| } | ||
| } | ||
| get(...params) { | ||
@@ -51,3 +56,3 @@ const [named, positional] = splitParameters(params) | ||
| const row = binding.get(this._handle, named, positional) | ||
| return row === undefined ? undefined : wrapBlobs(row) | ||
| return row === undefined ? undefined : wrapBlobRow(row) | ||
| } catch (err) { | ||
@@ -76,3 +81,3 @@ throw errors.from(err) | ||
| while ((row = binding.step(this._handle)) !== undefined) { | ||
| yield wrapBlobs(row) | ||
| yield wrapBlobRow(row) | ||
| } | ||
@@ -101,5 +106,12 @@ } catch (err) { | ||
| } | ||
| [Symbol.dispose]() { | ||
| if (this._handle === null) return | ||
| binding.finalize(this._handle) | ||
| this._handle = null | ||
| } | ||
| } | ||
| function wrapBlobs(row) { | ||
| function wrapBlobRow(row) { | ||
| for (const key in row) { | ||
@@ -112,2 +124,9 @@ const value = row[key] | ||
| function wrapBlobValues(row) { | ||
| for (let i = 0; i < row.length; i++) { | ||
| if (row[i] instanceof ArrayBuffer) row[i] = Buffer.from(row[i]) | ||
| } | ||
| return row | ||
| } | ||
| function splitParameters(params) { | ||
@@ -114,0 +133,0 @@ if (params.length === 0) return [null, params] |
+14
-2
| { | ||
| "name": "bare-sqlite", | ||
| "version": "0.1.3", | ||
| "version": "0.1.4", | ||
| "description": "SQLite bindings for Bare", | ||
| "exports": { | ||
| "./package": "./package.json", | ||
| ".": "./index.js" | ||
| ".": { | ||
| "types": "./index.d.ts", | ||
| "default": "./index.js" | ||
| } | ||
| }, | ||
| "files": [ | ||
| "index.js", | ||
| "index.d.ts", | ||
| "binding.c", | ||
@@ -41,3 +45,11 @@ "binding.js", | ||
| "prettier-config-holepunch": "^2.0.0" | ||
| }, | ||
| "peerDependencies": { | ||
| "bare-buffer": "*" | ||
| }, | ||
| "peerDependenciesMeta": { | ||
| "bare-buffer": { | ||
| "optional": true | ||
| } | ||
| } | ||
| } |
+20
-0
@@ -87,2 +87,18 @@ # bare-sqlite | ||
| #### `const sql = db.createTagStore([maxSize])` | ||
| Create an LRU cache of prepared statements keyed on the SQL string produced by a tagged template. `maxSize` defaults to `1000`. The returned store exposes `sql.all`, `sql.get`, `sql.iterate`, and `sql.run` as tag functions; placeholder values are bound positionally. | ||
| ```js | ||
| const sql = db.createTagStore() | ||
| sql.run`INSERT INTO users (name) VALUES (${name})` | ||
| const user = sql.get`SELECT * FROM users WHERE id = ${id}` | ||
| const users = sql.all`SELECT * FROM users` | ||
| for (const row of sql.iterate`SELECT * FROM users`) { ... } | ||
| ``` | ||
| The store also exposes `sql.size`, `sql.capacity`, `sql.db`, and `sql.clear()`. Two call sites that produce the same SQL share a cache entry, since the cache is keyed on the joined string. | ||
| #### `stmt.sourceSQL` | ||
@@ -100,2 +116,6 @@ | ||
| #### `const rows = stmt.values(...params)` | ||
| Execute the statement and return all rows as an array of value tuples, one per row, in the order given by `stmt.columns()`. Cheaper than `stmt.all()` when column names aren't needed. | ||
| #### `const row = stmt.get(...params)` | ||
@@ -102,0 +122,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
17387963
0.1%37
19.35%449
75.39%180
12.5%1
Infinity%