UNPKG

@keyv/sqlite

Version:

SQLite storage adapter for Keyv

198 lines (196 loc) 7.01 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { KeyvSqlite: () => KeyvSqlite, createKeyv: () => createKeyv, default: () => index_default }); module.exports = __toCommonJS(index_exports); var import_node_events = __toESM(require("events"), 1); var import_node_util = require("util"); var import_keyv = __toESM(require("keyv"), 1); var import_sqlite3 = __toESM(require("sqlite3"), 1); var toTableString = (input) => { const sanitized = String(input).replace(/[^a-zA-Z0-9_]/g, ""); if (sanitized.length === 0) { throw new Error("Invalid table name: must contain alphanumeric characters"); } return /^[a-zA-Z]/.test(sanitized) ? sanitized : `_${sanitized}`; }; var KeyvSqlite = class extends import_node_events.default { ttlSupport; opts; namespace; close; query; constructor(keyvOptions) { super(); this.ttlSupport = false; let options = { dialect: "sqlite", uri: "sqlite://:memory:" }; if (typeof keyvOptions === "string") { options.uri = keyvOptions; } else { options = { ...options, ...keyvOptions }; } options.db = options.uri.replace(/^sqlite:\/\//, ""); options.connect = async () => new Promise((resolve, reject) => { const database = new import_sqlite3.default.Database(options.db, (error) => { if (error) { reject(error); } else { if (options.busyTimeout) { database.configure("busyTimeout", options.busyTimeout); } resolve(database); } }); }).then((database) => ({ // @ts-expect-error query: (0, import_node_util.promisify)(database.all).bind(database), // @ts-expect-error close: (0, import_node_util.promisify)(database.close).bind(database) })); this.opts = { table: "keyv", keySize: 255, ...options }; this.opts.table = toTableString(this.opts.table); const keySize = Number(this.opts.keySize); if (!Number.isFinite(keySize) || keySize <= 0 || keySize > 65535) { throw new Error( "Invalid keySize: must be a positive number between 1 and 65535" ); } const createTable = `CREATE TABLE IF NOT EXISTS ${this.opts.table}(key VARCHAR(${keySize}) PRIMARY KEY, value TEXT )`; const connected = this.opts.connect().then( async (database) => database.query(createTable).then(() => database) ).catch((error) => this.emit("error", error)); this.query = async (sqlString, ...parameter) => connected.then( async (database) => database.query(sqlString, ...parameter) ); this.close = async () => connected.then((database) => database.close()); } async get(key) { const select = `SELECT * FROM ${this.opts.table} WHERE key = ?`; const rows = await this.query(select, key); const row = rows[0]; if (row === void 0) { return void 0; } return row.value; } async getMany(keys) { const select = `SELECT * FROM ${this.opts.table} WHERE key IN (SELECT value FROM json_each(?))`; const rows = await this.query(select, JSON.stringify(keys)); return keys.map((key) => { const row = rows.find( (row2) => row2.key === key ); return row ? row.value : void 0; }); } // biome-ignore lint/suspicious/noExplicitAny: type format async set(key, value) { const upsert = `INSERT INTO ${this.opts.table} (key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value;`; return this.query(upsert, key, value); } async delete(key) { const select = `SELECT * FROM ${this.opts.table} WHERE key = ?`; const del = `DELETE FROM ${this.opts.table} WHERE key = ?`; const rows = await this.query(select, key); const row = rows[0]; if (row === void 0) { return false; } await this.query(del, key); return true; } async deleteMany(keys) { const del = `DELETE FROM ${this.opts.table} WHERE key IN (SELECT value FROM json_each(?))`; const results = await this.getMany(keys); if (results.every((x) => x === void 0)) { return false; } await this.query(del, JSON.stringify(keys)); return true; } async clear() { const del = `DELETE FROM ${this.opts.table} WHERE key LIKE ?`; await this.query(del, this.namespace ? `${this.namespace}:%` : "%"); } async *iterator(namespace) { const limit = Number.parseInt(this.opts.iterationLimit, 10) || 10; async function* iterate(offset, options, query) { const select = `SELECT * FROM ${options.table} WHERE key LIKE ? LIMIT ? OFFSET ?`; const iterator = await query(select, [ // biome-ignore lint/style/useTemplate: need to fix `${namespace ? namespace + ":" : ""}%`, limit, offset ]); const entries = [...iterator]; if (entries.length === 0) { return; } for (const entry of entries) { offset += 1; yield [entry.key, entry.value]; } yield* iterate(offset, options, query); } yield* iterate(0, this.opts, this.query); } async has(key) { const exists = `SELECT EXISTS ( SELECT * FROM ${this.opts.table} WHERE key = ? )`; const result = await this.query(exists, key); return Object.values(result[0])[0] === 1; } async disconnect() { await this.close(); } }; var createKeyv = (keyvOptions) => new import_keyv.default({ store: new KeyvSqlite(keyvOptions) }); var index_default = KeyvSqlite; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { KeyvSqlite, createKeyv });