aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/bindings/sqlite/sqlite.exports.js
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 23:21:48 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 23:21:48 -0700
commit729d445b6885f69dd2c6355f38707bd42851c791 (patch)
treef87a7c408929ea3f57bbb7ace380cf869da83c0e /src/bun.js/bindings/sqlite/sqlite.exports.js
parent25f820c6bf1d8ec6d444ef579cc036b8c0607b75 (diff)
downloadbun-729d445b6885f69dd2c6355f38707bd42851c791.tar.gz
bun-729d445b6885f69dd2c6355f38707bd42851c791.tar.zst
bun-729d445b6885f69dd2c6355f38707bd42851c791.zip
change the directory structurejarred/rename
Diffstat (limited to 'src/bun.js/bindings/sqlite/sqlite.exports.js')
-rw-r--r--src/bun.js/bindings/sqlite/sqlite.exports.js470
1 files changed, 470 insertions, 0 deletions
diff --git a/src/bun.js/bindings/sqlite/sqlite.exports.js b/src/bun.js/bindings/sqlite/sqlite.exports.js
new file mode 100644
index 000000000..acd28164c
--- /dev/null
+++ b/src/bun.js/bindings/sqlite/sqlite.exports.js
@@ -0,0 +1,470 @@
+var symbolFor = Symbol.for;
+
+const lazy = globalThis[symbolFor("Bun.lazy")];
+if (!lazy || typeof lazy !== "function") {
+ throw new Error(
+ "Something went wrong while loading Bun. Expected 'Bun.lazy' to be defined."
+ );
+}
+
+var defineProperties = Object.defineProperties;
+
+var toStringTag = Symbol.toStringTag;
+var apply = Function.prototype.apply;
+var isArray = Array.isArray;
+var isTypedArray = ArrayBuffer.isView;
+export const constants = {
+ SQLITE_OPEN_READONLY: 0x00000001 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_READWRITE: 0x00000002 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_CREATE: 0x00000004 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_DELETEONCLOSE: 0x00000008 /* VFS only */,
+ SQLITE_OPEN_EXCLUSIVE: 0x00000010 /* VFS only */,
+ SQLITE_OPEN_AUTOPROXY: 0x00000020 /* VFS only */,
+ SQLITE_OPEN_URI: 0x00000040 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_MEMORY: 0x00000080 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_MAIN_DB: 0x00000100 /* VFS only */,
+ SQLITE_OPEN_TEMP_DB: 0x00000200 /* VFS only */,
+ SQLITE_OPEN_TRANSIENT_DB: 0x00000400 /* VFS only */,
+ SQLITE_OPEN_MAIN_JOURNAL: 0x00000800 /* VFS only */,
+ SQLITE_OPEN_TEMP_JOURNAL: 0x00001000 /* VFS only */,
+ SQLITE_OPEN_SUBJOURNAL: 0x00002000 /* VFS only */,
+ SQLITE_OPEN_SUPER_JOURNAL: 0x00004000 /* VFS only */,
+ SQLITE_OPEN_NOMUTEX: 0x00008000 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_FULLMUTEX: 0x00010000 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_SHAREDCACHE: 0x00020000 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_PRIVATECACHE: 0x00040000 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_WAL: 0x00080000 /* VFS only */,
+ SQLITE_OPEN_NOFOLLOW: 0x01000000 /* Ok for sqlite3_open_v2() */,
+ SQLITE_OPEN_EXRESCODE: 0x02000000 /* Extended result codes */,
+ SQLITE_PREPARE_PERSISTENT: 0x01,
+ SQLITE_PREPARE_NORMALIZE: 0x02,
+ SQLITE_PREPARE_NO_VTAB: 0x04,
+};
+
+var SQL;
+var _SQL;
+
+var controllers;
+
+export class Statement {
+ constructor(raw) {
+ this.#raw = raw;
+ this.#columns = undefined;
+
+ switch (raw.paramsCount) {
+ case 0: {
+ this.get = this.#getNoArgs;
+ this.all = this.#allNoArgs;
+ this.values = this.#valuesNoArgs;
+ this.run = this.#runNoArgs;
+ break;
+ }
+ default: {
+ this.get = this.#get;
+ this.all = this.#all;
+ this.values = this.#values;
+ this.run = this.#run;
+ break;
+ }
+ }
+ }
+
+ #raw;
+ #columns;
+
+ get;
+ all;
+ values;
+ run;
+ isFinalized = false;
+
+ toJSON() {
+ return {
+ sql: this.native.toString(),
+ isFinalized: this.isFinalized,
+ paramsCount: this.paramsCount,
+ columnNames: this.columnNames,
+ };
+ }
+
+ get [toStringTag]() {
+ return `"${this.native.toString()}"`;
+ }
+
+ toString() {
+ return this.native.toString();
+ }
+
+ get native() {
+ return this.#raw;
+ }
+
+ #getNoArgs() {
+ return this.#raw.get();
+ }
+
+ #allNoArgs() {
+ return this.#raw.all();
+ }
+
+ #valuesNoArgs() {
+ return this.#raw.values();
+ }
+
+ #runNoArgs() {
+ this.#raw.run();
+ }
+
+ #get(...args) {
+ if (args.length === 0) return this.#getNoArgs();
+ var arg0 = args[0];
+ // ["foo"] => ["foo"]
+ // ("foo") => ["foo"]
+ // (Uint8Array(1024)) => [Uint8Array]
+ // (123) => [123]
+ return !isArray(arg0) &&
+ (!arg0 || typeof arg0 !== "object" || isTypedArray(arg0))
+ ? this.#raw.get(args)
+ : this.#raw.get(...args);
+ }
+
+ #all(...args) {
+ if (args.length === 0) return this.#allNoArgs();
+ var arg0 = args[0];
+ // ["foo"] => ["foo"]
+ // ("foo") => ["foo"]
+ // (Uint8Array(1024)) => [Uint8Array]
+ // (123) => [123]
+ return !isArray(arg0) &&
+ (!arg0 || typeof arg0 !== "object" || isTypedArray(arg0))
+ ? this.#raw.all(args)
+ : this.#raw.all(...args);
+ }
+
+ #values(...args) {
+ if (args.length === 0) return this.#valuesNoArgs();
+ var arg0 = args[0];
+ // ["foo"] => ["foo"]
+ // ("foo") => ["foo"]
+ // (Uint8Array(1024)) => [Uint8Array]
+ // (123) => [123]
+ return !isArray(arg0) &&
+ (!arg0 || typeof arg0 !== "object" || isTypedArray(arg0))
+ ? this.#raw.values(args)
+ : this.#raw.values(...args);
+ }
+
+ #run(...args) {
+ if (args.length === 0) return this.#runNoArgs();
+ var arg0 = args[0];
+
+ !isArray(arg0) && (!arg0 || typeof arg0 !== "object" || isTypedArray(arg0))
+ ? this.#raw.run(args)
+ : this.#raw.run(...args);
+ }
+
+ get columnNames() {
+ return (this.#columns ||= this.#raw.columns);
+ }
+
+ get paramsCount() {
+ return this.#raw.paramsCount;
+ }
+
+ finalize(...args) {
+ this.isFinalized = true;
+ return this.#raw.finalize(...args);
+ }
+}
+
+var cachedCount = symbolFor("Bun.Database.cache.count");
+export class Database {
+ constructor(filenameGiven, options) {
+ if (typeof filenameGiven === "undefined") {
+ } else if (typeof filenameGiven !== "string") {
+ if (isTypedArray(filenameGiven)) {
+ this.#handle = Database.deserialize(
+ filenameGiven,
+ typeof options === "object" && options
+ ? !!options.readonly
+ : ((options | 0) & constants.SQLITE_OPEN_READONLY) != 0
+ );
+ this.filename = ":memory:";
+ return;
+ }
+
+ throw new TypeError(
+ `Expected 'filename' to be a string, got '${typeof filenameGiven}'`
+ );
+ }
+
+ var filename =
+ typeof filenameGiven === "string" ? filenameGiven.trim() : ":memory:";
+ var flags = constants.SQLITE_OPEN_READWRITE | constants.SQLITE_OPEN_CREATE;
+ if (typeof options === "object" && options) {
+ flags = 0;
+
+ if (options.readonly) {
+ flags = constants.SQLITE_OPEN_READONLY;
+ }
+
+ if ("readOnly" in options)
+ throw new TypeError(
+ 'Misspelled option "readOnly" should be "readonly"'
+ );
+
+ if (options.create) {
+ flags = constants.SQLITE_OPEN_READWRITE | constants.SQLITE_OPEN_CREATE;
+ }
+
+ if (options.readwrite) {
+ flags |= constants.SQLITE_OPEN_READWRITE;
+ }
+ } else if (typeof options === "number") {
+ flags = options;
+ }
+
+ const anonymous = filename === "" || filename === ":memory:";
+ if (anonymous && (flags & constants.SQLITE_OPEN_READONLY) !== 0) {
+ throw new Error("Cannot open an anonymous database in read-only mode.");
+ }
+
+ if (!SQL) {
+ _SQL = SQL = lazy("sqlite");
+ }
+
+ this.#handle = SQL.open(anonymous ? ":memory:" : filename, flags);
+ this.filename = filename;
+ }
+
+ #handle;
+ #cachedQueriesKeys = [];
+ #cachedQueriesLengths = [];
+ #cachedQueriesValues = [];
+ filename;
+
+ get handle() {
+ return this.#handle;
+ }
+
+ get inTransaction() {
+ return SQL.isInTransaction(this.#handle);
+ }
+
+ static open(filename, options) {
+ return new Database(filename, options);
+ }
+
+ loadExtension(name, entryPoint) {
+ return SQL.loadExtension(this.#handle, name, entryPoint);
+ }
+
+ serialize(optionalName) {
+ return SQL.serialize(this.#handle, optionalName || "main");
+ }
+
+ static deserialize(serialized, isReadOnly = false) {
+ if (!SQL) {
+ _SQL = SQL = lazy("sqlite");
+ }
+
+ return SQL.deserialize(serialized, isReadOnly);
+ }
+
+ static setCustomSQLite(path) {
+ if (!SQL) {
+ _SQL = SQL = lazy("sqlite");
+ }
+
+ return SQL.setCustomSQLite(path);
+ }
+
+ close() {
+ this.clearQueryCache();
+ return SQL.close(this.#handle);
+ }
+ clearQueryCache() {
+ for (let item of this.#cachedQueriesValues) {
+ item.finalize();
+ }
+ this.#cachedQueriesKeys.length = 0;
+ this.#cachedQueriesValues.length = 0;
+ this.#cachedQueriesLengths.length = 0;
+ }
+
+ run(query, ...params) {
+ if (params.length === 0) {
+ SQL.run(this.#handle, query);
+ return;
+ }
+
+ var arg0 = params[0];
+ return !isArray(arg0) &&
+ (!arg0 || typeof arg0 !== "object" || isTypedArray(arg0))
+ ? SQL.run(this.#handle, query, params)
+ : SQL.run(this.#handle, query, ...params);
+ }
+
+ prepare(query, params, flags) {
+ return new Statement(SQL.prepare(this.#handle, query, params, flags || 0));
+ }
+
+ static MAX_QUERY_CACHE_SIZE = 20;
+
+ get [cachedCount]() {
+ return this.#cachedQueriesKeys.length;
+ }
+
+ query(query) {
+ if (typeof query !== "string") {
+ throw new TypeError(
+ `Expected 'query' to be a string, got '${typeof query}'`
+ );
+ }
+
+ if (query.length === 0) {
+ throw new Error("SQL query cannot be empty.");
+ }
+
+ // this list should be pretty small
+ var index = this.#cachedQueriesLengths.indexOf(query.length);
+ while (index !== -1) {
+ if (this.#cachedQueriesKeys[index] !== query) {
+ index = this.#cachedQueriesLengths.indexOf(query.length, index + 1);
+ continue;
+ }
+
+ var stmt = this.#cachedQueriesValues[index];
+ if (stmt.isFinalized) {
+ return (this.#cachedQueriesValues[index] = this.prepare(
+ query,
+ undefined,
+ willCache ? constants.SQLITE_PREPARE_PERSISTENT : 0
+ ));
+ }
+ return stmt;
+ }
+
+ const willCache =
+ this.#cachedQueriesKeys.length < Database.MAX_QUERY_CACHE_SIZE;
+
+ var stmt = this.prepare(
+ query,
+ undefined,
+ willCache ? constants.SQLITE_PREPARE_PERSISTENT : 0
+ );
+
+ if (willCache) {
+ this.#cachedQueriesKeys.push(query);
+ this.#cachedQueriesLengths.push(query.length);
+ this.#cachedQueriesValues.push(stmt);
+ }
+
+ return stmt;
+ }
+
+ // Code for transactions is largely copied from better-sqlite3
+ // https://github.com/JoshuaWise/better-sqlite3/blob/master/lib/methods/transaction.js
+ // thank you @JoshuaWise!
+ transaction(fn, self) {
+ if (typeof fn !== "function")
+ throw new TypeError("Expected first argument to be a function");
+
+ const db = this;
+ const controller = getController(db, self);
+
+ // Each version of the transaction function has these same properties
+ const properties = {
+ default: { value: wrapTransaction(fn, db, controller.default) },
+ deferred: { value: wrapTransaction(fn, db, controller.deferred) },
+ immediate: {
+ value: wrapTransaction(fn, db, controller.immediate),
+ },
+ exclusive: {
+ value: wrapTransaction(fn, db, controller.exclusive),
+ },
+ database: { value: this, enumerable: true },
+ };
+
+ defineProperties(properties.default.value, properties);
+ defineProperties(properties.deferred.value, properties);
+ defineProperties(properties.immediate.value, properties);
+ defineProperties(properties.exclusive.value, properties);
+
+ // Return the default version of the transaction function
+ return properties.default.value;
+ }
+}
+
+Database.prototype.exec = Database.prototype.run;
+
+// Return the database's cached transaction controller, or create a new one
+const getController = (db, self) => {
+ let controller = (controllers ||= new WeakMap()).get(db);
+ if (!controller) {
+ const shared = {
+ commit: db.prepare("COMMIT", undefined, 0),
+ rollback: db.prepare("ROLLBACK", undefined, 0),
+ savepoint: db.prepare("SAVEPOINT `\t_bs3.\t`", undefined, 0),
+ release: db.prepare("RELEASE `\t_bs3.\t`", undefined, 0),
+ rollbackTo: db.prepare("ROLLBACK TO `\t_bs3.\t`", undefined, 0),
+ };
+
+ controllers.set(
+ db,
+ (controller = {
+ default: Object.assign(
+ { begin: db.prepare("BEGIN", undefined, 0) },
+ shared
+ ),
+ deferred: Object.assign(
+ { begin: db.prepare("BEGIN DEFERRED", undefined, 0) },
+ shared
+ ),
+ immediate: Object.assign(
+ { begin: db.prepare("BEGIN IMMEDIATE", undefined, 0) },
+ shared
+ ),
+ exclusive: Object.assign(
+ { begin: db.prepare("BEGIN EXCLUSIVE", undefined, 0) },
+ shared
+ ),
+ })
+ );
+ }
+ return controller;
+};
+
+// Return a new transaction function by wrapping the given function
+const wrapTransaction = (
+ fn,
+ db,
+ { begin, commit, rollback, savepoint, release, rollbackTo }
+) =>
+ function transaction(...args) {
+ let before, after, undo;
+ if (db.inTransaction) {
+ before = savepoint;
+ after = release;
+ undo = rollbackTo;
+ } else {
+ before = begin;
+ after = commit;
+ undo = rollback;
+ }
+ try {
+ before.run();
+ const result = fn.apply(this, args);
+ after.run();
+ return result;
+ } catch (ex) {
+ if (db.inTransaction) {
+ undo.run();
+ if (undo !== rollback) after.run();
+ }
+ throw ex;
+ }
+ };
+
+export { _SQL as native };
+export { Database as default };