@gjsify/sqlite 0.64.12-next.280 → 0.64.12-next.281
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/database-sync.js +1 -1
- package/lib/esm/errors.js +1 -1
- package/lib/esm/native.js +1 -0
- package/lib/esm/statement-sync.js +1 -1
- package/lib/types/database-sync.d.ts +8 -0
- package/lib/types/errors.d.ts +20 -4
- package/lib/types/iterate.spec.d.ts +2 -0
- package/lib/types/native.d.ts +11 -0
- package/lib/types/statement-sync.d.ts +16 -7
- package/lib/types/types.d.ts +13 -0
- package/package.json +8 -11
- package/lib/esm/connection-pool.js +0 -2
- package/lib/esm/data-model-reader.js +0 -1
- package/lib/esm/execution.js +0 -1
- package/lib/esm/exists-subquery.js +0 -1
- package/lib/esm/param-binding.js +0 -1
- package/lib/esm/parameter-syntax.js +0 -1
- package/lib/esm/parse-sql.js +0 -1
- package/lib/esm/sql-regions.js +0 -2
- package/lib/esm/statement-kind.js +0 -1
- package/lib/types/connection-pool.d.ts +0 -24
- package/lib/types/data-model-reader.d.ts +0 -10
- package/lib/types/execution.d.ts +0 -99
- package/lib/types/exists-subquery.d.ts +0 -36
- package/lib/types/param-binding.d.ts +0 -46
- package/lib/types/parameter-syntax.d.ts +0 -23
- package/lib/types/parse-sql.d.ts +0 -26
- package/lib/types/sql-regions.d.ts +0 -25
- package/lib/types/statement-kind.d.ts +0 -39
package/lib/esm/database-sync.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{ConstructCallRequiredError as e,InvalidArgTypeError as t,InvalidStateError as n,InvalidUrlSchemeError as r,
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{ConstructCallRequiredError as e,InvalidArgTypeError as t,InvalidStateError as n,InvalidUrlSchemeError as r,toSqliteError as i}from"./errors.js";import{nativeSqlite as a}from"./native.js";import{StatementSync as o}from"./statement-sync.js";const s=Symbol.for(`sqlite-type`);function parsePath(e){if(typeof e==`string`){if(e.includes(`\0`))throw new t(`The "path" argument must be a string, Uint8Array, or URL without null bytes.`);return e}if(e instanceof URL){if(e.protocol!==`file:`)throw new r;let n=e.pathname;if(n.includes(`\0`))throw new t(`The "path" argument must be a string, Uint8Array, or URL without null bytes.`);return n}if(e instanceof Uint8Array){for(let n=0;n<e.length;n++)if(e[n]===0)throw new t(`The "path" argument must be a string, Uint8Array, or URL without null bytes.`);return new TextDecoder().decode(e)}throw new t(`The "path" argument must be a string, Uint8Array, or URL without null bytes.`)}function validateOptions(e){if(e===void 0)return{};if(typeof e!=`object`||!e)throw new t(`The "options" argument must be an object.`);let n=e,r={};if(n.open!==void 0){if(typeof n.open!=`boolean`)throw new t(`The "options.open" argument must be a boolean.`);r.open=n.open}if(n.readOnly!==void 0){if(typeof n.readOnly!=`boolean`)throw new t(`The "options.readOnly" argument must be a boolean.`);r.readOnly=n.readOnly}if(n.timeout!==void 0){if(typeof n.timeout!=`number`||!Number.isInteger(n.timeout))throw new t(`The "options.timeout" argument must be an integer.`);r.timeout=n.timeout}if(n.enableForeignKeyConstraints!==void 0){if(typeof n.enableForeignKeyConstraints!=`boolean`)throw new t(`The "options.enableForeignKeyConstraints" argument must be a boolean.`);r.enableForeignKeyConstraints=n.enableForeignKeyConstraints}if(n.enableDoubleQuotedStringLiterals!==void 0){if(typeof n.enableDoubleQuotedStringLiterals!=`boolean`)throw new t(`The "options.enableDoubleQuotedStringLiterals" argument must be a boolean.`);r.enableDoubleQuotedStringLiterals=n.enableDoubleQuotedStringLiterals}if(n.readBigInts!==void 0){if(typeof n.readBigInts!=`boolean`)throw new t(`The "options.readBigInts" argument must be a boolean.`);r.readBigInts=n.readBigInts}if(n.returnArrays!==void 0){if(typeof n.returnArrays!=`boolean`)throw new t(`The "options.returnArrays" argument must be a boolean.`);r.returnArrays=n.returnArrays}if(n.allowBareNamedParameters!==void 0){if(typeof n.allowBareNamedParameters!=`boolean`)throw new t(`The "options.allowBareNamedParameters" argument must be a boolean.`);r.allowBareNamedParameters=n.allowBareNamedParameters}if(n.allowUnknownNamedParameters!==void 0){if(typeof n.allowUnknownNamedParameters!=`boolean`)throw new t(`The "options.allowUnknownNamedParameters" argument must be a boolean.`);r.allowUnknownNamedParameters=n.allowUnknownNamedParameters}if(n.defensive!==void 0){if(typeof n.defensive!=`boolean`)throw new t(`The "options.defensive" argument must be a boolean.`);r.defensive=n.defensive}if(n.allowExtension!==void 0){if(typeof n.allowExtension!=`boolean`)throw new t(`The "options.allowExtension" argument must be a boolean.`);r.allowExtension=n.allowExtension}return r}var DatabaseSync=class{#e=null;#t;#n;#r;constructor(t,n){if(!new.target)throw new e(`DatabaseSync`);this.#t=parsePath(t),this.#n=validateOptions(n),this.#r=this.#t===`:memory:`,this.#n.open!==!1&&this.open()}get[s](){return`node:sqlite`}get isOpen(){return this.#e!==null&&this.#e.is_open}get isTransaction(){return this.#i(),this.#e.in_transaction}open(){if(this.isOpen)throw new n(`database is already open`);let{Database:e,OpenMode:t}=a(),r=this.#n.readOnly?t.READONLY:t.READWRITE_CREATE;try{this.#e=e.open(this.#t,r,!1)}catch(e){throw this.#e=null,i(e)}this.#a()}close(){if(!this.isOpen)throw new n(`database is not open`);this.#e.close(),this.#e=null}sqlExec(e){if(this.#i(),typeof e!=`string`)throw new t(`The "sql" argument must be a string.`);try{this.#e.exec(e)}catch(e){throw i(e)}}prepare(e,n){if(this.#i(),typeof e!=`string`)throw new t(`The "sql" argument must be a string.`);let r={readBigInts:this.#n.readBigInts??!1,returnArrays:this.#n.returnArrays??!1,allowBareNamedParameters:this.#n.allowBareNamedParameters??!0,allowUnknownNamedParameters:this.#n.allowUnknownNamedParameters??!1};try{return o._create(this.#e,this.#e.prepare(e),e,r)}catch(e){throw i(e)}}location(e){if(this.#i(),e!==void 0&&typeof e!=`string`)throw new t(`The "dbName" argument must be a string.`);return this.#r?null:this.#t}[Symbol.dispose](){this.isOpen&&this.close()}#i(){if(!this.isOpen)throw new n(`database is not open`)}#a(){let e=this.#e;this.#n.enableForeignKeyConstraints===!1?e.exec(`PRAGMA foreign_keys = OFF`):e.exec(`PRAGMA foreign_keys = ON`),this.#n.timeout!==void 0&&this.#n.timeout>0&&e.exec(`PRAGMA busy_timeout = ${this.#n.timeout}`)}};DatabaseSync.prototype.exec=DatabaseSync.prototype.sqlExec;export{DatabaseSync};
|
package/lib/esm/errors.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";var SqliteError=class extends Error{code=`ERR_SQLITE_ERROR`;errcode;errstr;constructor(e,t=0,n=``){super(e),this.name=`SqliteError`,this.errcode=t,this.errstr=n||e}},InvalidStateError=class extends Error{code=`ERR_INVALID_STATE`;constructor(e){super(e),this.name=`InvalidStateError`}},InvalidArgTypeError=class extends TypeError{code=`ERR_INVALID_ARG_TYPE`;constructor(e){super(e),this.name=`InvalidArgTypeError`}},InvalidArgValueError=class extends Error{code=`ERR_INVALID_ARG_VALUE`;constructor(e){super(e),this.name=`InvalidArgValueError`}},OutOfRangeError=class extends RangeError{code=`ERR_OUT_OF_RANGE`;constructor(e){super(e),this.name=`OutOfRangeError`}},ConstructCallRequiredError=class extends TypeError{code=`ERR_CONSTRUCT_CALL_REQUIRED`;constructor(e){super(`Cannot call constructor without \`new\`: ${e}`),this.name=`ConstructCallRequiredError`}},InvalidUrlSchemeError=class extends TypeError{code=`ERR_INVALID_URL_SCHEME`;constructor(e=`The URL must be of scheme file:`){super(e),this.name=`InvalidUrlSchemeError`}},IllegalConstructorError=class extends TypeError{code=`ERR_ILLEGAL_CONSTRUCTOR`;constructor(){super(`Illegal constructor`),this.name=`IllegalConstructorError`}};function isNodeSqliteError(e){return e instanceof SqliteError||e instanceof InvalidStateError||e instanceof InvalidArgTypeError||e instanceof InvalidArgValueError||e instanceof OutOfRangeError||e instanceof ConstructCallRequiredError||e instanceof InvalidUrlSchemeError||e instanceof IllegalConstructorError}function sqliteErrorMessage(e){let t=e?.message;return typeof t==`string`?t:String(e)}export{ConstructCallRequiredError,IllegalConstructorError,InvalidArgTypeError,InvalidArgValueError,InvalidStateError,InvalidUrlSchemeError,OutOfRangeError,SqliteError,isNodeSqliteError,sqliteErrorMessage};
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";var SqliteError=class extends Error{code=`ERR_SQLITE_ERROR`;errcode;errstr;constructor(e,t=0,n=``){super(e),this.name=`SqliteError`,this.errcode=t,this.errstr=n||e}},InvalidStateError=class extends Error{code=`ERR_INVALID_STATE`;constructor(e){super(e),this.name=`InvalidStateError`}},InvalidArgTypeError=class extends TypeError{code=`ERR_INVALID_ARG_TYPE`;constructor(e){super(e),this.name=`InvalidArgTypeError`}},InvalidArgValueError=class extends Error{code=`ERR_INVALID_ARG_VALUE`;constructor(e){super(e),this.name=`InvalidArgValueError`}},OutOfRangeError=class extends RangeError{code=`ERR_OUT_OF_RANGE`;constructor(e){super(e),this.name=`OutOfRangeError`}},ConstructCallRequiredError=class extends TypeError{code=`ERR_CONSTRUCT_CALL_REQUIRED`;constructor(e){super(`Cannot call constructor without \`new\`: ${e}`),this.name=`ConstructCallRequiredError`}},InvalidUrlSchemeError=class extends TypeError{code=`ERR_INVALID_URL_SCHEME`;constructor(e=`The URL must be of scheme file:`){super(e),this.name=`InvalidUrlSchemeError`}},IllegalConstructorError=class extends TypeError{code=`ERR_ILLEGAL_CONSTRUCTOR`;constructor(){super(`Illegal constructor`),this.name=`IllegalConstructorError`}};function isNodeSqliteError(e){return e instanceof SqliteError||e instanceof InvalidStateError||e instanceof InvalidArgTypeError||e instanceof InvalidArgValueError||e instanceof OutOfRangeError||e instanceof ConstructCallRequiredError||e instanceof InvalidUrlSchemeError||e instanceof IllegalConstructorError}function sqliteErrorMessage(e){let t=e?.message;return typeof t==`string`?t:String(e)}function sqliteErrorCode(e){let t=e?.code;return typeof t==`number`?t:0}function toSqliteError(e){return isNodeSqliteError(e)?e:new SqliteError(sqliteErrorMessage(e),sqliteErrorCode(e))}export{ConstructCallRequiredError,IllegalConstructorError,InvalidArgTypeError,InvalidArgValueError,InvalidStateError,InvalidUrlSchemeError,OutOfRangeError,SqliteError,isNodeSqliteError,sqliteErrorCode,sqliteErrorMessage,toSqliteError};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{InvalidStateError as e}from"./errors.js";import{getLoadError as t,loadNativeSqlite as n}from"@gjsify/sqlite-native";function nativeSqlite(){let r=n();if(!r){let n=t()?.message;throw new e(`@gjsify/sqlite requires the @gjsify/sqlite-native prebuild for this platform${n?`: ${n}`:``}`)}return r}export{nativeSqlite};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{IllegalConstructorError as e,InvalidArgTypeError as t,InvalidArgValueError as n,
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{IllegalConstructorError as e,InvalidArgTypeError as t,InvalidArgValueError as n,InvalidStateError as r,OutOfRangeError as i,SqliteError as a,toSqliteError as o}from"./errors.js";import{nativeSqlite as s}from"./native.js";const c=Symbol(`StatementSync.internal`),l=`SELECT last_insert_rowid()`,u=new WeakMap;function rowidStatement(e){let t=u.get(e);return t||(t=e.prepare(l),u.set(e,t)),t}function isNamedArgObject(e){return typeof e==`object`&&!!e&&!ArrayBuffer.isView(e)}function viewBytes(e){return e instanceof Uint8Array?e:new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}function iteratorPrototype(){let e=globalThis.Iterator;return e?e.prototype:null}var d=class StatementSync{#e;#t;#n;#r;#i;#a;#o;#s=null;#c=0;constructor(t,n,r,i,a){if(t!==c)throw new e;this.#e=n,this.#t=r,this.#n=i,this.#r=a.readBigInts??!1,this.#i=a.returnArrays??!1,this.#a=a.allowBareNamedParameters??!0,this.#o=a.allowUnknownNamedParameters??!1}static _create(e,t,n,r){return new StatementSync(c,e,t,n,r)}get sourceSQL(){return this.#n}get expandedSQL(){return this.#t.expanded_sql??this.#n}run(...e){this.#l();try{this.#u(),this.#d(e),this.#t.step()}catch(e){throw this.#u(),o(e)}this.#u();let t=this.#e.changes;return this.#r?{changes:BigInt(t),lastInsertRowid:this.#v()}:{changes:t,lastInsertRowid:this.#e.last_insert_rowid}}get(...e){let{StepResult:t}=s();this.#l();try{return this.#u(),this.#d(e),this.#t.step()!==t.ROW||this.#t.column_count===0?void 0:this.#h(this.#i?null:this.#m())}catch(e){throw o(e)}finally{this.#u()}}all(...e){let{StepResult:t}=s();this.#l();let n=[];try{this.#u(),this.#d(e);let r=this.#i?null:this.#m();for(;this.#t.step()===t.ROW;)n.push(this.#h(r))}catch(e){throw o(e)}finally{this.#u()}return n}iterate(...e){let{StepResult:t}=s();this.#l();try{this.#u(),this.#d(e)}catch(e){throw this.#u(),o(e)}let n=this.#m(),i=this.#c,a=!1,stop=()=>(a||(a=!0,this.#c===i&&this.#u()),{done:!0,value:null}),c={next:()=>{if(a)return{done:!0,value:null};if(this.#c!==i)throw new r(`iterator was invalidated`);this.#l();let e;try{e=this.#t.step()}catch(e){throw a=!0,this.#u(),o(e)}return e===t.ROW?{done:!1,value:this.#h(this.#i?null:n)}:stop()},return:stop,[Symbol.iterator]:()=>c},l=iteratorPrototype();return l&&Object.setPrototypeOf(c,l),c}setReadBigInts(e){if(typeof e!=`boolean`)throw new t(`The "readBigInts" argument must be a boolean.`);this.#r=e}setReturnArrays(e){if(typeof e!=`boolean`)throw new t(`The "returnArrays" argument must be a boolean.`);this.#i=e}setAllowBareNamedParameters(e){if(typeof e!=`boolean`)throw new t(`The "allowBareNamedParameters" argument must be a boolean.`);this.#a=e}setAllowUnknownNamedParameters(e){if(typeof e!=`boolean`)throw new t(`The "allowUnknownNamedParameters" argument must be a boolean.`);this.#o=e}#l(){if(!this.#t.is_valid)throw new r(`statement has been finalized`)}#u(){this.#c++,this.#t.reset()}#d(e){let t=this.#t;t.clear_bindings();let n=1,i=0;if(e.length>0&&isNamedArgObject(e[0])){let n=e[0];for(let e of Object.keys(n)){let i=t.bind_parameter_index(e);if(i===0&&this.#a&&(i=this.#f(e)),i===0){if(this.#o)continue;throw new r(`Unknown named parameter '${e}'`)}this.#p(n[e],i)}i++}for(let r=i;r<e.length;r++){for(;;){let e=t.bind_parameter_name(n);if(e===null||e[0]===`?`)break;n++}this.#p(e[r],n),n++}}#f(e){let t=this.#s;if(!t){t=new Map;let e=this.#t,n=e.bind_parameter_count;for(let i=1;i<=n;i++){let n=e.bind_parameter_name(i);if(n===null)continue;let a=n.slice(1),o=t.get(a);if(o!==void 0){if(o===n)continue;throw new r(`Cannot create bare named parameter '${a}' because of conflicting names '${o}' and '${n}'.`)}t.set(a,n)}this.#s=t}let n=t.get(e);return n===void 0?0:this.#t.bind_parameter_index(n)}#p(e,r){let i=this.#t;if(typeof e==`number`)i.bind_double(r,e);else if(typeof e==`string`)i.bind_text(r,e);else if(e==null)i.bind_null(r);else if(ArrayBuffer.isView(e))i.bind_blob(r,viewBytes(e));else if(typeof e==`bigint`){if(e>9223372036854775807n||e<-9223372036854775808n)throw new n(`BigInt value is too large to bind.`);i.bind_int64(r,e)}else if(typeof e==`boolean`)i.bind_int64(r,e?1n:0n);else throw new t(`Provided value cannot be bound to SQLite parameter ${r}.`)}#m(){let e=this.#t,t=e.column_count;return Array.from({length:t},(t,n)=>e.column_name(n)??``)}#h(e){let{ColumnType:t}=s();if(e===null){let e=this.#t.column_count;return Array.from({length:e},(e,n)=>this.#g(t,n))}let n=Object.create(null);for(let r=0;r<e.length;r++)n[e[r]]=this.#g(t,r);return n}#g(e,t){let n=this.#t;switch(n.column_type(t)){case e.NULL:return null;case e.FLOAT:return n.column_double(t);case e.TEXT:return n.column_text(t)??``;case e.BLOB:return new Uint8Array(n.column_blob(t).get_data()??[]);default:return this.#_(t)}}#_(e){let t=this.#t.column_double(e);if(Number.isSafeInteger(t))return this.#r?BigInt(t):t;let n=this.#t.column_text(e)??`0`;if(this.#r)return BigInt(n);throw new i(`Value is too large to be represented as a JavaScript number: ${n}`)}#v(){let{StepResult:e}=s(),t=rowidStatement(this.#e);try{if(t.step()!==e.ROW)throw new a(`${l} returned no row`);return BigInt(t.column_text(0)??`0`)}finally{t.reset()}}};export{d as StatementSync};
|
|
@@ -5,6 +5,14 @@ export declare class DatabaseSync {
|
|
|
5
5
|
constructor(path: unknown, options?: unknown);
|
|
6
6
|
get [sqliteTypeSymbol](): string;
|
|
7
7
|
get isOpen(): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Whether a transaction is open — asked of SQLite, never read off the SQL.
|
|
10
|
+
*
|
|
11
|
+
* The text cannot answer it: `CREATE TRIGGER … BEGIN … END` carries the word BEGIN
|
|
12
|
+
* and opens no transaction, while `SAVEPOINT`/`RELEASE` open and close one and carry
|
|
13
|
+
* neither word. The native property is `sqlite3_get_autocommit()`, which is what
|
|
14
|
+
* node:sqlite reads too — so both cases now agree with it.
|
|
15
|
+
*/
|
|
8
16
|
get isTransaction(): boolean;
|
|
9
17
|
open(): undefined;
|
|
10
18
|
close(): undefined;
|
package/lib/types/errors.d.ts
CHANGED
|
@@ -34,9 +34,9 @@ export declare class IllegalConstructorError extends TypeError {
|
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* Whether `cause` is one of the errors above — already Node-shaped, so a catch that
|
|
37
|
-
* translates
|
|
37
|
+
* translates the native module's must let it through untouched.
|
|
38
38
|
*
|
|
39
|
-
* **The discriminator cannot be `instanceof Error`.**
|
|
39
|
+
* **The discriminator cannot be `instanceof Error`.** The native module reports through
|
|
40
40
|
* `GLib.Error`, which is a boxed GObject value whose prototype chain does NOT reach
|
|
41
41
|
* `Error.prototype` — on GJS and, since the GError identity fix, on `@gjsify/node-gi`
|
|
42
42
|
* too. It used to be a real `Error` subclass there, so an `instanceof Error` test
|
|
@@ -45,13 +45,29 @@ export declare class IllegalConstructorError extends TypeError {
|
|
|
45
45
|
*/
|
|
46
46
|
export declare function isNodeSqliteError(cause: unknown): boolean;
|
|
47
47
|
/**
|
|
48
|
-
* The message
|
|
48
|
+
* The message SQLite actually reported.
|
|
49
49
|
*
|
|
50
50
|
* An `e instanceof Error ? e.message : String(e)` extraction takes the `String(e)`
|
|
51
51
|
* branch for a GJS `GLib.Error` and yields
|
|
52
|
-
* `"GLib.Error
|
|
52
|
+
* `"GLib.Error gjsify-sqlite-error: no such table: t"`; under node-gi the same
|
|
53
53
|
* expression takes the OTHER branch and yields the bare message. The `message`
|
|
54
54
|
* property alone is SQLite's own text on both — byte-for-byte what node:sqlite
|
|
55
55
|
* reports for the same statement — so read the property instead of stringifying.
|
|
56
56
|
*/
|
|
57
57
|
export declare function sqliteErrorMessage(cause: unknown): string;
|
|
58
|
+
/**
|
|
59
|
+
* SQLite's result code for a failure the native module raised.
|
|
60
|
+
*
|
|
61
|
+
* `GjsifySqlite.SqliteError` is a GError domain whose `code` IS the extended result
|
|
62
|
+
* code, which is exactly what node:sqlite exposes as `err.errcode`. Anything else
|
|
63
|
+
* reports 0 rather than a number from an unrelated domain.
|
|
64
|
+
*/
|
|
65
|
+
export declare function sqliteErrorCode(cause: unknown): number;
|
|
66
|
+
/**
|
|
67
|
+
* A native failure in the shape a consumer written against node:sqlite branches on.
|
|
68
|
+
*
|
|
69
|
+
* Returned rather than thrown, so every call site reads `throw toSqliteError(e)` and
|
|
70
|
+
* stays an exit the type checker can see. One of our own errors passes through: it is
|
|
71
|
+
* already the shape, and re-wrapping would lose its `code`.
|
|
72
|
+
*/
|
|
73
|
+
export declare function toSqliteError(cause: unknown): Error;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type NativeSqliteModule } from '@gjsify/sqlite-native';
|
|
2
|
+
/**
|
|
3
|
+
* The loaded native module, or a thrown explanation of why there is none.
|
|
4
|
+
*
|
|
5
|
+
* Unlike `@gjsify/tty`, which degrades to an env/GLib reading of the terminal when
|
|
6
|
+
* `@gjsify/terminal-native` is absent, there is no second engine to fall back to: the
|
|
7
|
+
* prebuild IS SQLite here. So the failure is raised at the first call that needs it —
|
|
8
|
+
* carrying the loader's own message, which names the missing library rather than only
|
|
9
|
+
* the namespace.
|
|
10
|
+
*/
|
|
11
|
+
export declare function nativeSqlite(): NativeSqliteModule;
|
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
3
|
-
import type { RunResult, StatementSyncOptions } from './types.ts';
|
|
1
|
+
import type { Database as NativeDatabase, Statement as NativeStatement } from '@gjsify/sqlite-native';
|
|
2
|
+
import type { RunResult, StatementIterator, StatementRow, StatementSyncOptions } from './types.ts';
|
|
4
3
|
export declare class StatementSync {
|
|
5
4
|
#private;
|
|
6
|
-
constructor(sentinel: symbol,
|
|
5
|
+
constructor(sentinel: symbol, database: NativeDatabase, statement: NativeStatement, sql: string, options: StatementSyncOptions);
|
|
7
6
|
/** @internal */
|
|
8
|
-
static _create(
|
|
7
|
+
static _create(database: NativeDatabase, statement: NativeStatement, sql: string, options: StatementSyncOptions): StatementSync;
|
|
9
8
|
get sourceSQL(): string;
|
|
10
9
|
get expandedSQL(): string;
|
|
11
10
|
run(...args: unknown[]): RunResult;
|
|
12
|
-
get(...args: unknown[]):
|
|
13
|
-
all(...args: unknown[]):
|
|
11
|
+
get(...args: unknown[]): StatementRow | undefined;
|
|
12
|
+
all(...args: unknown[]): StatementRow[];
|
|
13
|
+
/**
|
|
14
|
+
* Step the statement one row at a time.
|
|
15
|
+
*
|
|
16
|
+
* Nothing is read until `next()` asks, which is the whole point: `all()` materialises
|
|
17
|
+
* every row before the caller sees the first one, and a table of BLOBs does not fit
|
|
18
|
+
* twice. The statement is reset when the rows run out and when a loop is left early
|
|
19
|
+
* (`break`, `return`, a throw) — the latter through the iterator protocol's own
|
|
20
|
+
* `return()`, which `for…of` calls for exactly this.
|
|
21
|
+
*/
|
|
22
|
+
iterate(...args: unknown[]): StatementIterator;
|
|
14
23
|
setReadBigInts(enabled: unknown): undefined;
|
|
15
24
|
setReturnArrays(enabled: unknown): undefined;
|
|
16
25
|
setAllowBareNamedParameters(enabled: unknown): undefined;
|
package/lib/types/types.d.ts
CHANGED
|
@@ -29,3 +29,16 @@ export interface ColumnInfo {
|
|
|
29
29
|
type: string | null;
|
|
30
30
|
}
|
|
31
31
|
export type SQLiteValue = null | number | bigint | string | Uint8Array;
|
|
32
|
+
/** One result row, an object by default and an array under `returnArrays`. */
|
|
33
|
+
export type StatementRow = Record<string, unknown> | unknown[];
|
|
34
|
+
/**
|
|
35
|
+
* What `StatementSync.iterate()` hands back.
|
|
36
|
+
*
|
|
37
|
+
* An iterator AND an iterable — `for…of` needs the second — whose `return()` is
|
|
38
|
+
* declared because the contract includes resetting the statement when a loop is left
|
|
39
|
+
* early, not only when it runs out.
|
|
40
|
+
*/
|
|
41
|
+
export interface StatementIterator extends Iterator<StatementRow, null> {
|
|
42
|
+
[Symbol.iterator](): StatementIterator;
|
|
43
|
+
return(): IteratorResult<StatementRow, null>;
|
|
44
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/sqlite",
|
|
3
|
-
"version": "0.64.12-next.
|
|
4
|
-
"description": "Node.js sqlite module for Gjs
|
|
3
|
+
"version": "0.64.12-next.281",
|
|
4
|
+
"description": "Node.js sqlite module for Gjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -31,27 +31,24 @@
|
|
|
31
31
|
"test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:node && gjsify run test:gjs",
|
|
32
32
|
"test:gjs": "gjsify run test.gjs.mjs",
|
|
33
33
|
"test:node": "node test.node.mjs",
|
|
34
|
-
"test:gjs-on-node": "gjsify build src/test.node-gi.mts --app node --alias node:sqlite=@gjsify/sqlite --outfile dist/test.node-gi.mjs && node dist/test.node-gi.mjs"
|
|
34
|
+
"test:gjs-on-node": "gjsify build src/test.node-gi.mts --app node --alias node:sqlite=@gjsify/sqlite --outfile dist/test.node-gi.mjs && gjsify run --runtime node dist/test.node-gi.mjs"
|
|
35
35
|
},
|
|
36
36
|
"keywords": [
|
|
37
37
|
"gjs",
|
|
38
38
|
"node",
|
|
39
39
|
"sqlite",
|
|
40
|
-
"
|
|
40
|
+
"sqlite3"
|
|
41
41
|
],
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@gjsify/cli": "0.64.12-next.
|
|
43
|
+
"@gjsify/cli": "0.64.12-next.281",
|
|
44
44
|
"@gjsify/node-gi": "file:../../../packages/node-gi/node-gi",
|
|
45
|
-
"@gjsify/unit": "0.64.12-next.
|
|
45
|
+
"@gjsify/unit": "0.64.12-next.281",
|
|
46
46
|
"@types/node": "^25.9.2",
|
|
47
47
|
"typescript": "^6.0.3"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@girs/gda-6.0": "5.4.0",
|
|
51
|
-
"@girs/gio-2.0": "5.4.0",
|
|
52
50
|
"@girs/glib-2.0": "5.4.0",
|
|
53
|
-
"@
|
|
54
|
-
"@gjsify/utils": "0.64.12-next.280"
|
|
51
|
+
"@gjsify/sqlite-native": "0.64.12-next.281"
|
|
55
52
|
},
|
|
56
53
|
"gjsify": {
|
|
57
54
|
"runtimes": {
|
|
@@ -72,5 +69,5 @@
|
|
|
72
69
|
"url": "https://github.com/gjsify/gjsify/issues"
|
|
73
70
|
},
|
|
74
71
|
"homepage": "https://github.com/gjsify/gjsify/tree/main/packages/node/sqlite#readme",
|
|
75
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "c4d2e266c0d9849860b9828c14ebfe37b6d493b8"
|
|
76
73
|
}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{executeStatement as e,integerColumns as t,releaseRetained as n}from"./execution.js";import{parseSql as r}from"./parse-sql.js";import i from"@girs/gio-2.0";const a=new Set,o=new Map;function keyOf(e){return`${e.readOnly?`ro`:`rw`}\u0000${e.path}`}function fileIdentity(e){let t=i.File.new_for_path(e);try{return t.query_info(i.FILE_ATTRIBUTE_ID_FILE,i.FileQueryInfoFlags.NONE,null).get_attribute_string(i.FILE_ATTRIBUTE_ID_FILE)}catch{return null}}function exec(t,n){let[i]=r(t,n);e(t,i,null,()=>void 0)}function query(n,i,a){let[o]=r(n,i);return e(n,o,null,e=>{if(!e)return[];let t=[];for(let n=0;n<e.get_n_rows();n++){let r=[];for(let t=0;t<e.get_n_columns();t++)r.push(String(e.get_value_at(t,n)));t.push(r)}return t},{columns:t(a)})}const s={table:`TABLE`,view:`VIEW`,index:`INDEX`,trigger:`TRIGGER`};function userObjects(e,t){return query(e,`SELECT type, name FROM ${t} WHERE name NOT LIKE 'sqlite_%'
|
|
2
|
-
ORDER BY CASE type WHEN 'trigger' THEN 0 WHEN 'view' THEN 1 WHEN 'index' THEN 2 ELSE 3 END`,2)}function wipeMemory(e){for(let t of[`sqlite_master`,`sqlite_temp_master`])for(;;){let n=userObjects(e,t);if(n.length===0)break;let r=0;for(let[t,i]of n){let n=s[t];if(n)try{exec(e,`DROP ${n} IF EXISTS "${i.replace(/"/g,`""`)}"`),r++}catch{}}if(r===0)break}exec(e,`PRAGMA user_version = 0`),exec(e,`PRAGMA application_id = 0`)}function isPristine(e){for(let t of[`sqlite_master`,`sqlite_temp_master`])if(query(e,`SELECT name FROM ${t}`,1).length>0)return!1;for(let t of[`pragma_user_version()`,`pragma_application_id()`]){let[n]=query(e,`SELECT * FROM ${t}`,1);if(!n||n[0]!==`0`)return!1}return!0}function rollbackIfNeeded(e){e.get_transaction_status()&&exec(e,`ROLLBACK`)}function acquire(e,t){let n=o.get(keyOf(e)),r=e.isMemory?null:fileIdentity(e.path);for(;n&&n.length>0;){let t=n.pop();if(e.isMemory||r!==null&&t.fileId===r)return t.connection}let i=t();return a.add(i),i}function release(e,t){try{if(n(t),rollbackIfNeeded(t),e.isMemory&&(wipeMemory(t),!isPristine(t)))return;let r=keyOf(e),i=o.get(r)??[];i.push({connection:t,fileId:e.isMemory?null:fileIdentity(e.path)}),o.set(r,i)}catch{}}export{acquire,release};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{OutOfRangeError as e,SqliteError as t}from"./errors.js";const n=BigInt(2**53-1),r=/^[+-]?\d+$/;function convertIntegerText(t,i){if(r.test(t)){let r=BigInt(t);if(i)return r;if(r>n||r<-n)throw new e(`Value is too large to be represented as a JavaScript number: ${r}`);return Number(r)}let a=Number(t);return t.trim()!==``&&Number.isFinite(a)?a:t}function decodeBinaryString(e,n){let r=new Uint8Array(n),i=e.length,a=0,o=0;for(;o<i;){if(a>=n)throw new t(`BLOB decoded to more than ${n} bytes`);let i=e.charCodeAt(o);if(i!==92){if(i>127)throw new t(`BLOB holds a non-ASCII character at offset ${o}`);r[a++]=i,o+=1;continue}let s=e.charCodeAt(o+1)-48;if(s===44){r[a++]=92,o+=2;continue}let c=e.charCodeAt(o+2)-48,l=e.charCodeAt(o+3)-48;if(!(s>=0&&s<=3&&c>=0&&c<=7&&l>=0&&l<=7))throw new t(`BLOB holds an unknown escape at offset ${o}`);r[a++]=s<<6|c<<3|l,o+=4}if(a!==n)throw new t(`BLOB decoded to ${a} bytes, expected ${n}`);return r}function readBinary(e){return decodeBinaryString(e.to_string(0),e.get_size())}function convertValue(t,n,r=!1){if(t==null)return null;if(r&&typeof t==`string`)return convertIntegerText(t,n);if(typeof t==`number`){if(Number.isInteger(t)&&!Number.isSafeInteger(t)){if(!n)throw new e(`Value is too large to be represented as a JavaScript number: ${t}`);return BigInt(t)}return n&&Number.isInteger(t)?BigInt(t):t}if(typeof t==`bigint`){if(!n){if(t>BigInt(2**53-1)||t<BigInt(-(2**53-1)))throw new e(`Value is too large to be represented as a JavaScript number: ${t}`);return Number(t)}return t}if(typeof t==`string`||t instanceof Uint8Array)return t;let i=t;return typeof i.get_size==`function`&&typeof i.to_string==`function`?readBinary(i):t}function readRow(e,t,n){let r=e.get_n_columns();if(n.returnArrays){let i=[];for(let a=0;a<r;a++){let r=e.get_value_at(a,t);i.push(convertValue(r,n.readBigInts,n.textColumns?.[a]))}return i}let i=Object.create(null);for(let a=0;a<r;a++){let r=e.get_column_name(a);i[r]=convertValue(e.get_value_at(a,t),n.readBigInts,n.textColumns?.[a])}return i}function readAllRows(e,t){let n=e.get_n_rows(),r=[];for(let i=0;i<n;i++){let n=readRow(e,i,t);n!==void 0&&r.push(n)}return r}function readFirstRow(e,t){if(e.get_n_rows()!==0)return readRow(e,0,t)}export{readAllRows,readFirstRow,readRow};
|
package/lib/esm/execution.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{SqliteError as e}from"./errors.js";import t from"@girs/gda-6.0";import n from"@girs/gobject-2.0";let r=null;function typeNull(){if(r===null&&(t.value_new_null(),r=n.type_from_name(`GdaNull`),!r))throw new e(`libgda did not register GdaNull`);return r}const i=new Set([`gint`,`guint`,`gint64`,`guint64`,`gboolean`,`GDate`,`GdaTime`,`GDateTime`]);var ColumnTypes=class{types;constructor(e=null){this.types=e}get textColumns(){return(this.types??[]).map(e=>e===n.TYPE_STRING)}};function integerColumns(e){return new ColumnTypes(Array.from({length:e},()=>n.TYPE_STRING))}const a=new Map;function retainPrepared(e,t){for(a.delete(t),a.set(t,e);a.size>512;){let[e,t]=a.entries().next().value;a.delete(e),t.del_prepared_statement(e)}}function releaseStatement(e,t){a.delete(t),e.del_prepared_statement(t)}function releaseRetained(e){for(let[t,n]of a)n===e&&releaseStatement(e,t)}function executeStatement(e,t,n,r,i={}){let a=i.columns,o=null,s=!1;try{o=execute(e,t,n,a,i.kind),o&&assertTyped(o);let c=r(o,a?.textColumns??[]);return s=!isForwardCursor(t,o,a,i.kind),c}finally{o&&(s&&i.retain&&o.get_n_rows(),releasePreparedStatement(o)),s&&i.retain?retainPrepared(e,t):releaseStatement(e,t)}}function returnsRows(e,n){let r=e.get_statement_type();return r===t.SqlStatementType.SELECT?!0:r===t.SqlStatementType.UNKNOWN?n===`rows`:!1}function isForwardCursor(e,t,n,r){return t!==null&&n===void 0&&returnsRows(e,r)}function execute(e,n,r,i,a){if(returnsRows(n,a))return i?executeTyped(e,n,r,i):e.statement_execute_select_full(n,r,t.StatementModelUsage.CURSOR_FORWARD,null);let o=t.Batch.new();o.add_statement(n);let[s]=e.batch_execute(o,r,t.StatementModelUsage.RANDOM_ACCESS);return!s||s instanceof t.Set?null:s}function executeTyped(t,n,r,i){let a=i.types===null;a&&(i.types=probeColumns(t,n,r));let o=selectWith(t,n,r,i.types);if(matches(o,i.types))return o;if(releasePreparedStatement(o),releaseStatement(t,n),a)throw new e(`the result columns changed between two executions`);i.types=probeColumns(t,n,r);let s=selectWith(t,n,r,i.types);if(matches(s,i.types))return s;throw releasePreparedStatement(s),new e(`the result columns changed between two executions`)}function matches(e,t){if(e.get_n_columns()!==t.length)return!1;for(let r=0;r<t.length;r++){if(t[r]===n.TYPE_STRING)continue;let a=n.type_name(e.describe_column(r).get_g_type());if(a!==null&&i.has(a))return!1}return!0}function selectWith(e,r,i,a){return e.statement_execute_select_full(r,i,t.StatementModelUsage.RANDOM_ACCESS,[...a,n.TYPE_NONE])}function probeColumns(e,r,a){let o=e.statement_execute_select_full(r,a,t.StatementModelUsage.CURSOR_FORWARD,null);try{assertTyped(o);let e=[];for(let t=0;t<o.get_n_columns();t++){let r=n.type_name(o.describe_column(t).get_g_type());e.push(r!==null&&i.has(r)?n.TYPE_STRING:typeNull())}return e}finally{releasePreparedStatement(o),releaseStatement(e,r)}}function assertTyped(t){let n=t.get_n_columns();for(let r=0;r<n;r++){let n=t.describe_column(r);if(n&&!n.get_g_type())throw new e(`libgda could not type a result column; the connection has lost its SQLite provider`)}}function releasePreparedStatement(e){e.prepared_stmt=null}export{ColumnTypes,executeStatement,integerColumns,releaseRetained,releaseStatement};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{sqlRegions as e}from"./sql-regions.js";const t=/exists/i;function rewriteExistsSubqueries(n){if(!t.test(n))return n;let r=e(n),i=[],a=0,o={at:0,region:0};for(;o.at<n.length&&(seekToCode(n,r,o),!(o.at>=n.length));){let e=o.at;if(isExistsAt(n,r,o)){let t=openParenAfter(n,r,o),s=t<0?-1:matchingParen(n,r,t);if(s>=0){i.push(n.slice(a,e),`(1 IN (SELECT 1 FROM (`),i.push(rewriteExistsSubqueries(n.slice(t+1,s))),i.push(`)))`),a=s+1,o.at=s+1;continue}}o.at=e+1}return a===0?n:(i.push(n.slice(a)),i.join(``))}function seekToCode(e,t,n){for(;n.at<e.length;){for(;n.region<t.length-1&&t[n.region].end<=n.at;)n.region++;if(t[n.region].kind===`code`)return;n.at=t[n.region].end}}function isExistsAt(e,t,n){let r=n.at;return e.slice(r,r+6).toUpperCase()!==`EXISTS`||r>0&&/[A-Za-z0-9_$]/.test(e[r-1])?!1:openParenAfter(e,t,n)>=0}function openParenAfter(e,t,n){let r=n.at+6,i=n.region;for(;r<e.length;){for(;i<t.length-1&&t[i].end<=r;)i++;let n=t[i];if(n.kind===`code`){if(e[r]===`(`)return r;if(!/\s/.test(e[r]))return-1;r++}else r=n.end}return-1}function matchingParen(e,t,n){let r=0,i={at:n,region:0};for(;i.at<e.length&&(seekToCode(e,t,i),!(i.at>=e.length));){let t=e[i.at];if(t===`(`)r++;else if(t===`)`&&--r===0)return i.at;i.at++}return-1}export{rewriteExistsSubqueries};
|
package/lib/esm/param-binding.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{SqliteError as e}from"./errors.js";function setHolderValue(e,t){return e.set_value(t)}function releaseHolders(e,t){if(e)for(let[n,r]of t)r.type===`gchararray`&&e.get_holder(n)?.set_value(``)}function bindHolders(t,n){if(n.size!==0){if(!t)throw new e(`Failed to bind parameters: statement has no parameter set`);for(let[r,i]of n){let n=t.get_holder(r);if(!n)throw new e(`Failed to bind parameter '${r}'`);setHolderValue(n,i.value)}}}export{bindHolders,releaseHolders};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";const asStringHolder=e=>`##${e.gdaId}::string`;function convertParameterSyntax(e,t=asStringHolder){let n=[],r=0,i=``,a=0;for(;a<e.length;){if(e[a]===`'`){let t=a;for(a++;a<e.length&&e[a]!==`'`;){if(e[a]===`'`&&e[a+1]===`'`){a+=2;continue}a++}a<e.length&&a++,i+=e.substring(t,a);continue}if(e[a]===`?`){a++;let o=``;for(;a<e.length&&e[a]>=`0`&&e[a]<=`9`;)o+=e[a],a++;let s=o?parseInt(o,10)-1:r;r=o?r:r+1;let c={gdaId:`p${s}`,originalName:o?`?${o}`:`?`,position:s};n.push(c),i+=t(c);continue}if((e[a]===`$`||e[a]===`:`||e[a]===`@`)&&a+1<e.length&&/[a-zA-Z_]/.test(e[a+1])){let r=e[a];a++;let o=``;for(;a<e.length&&/[a-zA-Z0-9_]/.test(e[a]);)o+=e[a],a++;let s={gdaId:o,originalName:`${r}${o}`,position:-1};n.push(s),i+=t(s);continue}i+=e[a],a++}return[i,n]}export{asStringHolder,convertParameterSyntax};
|
package/lib/esm/parse-sql.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{SqliteError as e}from"./errors.js";function parseSql(t,n){let[r,i]=t.parse_sql_string(n);if(!r)throw new e(`Failed to parse SQL statement`);return[r,i]}export{parseSql};
|
package/lib/esm/sql-regions.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";function sqlRegions(e){let t=[],n=0,r=0;for(;r<e.length;){let i=r,a=e[r],o=`quoted`;if(a===`'`||a===`"`||a==="`"||a===`[`){let t=a===`[`?`]`:a,n=a!==`[`;for(r++;r<e.length;){if(e[r]===t){if(n&&e[r+1]===t){r+=2;continue}r++;break}r++}}else if(a===`-`&&e[r+1]===`-`)for(o=`line-comment`,r+=2;r<e.length&&e[r]!==`
|
|
2
|
-
`;)r++;else if(a===`/`&&e[r+1]===`*`){for(o=`block-comment`,r+=2;r<e.length&&!(e[r]===`*`&&e[r+1]===`/`);)r++;r=r<e.length?r+2:e.length}else{r++;continue}i>n&&t.push({kind:`code`,start:n,end:i}),t.push({kind:o,start:i,end:r}),n=r}return n<e.length&&t.push({kind:`code`,start:n,end:e.length}),t}export{sqlRegions};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{sqlRegions as e}from"./sql-regions.js";const t=new Set([`SELECT`,`VALUES`]),n=new Set([`INSERT`,`UPDATE`,`DELETE`,`REPLACE`]);function statementKind(e){let r=tokenize(e),i=r[0];if(!i||i.kind!==`word`)return`other`;let a=i.text.toUpperCase()===`WITH`?verbAfterCtes(r):i.text.toUpperCase();return a===null?`other`:t.has(a)?`rows`:n.has(a)?`write`:`other`}function providerSql(e,t){if(t!==`rows`)return e;let n=tokenize(e)[0];if(n&&n.kind===`word`&&n.text.toUpperCase()===`SELECT`)return e;let r=splitTrailingSemicolon(e);return`SELECT * FROM (${endsInsideLineComment(r.body)?`${r.body}\n`:r.body})${r.tail}`}function verbAfterCtes(e){let t=1;for(isWord(e[t],`RECURSIVE`)&&t++;;){if(!e[t]||e[t].kind!==`word`&&e[t].kind!==`quoted`)return null;if(t++,isPunct(e[t],`(`)){let n=matchingParen(e,t);if(n<0)return null;t=n+1}if(!isWord(e[t],`AS`)||(t++,isWord(e[t],`NOT`)&&t++,isWord(e[t],`MATERIALIZED`)&&t++,!isPunct(e[t],`(`)))return null;let n=matchingParen(e,t);if(n<0)return null;if(t=n+1,isPunct(e[t],`,`)){t++;continue}let r=e[t];return r&&r.kind===`word`?r.text.toUpperCase():null}}function matchingParen(e,t){let n=0;for(let r=t;r<e.length;r++)if(e[r].kind===`punct`){if(e[r].text===`(`)n++;else if(e[r].text===`)`&&--n===0)return r}return-1}function isWord(e,t){return e!==void 0&&e.kind===`word`&&e.text.toUpperCase()===t}function isPunct(e,t){return e!==void 0&&e.kind===`punct`&&e.text===t}function splitTrailingSemicolon(t){let n=e(t),r=-1;for(let e of n)if(e.kind===`code`)for(let n=e.start;n<e.end;n++)t[n]===`;`&&(r=n);if(r<0)return{body:t,tail:``};for(let e of n){let n=Math.max(e.start,r+1);if(!(n>=e.end)){if(e.kind===`code`){if(t.slice(n,e.end).trim()!==``)return{body:t,tail:``}}else if(e.kind===`quoted`)return{body:t,tail:``}}}return{body:t.slice(0,r),tail:t.slice(r)}}function endsInsideLineComment(t){let n=e(t),r=n[n.length-1];return r!==void 0&&r.kind===`line-comment`&&r.end===t.length}function tokenize(t){let n=[];for(let r of e(t)){if(r.kind===`quoted`){n.push({kind:`quoted`,text:t.slice(r.start,r.end)});continue}if(r.kind!==`code`)continue;let e=r.start;for(;e<r.end;){let i=t[e];if(isSpace(i)){e++;continue}if(i===`#`&&t[e+1]===`#`){let i=placeholderEnd(t,e,r.end);n.push({kind:`param`,text:t.slice(e,i)}),e=i;continue}if(i===`?`){let i=e+1;for(;i<r.end&&t[i]>=`0`&&t[i]<=`9`;)i++;n.push({kind:`param`,text:t.slice(e,i)}),e=i;continue}if((i===`:`||i===`$`||i===`@`)&&isNameStart(t[e+1])){let i=e+1;for(;i<r.end&&isNamePart(t[i]);)i++;n.push({kind:`param`,text:t.slice(e,i)}),e=i;continue}if(isNameStart(i)){let i=e+1;for(;i<r.end&&isNamePart(t[i]);)i++;n.push({kind:`word`,text:t.slice(e,i)}),e=i;continue}n.push({kind:`punct`,text:i}),e++}}return n}function placeholderEnd(e,t,n){let r=t+2;for(;r<n&&isNamePart(e[r]);)r++;if(e[r]===`:`&&e[r+1]===`:`)for(r+=2;r<n&&isNamePart(e[r]);)r++;return r}function isSpace(e){return e!==void 0&&/\s/.test(e)}function isNameStart(e){return e!==void 0&&/[A-Za-z_]/.test(e)}function isNamePart(e){return e!==void 0&&/[A-Za-z0-9_$]/.test(e)}export{providerSql,statementKind};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type Gda from '@girs/gda-6.0';
|
|
2
|
-
export interface PoolKey {
|
|
3
|
-
/** The database path as the caller gave it — `:memory:` or a file path. */
|
|
4
|
-
path: string;
|
|
5
|
-
isMemory: boolean;
|
|
6
|
-
readOnly: boolean;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* A connection for `key` — a parked one proven equivalent to a fresh one, or a new one
|
|
10
|
-
* from `create`.
|
|
11
|
-
*
|
|
12
|
-
* The caller's `create` is what knows the connection string; this module only owns the
|
|
13
|
-
* lifetime. A connection it returns is registered before it is handed out, so even a
|
|
14
|
-
* caller that drops it on the floor cannot let the garbage collector finalize it.
|
|
15
|
-
*/
|
|
16
|
-
export declare function acquire(key: PoolKey, create: () => Gda.Connection): Gda.Connection;
|
|
17
|
-
/**
|
|
18
|
-
* Take a connection back from a `DatabaseSync` that is done with it.
|
|
19
|
-
*
|
|
20
|
-
* Never closes it (see the note at the top of this file). A `:memory:` connection is
|
|
21
|
-
* wiped and parked only if it verifies as pristine afterwards; a file connection is parked
|
|
22
|
-
* with the identity of the file it is attached to.
|
|
23
|
-
*/
|
|
24
|
-
export declare function release(key: PoolKey, connection: Gda.Connection): void;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type Gda from '@girs/gda-6.0';
|
|
2
|
-
export interface ReadOptions {
|
|
3
|
-
readBigInts: boolean;
|
|
4
|
-
returnArrays: boolean;
|
|
5
|
-
/** Per column: true where libgda was told to hand the value over as text (execution.ts). */
|
|
6
|
-
textColumns?: boolean[];
|
|
7
|
-
}
|
|
8
|
-
export declare function readRow(model: Gda.DataModel, row: number, options: ReadOptions): Record<string, unknown> | unknown[] | undefined;
|
|
9
|
-
export declare function readAllRows(model: Gda.DataModel, options: ReadOptions): (Record<string, unknown> | unknown[])[];
|
|
10
|
-
export declare function readFirstRow(model: Gda.DataModel, options: ReadOptions): Record<string, unknown> | unknown[] | undefined;
|
package/lib/types/execution.d.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import Gda from '@girs/gda-6.0';
|
|
2
|
-
import GObject from '@girs/gobject-2.0';
|
|
3
|
-
import type { StatementKind } from './statement-kind.ts';
|
|
4
|
-
/**
|
|
5
|
-
* How the result columns of one prepared statement are read, remembered between its
|
|
6
|
-
* executions.
|
|
7
|
-
*
|
|
8
|
-
* Learning it costs an extra execution (see `probeColumns`), so a `StatementSync` keeps one
|
|
9
|
-
* of these for its lifetime. A column this has never seen typed (NULL in every probed row)
|
|
10
|
-
* is left to libgda; if a later execution types it integer-like, it is probed again.
|
|
11
|
-
*/
|
|
12
|
-
export declare class ColumnTypes {
|
|
13
|
-
/** Per column: TYPE_STRING to read as exact text, GdaNull to let libgda decide. */
|
|
14
|
-
types: GObject.GType[] | null;
|
|
15
|
-
constructor(types?: GObject.GType[] | null);
|
|
16
|
-
/** Which columns hold text that `data-model-reader.ts` must convert back. */
|
|
17
|
-
get textColumns(): boolean[];
|
|
18
|
-
}
|
|
19
|
-
/** Every column read as text — for a query whose columns are all known to be integers. */
|
|
20
|
-
export declare function integerColumns(count: number): ColumnTypes;
|
|
21
|
-
/**
|
|
22
|
-
* Drop the connection's prepared-statement cache entry for `stmt`.
|
|
23
|
-
*
|
|
24
|
-
* Call this when a statement is discarded rather than executed again — a reused one is
|
|
25
|
-
* retained by `executeStatement` instead. It is also the remedy for a stale entry: a
|
|
26
|
-
* retained `SELECT *` keeps the column count it was prepared with across an
|
|
27
|
-
* `ALTER TABLE … ADD COLUMN`, and deleting the entry is what makes the next execution see
|
|
28
|
-
* the new one (no reparse needed). `matches()` below is what notices.
|
|
29
|
-
*
|
|
30
|
-
* `del_prepared_statement()` does not check for a missing cache, which libgda creates on
|
|
31
|
-
* the first successful prepare. open()'s first PRAGMA is always one, so every connection
|
|
32
|
-
* this package hands out already has it.
|
|
33
|
-
*/
|
|
34
|
-
export declare function releaseStatement(connection: Gda.Connection, stmt: Gda.Statement): void;
|
|
35
|
-
/**
|
|
36
|
-
* Give back every cache entry retained on `connection`.
|
|
37
|
-
*
|
|
38
|
-
* A `StatementSync` asks for retention and is then collected without telling anyone, so
|
|
39
|
-
* the connection's own lifecycle is the only seam that can give its entries back — and it
|
|
40
|
-
* must: a parked connection is handed to the NEXT consumer, who can recreate a table a
|
|
41
|
-
* retained statement was compiled against. A never-closed `DatabaseSync` pins its
|
|
42
|
-
* connection plus at most `MAX_RETAINED` compiled statements — bounded, by design.
|
|
43
|
-
*/
|
|
44
|
-
export declare function releaseRetained(connection: Gda.Connection): void;
|
|
45
|
-
export interface ExecuteOptions {
|
|
46
|
-
/** How to read the result columns. Pass only when `read` reads rows. */
|
|
47
|
-
columns?: ColumnTypes;
|
|
48
|
-
/**
|
|
49
|
-
* Keep the connection's prepared-statement cache entry when the execution leaves the
|
|
50
|
-
* statement drained, so the next execution of the SAME `Gda.Statement` reuses the
|
|
51
|
-
* compiled `sqlite3_stmt` (see `retained`). Only a caller that HOLDS its statement for
|
|
52
|
-
* reuse asks for this; a one-shot statement would just occupy the bound.
|
|
53
|
-
*/
|
|
54
|
-
retain?: boolean;
|
|
55
|
-
/**
|
|
56
|
-
* What the statement does, for the statements libgda cannot classify.
|
|
57
|
-
*
|
|
58
|
-
* A statement with a CTE reaches libgda as UNKNOWN whatever it does (see
|
|
59
|
-
* `statement-kind.ts`), so the row-vs-rows decision cannot be left to
|
|
60
|
-
* `get_statement_type()` alone — the answer comes from the SQL text instead. A
|
|
61
|
-
* caller that does not know the statement leaves it out, and an UNKNOWN statement
|
|
62
|
-
* then keeps the path it had.
|
|
63
|
-
*/
|
|
64
|
-
kind?: StatementKind;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Execute `stmt`, hand its result to `read`, and leave NOTHING behind on the connection.
|
|
68
|
-
*
|
|
69
|
-
* libgda keeps state per execution that only the connection's close() or the garbage
|
|
70
|
-
* collector would otherwise release, and on a long-lived connection that state runs out:
|
|
71
|
-
*
|
|
72
|
-
* - The connection caches a prepared statement (`GdaSqlitePStmt`) for every
|
|
73
|
-
* `Gda.Statement` it ever executed, holding a STRONG reference to both, until the
|
|
74
|
-
* statement emits `reset` — which ours never do — or the connection closes. This package
|
|
75
|
-
* renders a fresh statement per execution, so the cache grew by one on every call.
|
|
76
|
-
* - Every `GdaSqlitePStmt` holds a GWeakRef to the SQLite provider, and GLib (≥ 2.84) caps
|
|
77
|
-
* the GWeakRefs on one object at 65535. Past it, `g_weak_ref_set()` refuses with
|
|
78
|
-
* "Too many GWeakRef registered", the next prepared statement has no provider, and
|
|
79
|
-
* libgda answers `fuzzy_get_gtype: assertion 'prov != NULL' failed` — a CRITICAL, not an
|
|
80
|
-
* error. Reads on that connection came back typeless or empty with no exception.
|
|
81
|
-
* - A SELECT's data model (`GdaSqliteRecordset`) holds its prepared statement until the
|
|
82
|
-
* model is finalized, and the model is a GJS wrapper the garbage collector frees
|
|
83
|
-
* whenever it gets round to it. Measured: ~70,000 unread models outlive one GC.
|
|
84
|
-
* - `statement_execute_non_select()` has a `last_insert_row` out-parameter. GJS always
|
|
85
|
-
* passes the pointer, so on every INSERT the SQLite provider built and executed a
|
|
86
|
-
* hidden `SELECT * FROM <table> WHERE rowid = ?` — on a statement of its own that the
|
|
87
|
-
* connection cached as above, where no caller can reach it to release it.
|
|
88
|
-
*
|
|
89
|
-
* So: non-SELECTs go through `batch_execute()`, which passes `last_insert_row` as NULL;
|
|
90
|
-
* the connection's cache entry is deleted after every execution unless the caller asks to
|
|
91
|
-
* keep it for a statement it will run again (`ExecuteOptions.retain`, bounded by
|
|
92
|
-
* `retained`); and the data model lets go of its prepared statement as soon as `read`
|
|
93
|
-
* returns. Every object an execution creates is then released before this function does.
|
|
94
|
-
*
|
|
95
|
-
* Do NOT use `GObject.Object.run_dispose()` on the model instead: `GdaSqliteRecordset`'s
|
|
96
|
-
* dispose clears a GWeakRef without re-initialising it, so the second dispose the
|
|
97
|
-
* finalizer runs dereferences a cleared weak ref and the process dies with SIGSEGV.
|
|
98
|
-
*/
|
|
99
|
-
export declare function executeStatement<T>(connection: Gda.Connection, stmt: Gda.Statement, params: Gda.Set | null, read: (model: Gda.DataModel | null, textColumns: boolean[]) => T, options?: ExecuteOptions): T;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `EXISTS (S)` → `(1 IN (SELECT 1 FROM (S)))`, for every `EXISTS (` in `sql`.
|
|
3
|
-
*
|
|
4
|
-
* Equivalent by construction: the derived table `S` yields one row per row of `S` and
|
|
5
|
-
* every one of them holds the constant `1`, so `1 IN (…)` is true exactly when `S` yields
|
|
6
|
-
* a row — which is what `EXISTS (S)` means. The derived table is what makes that
|
|
7
|
-
* independent of what `S` projects; `1 IN (S)` on its own would only agree while `S`
|
|
8
|
-
* already projected the constant 1. The `IN` form is the one construct libgda renders
|
|
9
|
-
* correctly: an operation operand that is a sub-SELECT gets ONE pair of parentheses,
|
|
10
|
-
* from `default_render_operation()`, which marks the operand composed rather than
|
|
11
|
-
* parenthesising it a second time.
|
|
12
|
-
*
|
|
13
|
-
* The outer parentheses keep `NOT` and `AND`/`OR` bound to the predicate the caller
|
|
14
|
-
* wrote: without them `NOT EXISTS (S)` would become `NOT 1 IN (…)`, which SQL reads the
|
|
15
|
-
* same way but which no longer looks like the subquery the caller passed.
|
|
16
|
-
*
|
|
17
|
-
* `S` is copied byte for byte, so every parameter, literal and identifier inside it keeps
|
|
18
|
-
* its position and its text — which is what keeps the holders this package binds
|
|
19
|
-
* (`Gda.Set`) lined up with the `?` placeholders of the rendered statement.
|
|
20
|
-
*
|
|
21
|
-
* A nested `EXISTS` inside `S` is rewritten too, and only occurrences in CODE are
|
|
22
|
-
* touched: `sqlRegions()` is what keeps the word out of a string literal, a quoted
|
|
23
|
-
* identifier and a comment. A comment BETWEEN the keyword and its parenthesis counts as
|
|
24
|
-
* nothing at all, because SQLite's own tokenizer skips it there — `EXISTS -- c\n(SELECT …)`
|
|
25
|
-
* is ONE statement and has to be rewritten as one. An `EXISTS` not followed by a `(` — a
|
|
26
|
-
* column, a longer identifier ending in it, prose in a comment — is left alone, as is an
|
|
27
|
-
* unterminated `(`, which is a syntax error libgda should report in its own words.
|
|
28
|
-
*
|
|
29
|
-
* The cost of the IN form, recorded so it is not "optimised" away: SQLite materialises `S`
|
|
30
|
-
* into an ephemeral index (a `LIST SUBQUERY` scan with a bloom filter, measured on 100k
|
|
31
|
-
* rows) where `EXISTS` stops at the first row, and `LIMIT 1` on `S` does NOT bring that
|
|
32
|
-
* plan back (measured). The faster scalar restatement, `(SELECT 1 FROM (S) LIMIT 1) = 1`,
|
|
33
|
-
* answers NULL instead of 0 in a projection when `S` is empty (measured) — so the IN form
|
|
34
|
-
* is the one that is correct in every position.
|
|
35
|
-
*/
|
|
36
|
-
export declare function rewriteExistsSubqueries(sql: string): string;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type Gda from '@girs/gda-6.0';
|
|
2
|
-
/**
|
|
3
|
-
* The GType a value is bound through, spelled the same way in the `##id::type`
|
|
4
|
-
* placeholder and in the holder libgda creates from it.
|
|
5
|
-
*
|
|
6
|
-
* Measured against a TEXT read-back of the stored value: `gint64` round-trips every
|
|
7
|
-
* int64 exactly — 2^53 + 1 and both extremes included — and `gdouble` yields a REAL, so
|
|
8
|
-
* `42` reads back as `42.0`, `Infinity` as `Inf` and `NaN` as NULL. Value for value that
|
|
9
|
-
* is what the SQL literals these replaced produced.
|
|
10
|
-
*/
|
|
11
|
-
export type HolderType = 'gchararray' | 'gint64' | 'gdouble';
|
|
12
|
-
/** One parameter of one execution, bound rather than written into the SQL. */
|
|
13
|
-
export interface HolderBinding {
|
|
14
|
-
type: HolderType;
|
|
15
|
-
value: string | number | bigint;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Let go of the strings an execution bound.
|
|
19
|
-
*
|
|
20
|
-
* A `Gda.Holder` keeps the value it was given until its `Gda.Set` is finalized, and the
|
|
21
|
-
* Set is a GJS wrapper the garbage collector frees whenever it gets round to it — which
|
|
22
|
-
* is late, because the collector cannot see the native copy. Measured on 8000 inserts of
|
|
23
|
-
* a ~56 KB text each: 86 → 563 MiB without this, 59 → 96 MiB with it. Numbers are not
|
|
24
|
-
* worth the call; only a string can be large.
|
|
25
|
-
*/
|
|
26
|
-
export declare function releaseHolders(paramSet: Gda.Set | null, bindings: Map<string, HolderBinding>): void;
|
|
27
|
-
/**
|
|
28
|
-
* Bind the parameters of one execution to the holders libgda created for them.
|
|
29
|
-
*
|
|
30
|
-
* A bound parameter is what lets the SQL TEXT stay the same across executions, which is
|
|
31
|
-
* what lets the parsed statement — and the connection's compiled `sqlite3_stmt` behind it
|
|
32
|
-
* — be reused (see execution.ts). NULL and BLOBs are the two values that cannot take this
|
|
33
|
-
* route and stay SQL literals: libgda refuses NULL through a holder by every spelling
|
|
34
|
-
* (`set_value(null)`, `Gda.value_new_null()`, `force_invalid()`, and leaving it unset all
|
|
35
|
-
* raise), and a `Uint8Array` is "Could not guess unspecified GValue type" while a
|
|
36
|
-
* `GLib.Bytes` is a type mismatch.
|
|
37
|
-
*
|
|
38
|
-
* A string is the one type that MUST be bound: libgda reads `\` as an escape inside `'…'`
|
|
39
|
-
* where SQLite does not, so a value ending in a backslash ran the quoted region past its
|
|
40
|
-
* intended end (see parse-sql.ts).
|
|
41
|
-
*
|
|
42
|
-
* A missing holder is a bug in this package — the SQL and the holder set come from the
|
|
43
|
-
* same `convertParameterSyntax` pass — so it raises rather than binding nothing and
|
|
44
|
-
* silently writing NULL.
|
|
45
|
-
*/
|
|
46
|
-
export declare function bindHolders(paramSet: Gda.Set | null, bindings: Map<string, HolderBinding>): void;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/** One placeholder found in the SQL. `position` is -1 for named parameters. */
|
|
2
|
-
export interface ParamInfo {
|
|
3
|
-
gdaId: string;
|
|
4
|
-
originalName: string;
|
|
5
|
-
position: number;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Decides what a placeholder becomes in the SQL handed to libgda.
|
|
9
|
-
*
|
|
10
|
-
* `StatementSync` substitutes this per execution, because the choice depends on the value:
|
|
11
|
-
* anything libgda can carry becomes a `##id::<type>` holder so the value never enters the
|
|
12
|
-
* SQL, and only NULL and a BLOB — which no holder accepts — become a literal, drawn from
|
|
13
|
-
* an alphabet that cannot end a quoted region. Callers that only need to VALIDATE the SQL,
|
|
14
|
-
* where no values exist yet, take the default.
|
|
15
|
-
*/
|
|
16
|
-
export type PlaceholderRenderer = (param: ParamInfo) => string;
|
|
17
|
-
export declare const asStringHolder: PlaceholderRenderer;
|
|
18
|
-
/**
|
|
19
|
-
* Rewrite `sql` with every parameter rendered by `render`, and report the parameters in
|
|
20
|
-
* source order. String literals are copied verbatim so a `?` or `:name` inside one is not
|
|
21
|
-
* mistaken for a placeholder.
|
|
22
|
-
*/
|
|
23
|
-
export declare function convertParameterSyntax(sql: string, render?: PlaceholderRenderer): [string, ParamInfo[]];
|
package/lib/types/parse-sql.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type Gda from '@girs/gda-6.0';
|
|
2
|
-
/**
|
|
3
|
-
* Parse a single SQL statement and return it with its parameter set.
|
|
4
|
-
*
|
|
5
|
-
* **Never call `Gda.SqlParser.parse_string()` in this package.** Its `remain`
|
|
6
|
-
* out-parameter points INTO the SQL string that was passed in — it is the unparsed tail,
|
|
7
|
-
* not an allocation — but `Gda-6.0.gir` declares it `transfer-ownership="full"`:
|
|
8
|
-
*
|
|
9
|
-
* ```xml
|
|
10
|
-
* <parameter name="remain" direction="out" transfer-ownership="full" nullable="1">
|
|
11
|
-
* <type name="utf8" c:type="const gchar**"/>
|
|
12
|
-
* ```
|
|
13
|
-
*
|
|
14
|
-
* So whenever libgda stops before the end of the string, GJS calls `g_free()` on an
|
|
15
|
-
* interior pointer at call teardown and glibc aborts the process: `free(): invalid
|
|
16
|
-
* pointer`, SIGABRT, no JS exception, no return value. Nothing can catch it and nothing
|
|
17
|
-
* can be checked first — asking for the parse IS the crash. A block comment does it; so
|
|
18
|
-
* does a statement whose string literal libgda thinks ends elsewhere than SQLite does
|
|
19
|
-
* (libgda honours `\` as an escape inside `'…'`, SQLite does not — which is how a mail
|
|
20
|
-
* body ending in a backslash killed a consumer mid-import).
|
|
21
|
-
*
|
|
22
|
-
* `gda_connection_parse_sql_string()` takes no `remain` at all, so the same input raises
|
|
23
|
-
* an ordinary catchable error. It also hands back the `Gda.Set` of parameter holders,
|
|
24
|
-
* which is what lets values be BOUND instead of spliced into the SQL text.
|
|
25
|
-
*/
|
|
26
|
-
export declare function parseSql(connection: Gda.Connection, sql: string): [Gda.Statement, Gda.Set | null];
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a stretch of the SQL text is. Only `code` is parsed; the other three are inert
|
|
3
|
-
* bytes that must be copied through untouched.
|
|
4
|
-
*/
|
|
5
|
-
export type SqlRegionKind = 'code' | 'quoted' | 'line-comment' | 'block-comment';
|
|
6
|
-
export interface SqlRegion {
|
|
7
|
-
kind: SqlRegionKind;
|
|
8
|
-
/** Index of the first character, and one past the last. */
|
|
9
|
-
start: number;
|
|
10
|
-
end: number;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Split `sql` into alternating code and inert regions, in source order and covering it
|
|
14
|
-
* exactly — a region is never empty, and no two regions touch. Neither end is
|
|
15
|
-
* necessarily `code`: SQL beginning with a comment yields a first region of that kind, and
|
|
16
|
-
* so does SQL ending in one, so a caller that walks the list must not assume either.
|
|
17
|
-
*
|
|
18
|
-
* A line comment ends BEFORE its terminating newline, so the newline is CODE and the next
|
|
19
|
-
* statement is found from it. That is SQLite's own rule, and it is what lets a consumer
|
|
20
|
-
* write `EXISTS -- why\n(SELECT …)` and have the parenthesis still be the sub-SELECT's.
|
|
21
|
-
*
|
|
22
|
-
* An unterminated quoted region or comment runs to the end of the input, which is what
|
|
23
|
-
* SQLite's own tokenizer does with the same input.
|
|
24
|
-
*/
|
|
25
|
-
export declare function sqlRegions(sql: string): SqlRegion[];
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a statement does.
|
|
3
|
-
*
|
|
4
|
-
* `other` is everything this package does not read rows from and does not treat as a
|
|
5
|
-
* write: a PRAGMA, a CREATE, an EXPLAIN. Those keep the path they had before — see
|
|
6
|
-
* `returnsRows()` in execution.ts.
|
|
7
|
-
*/
|
|
8
|
-
export type StatementKind = 'rows' | 'write' | 'other';
|
|
9
|
-
/**
|
|
10
|
-
* Does this statement return rows, write, or neither?
|
|
11
|
-
*
|
|
12
|
-
* The answer comes from the SQL TEXT, because libgda's own classification cannot be
|
|
13
|
-
* asked: a statement with a CTE is UNKNOWN to it whatever it does (see the header).
|
|
14
|
-
*
|
|
15
|
-
* A statement that does not start with `WITH` is classified by its first word. A
|
|
16
|
-
* `WITH` statement is classified by the verb that follows its CTE definitions — the
|
|
17
|
-
* CTEs themselves may hide anything, so the verb is what decides, and `WITH q AS
|
|
18
|
-
* (SELECT 1) INSERT INTO t SELECT * FROM q` is a WRITE.
|
|
19
|
-
*/
|
|
20
|
-
export declare function statementKind(sql: string): StatementKind;
|
|
21
|
-
/**
|
|
22
|
-
* The text the provider must be given for a statement of this kind.
|
|
23
|
-
*
|
|
24
|
-
* The provider dispatches on the FIRST WORD of the text it renders (see the header), so
|
|
25
|
-
* a statement that returns rows but does not start with `SELECT` has to be stated in a
|
|
26
|
-
* shape that does: `SELECT * FROM ( … )` — a derived table, which SQLite accepts around
|
|
27
|
-
* a whole CTE statement. The rows and their column names are the inner statement's:
|
|
28
|
-
* SQLite names the columns of a subquery after the ones its own SELECT produced.
|
|
29
|
-
*
|
|
30
|
-
* A statement that already starts with `SELECT` is handed over unchanged, and so is
|
|
31
|
-
* every statement that does not return rows: a write must stay a write, and the
|
|
32
|
-
* provider runs it as a command — which is what an INSERT, an UPDATE and a DELETE
|
|
33
|
-
* need.
|
|
34
|
-
*
|
|
35
|
-
* A trailing `;` moves OUT of the parentheses: it would end the statement there and
|
|
36
|
-
* leave the parenthesis unclosed ("incomplete input"). SQLite does not need it, and
|
|
37
|
-
* libgda's parser drops a trailing `;` of its own accord.
|
|
38
|
-
*/
|
|
39
|
-
export declare function providerSql(sql: string, kind: StatementKind): string;
|