@gjsify/sqlite 0.64.3-next.264 → 0.64.4
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/connection-pool.js +2 -2
- package/lib/esm/database-sync.js +1 -1
- package/lib/esm/execution.js +1 -1
- package/lib/esm/param-binding.js +1 -1
- package/lib/esm/statement-sync.js +1 -1
- package/lib/types/execution.d.ts +40 -4
- package/lib/types/param-binding.d.ts +40 -7
- package/lib/types/parameter-syntax.d.ts +4 -3
- package/lib/types/statement-cache.spec.d.ts +2 -0
- package/package.json +5 -6
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{executeStatement as e,integerColumns as t}from"./execution.js";import{parseSql as
|
|
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=
|
|
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};
|
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,SqliteError as i,isNodeSqliteError as a,sqliteErrorMessage as o}from"./errors.js";import{executeStatement as s}from"./execution.js";import{parseSql as c}from"./parse-sql.js";import{acquire as l,release as u}from"./connection-pool.js";import{convertParameterSyntax as d}from"./parameter-syntax.js";import{sqlRegions as f}from"./sql-regions.js";import{rewriteExistsSubqueries as p}from"./exists-subquery.js";import{StatementSync as m}from"./statement-sync.js";import h from"@girs/gda-6.0";import{lastPathSeparatorIndex as g}from"@gjsify/utils/core";const _=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;#i=!1;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[_](){return`node:sqlite`}get isOpen(){return this.#e!==null&&this.#e.is_opened()}get isTransaction(){return this.#a(),this.#i}open(){if(this.isOpen)throw new n(`database is already open`);try{this.#e=l(this.#o(),()=>{let e;if(this.#r)e=h.Connection.new_from_string(`SQLite`,`DB_DIR=;DB_NAME=:memory:`,null,h.ConnectionOptions.NONE);else{let t=g(this.#t),n=t>=0?this.#t.substring(0,t):`.`,r=t>=0?this.#t.substring(t+1):this.#t,i=`DB_DIR=${n};DB_NAME=${r.endsWith(`.db`)?r.slice(0,-3):r}`,a=this.#n.readOnly?h.ConnectionOptions.READ_ONLY:h.ConnectionOptions.NONE;e=h.Connection.new_from_string(`SQLite`,i,null,a)}return e.open(),e})}catch(e){throw this.#e=null,new i(o(e))}this.#c()}close(){if(!this.isOpen)throw new n(`database is not open`);u(this.#o(),this.#e),this.#e=null,this.#i=!1}sqlExec(e){if(this.#a(),typeof e!=`string`)throw new t(`The "sql" argument must be a string.`);try{let t=this.#l(e);for(let e of t){let[t]=this.#s(p(e));s(this.#e,t,null,()=>void 0)}}catch(e){throw a(e)?e:new i(o(e))}this.#u(
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{ConstructCallRequiredError as e,InvalidArgTypeError as t,InvalidStateError as n,InvalidUrlSchemeError as r,SqliteError as i,isNodeSqliteError as a,sqliteErrorMessage as o}from"./errors.js";import{executeStatement as s}from"./execution.js";import{parseSql as c}from"./parse-sql.js";import{acquire as l,release as u}from"./connection-pool.js";import{convertParameterSyntax as d}from"./parameter-syntax.js";import{sqlRegions as f}from"./sql-regions.js";import{rewriteExistsSubqueries as p}from"./exists-subquery.js";import{StatementSync as m}from"./statement-sync.js";import h from"@girs/gda-6.0";import{lastPathSeparatorIndex as g}from"@gjsify/utils/core";const _=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;#i=!1;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[_](){return`node:sqlite`}get isOpen(){return this.#e!==null&&this.#e.is_opened()}get isTransaction(){return this.#a(),this.#i}open(){if(this.isOpen)throw new n(`database is already open`);try{this.#e=l(this.#o(),()=>{let e;if(this.#r)e=h.Connection.new_from_string(`SQLite`,`DB_DIR=;DB_NAME=:memory:`,null,h.ConnectionOptions.NONE);else{let t=g(this.#t),n=t>=0?this.#t.substring(0,t):`.`,r=t>=0?this.#t.substring(t+1):this.#t,i=`DB_DIR=${n};DB_NAME=${r.endsWith(`.db`)?r.slice(0,-3):r}`,a=this.#n.readOnly?h.ConnectionOptions.READ_ONLY:h.ConnectionOptions.NONE;e=h.Connection.new_from_string(`SQLite`,i,null,a)}return e.open(),e})}catch(e){throw this.#e=null,new i(o(e))}this.#c()}close(){if(!this.isOpen)throw new n(`database is not open`);u(this.#o(),this.#e),this.#e=null,this.#i=!1}sqlExec(e){if(this.#a(),typeof e!=`string`)throw new t(`The "sql" argument must be a string.`);try{let t=this.#l(e);for(let e of t){let[t]=this.#s(p(e));s(this.#e,t,null,()=>void 0)}}catch(e){throw a(e)?e:new i(o(e))}this.#u()}prepare(e,n){if(this.#a(),typeof e!=`string`)throw new t(`The "sql" argument must be a string.`);let[r,s]=d(e);try{this.#s(p(r))}catch(e){throw a(e)?e:new i(o(e))}let c={readBigInts:this.#n.readBigInts??!1,returnArrays:this.#n.returnArrays??!1,allowBareNamedParameters:this.#n.allowBareNamedParameters??!0,allowUnknownNamedParameters:this.#n.allowUnknownNamedParameters??!1};return m._create(this.#e,e,c,s)}location(e){if(this.#a(),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()}#a(){if(!this.isOpen)throw new n(`database is not open`)}#o(){return{path:this.#t,isMemory:this.#r,readOnly:this.#n.readOnly??!1}}#s(e){return c(this.#e,e)}#c(){let runPragma=e=>{let[t]=this.#s(e);s(this.#e,t,null,()=>void 0)};this.#n.enableForeignKeyConstraints===!1?runPragma(`PRAGMA foreign_keys = OFF`):runPragma(`PRAGMA foreign_keys = ON`),this.#n.timeout!==void 0&&this.#n.timeout>0&&runPragma(`PRAGMA busy_timeout = ${this.#n.timeout}`)}#l(e){let t=[],n=``,flush=()=>{let e=n.trim();e.length>0&&t.push(e),n=``};for(let t of f(e))if(t.kind===`code`){let r=e.slice(t.start,t.end).split(`;`);n+=r[0];for(let e of r.slice(1))flush(),n+=e}else t.kind===`block-comment`?n+=` `:n+=e.slice(t.start,t.end);return flush(),t}#u(){this.#i=this.#e.get_transaction_status()!==null}};DatabaseSync.prototype.exec=DatabaseSync.prototype.sqlExec;export{DatabaseSync};
|
package/lib/esm/execution.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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))}function executeStatement(e,t,n,r,i){let a=null;try{
|
|
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),o&&assertTyped(o);let i=r(o,a?.textColumns??[]);return s=!isForwardCursor(t,o,a),i}finally{o&&(s&&i.retain&&o.get_n_rows(),releasePreparedStatement(o)),s&&i.retain?retainPrepared(e,t):releaseStatement(e,t)}}function isForwardCursor(e,n,r){return n!==null&&r===void 0&&e.get_statement_type()===t.SqlStatementType.SELECT}function execute(e,n,r,i){if(n.get_statement_type()===t.SqlStatementType.SELECT)return i?executeTyped(e,n,r,i):e.statement_execute_select_full(n,r,t.StatementModelUsage.CURSOR_FORWARD,null);let a=t.Batch.new();a.add_statement(n);let[o]=e.batch_execute(a,r,t.StatementModelUsage.RANDOM_ACCESS);return!o||o instanceof t.Set?null:o}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};
|
package/lib/esm/param-binding.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{SqliteError as e}from"./errors.js";function
|
|
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 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{IllegalConstructorError as e,InvalidArgTypeError as t,InvalidArgValueError as n,SqliteError as r,isNodeSqliteError as i,sqliteErrorMessage as a}from"./errors.js";import{ColumnTypes as o,executeStatement as s,integerColumns as c}from"./execution.js";import{parseSql as
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{IllegalConstructorError as e,InvalidArgTypeError as t,InvalidArgValueError as n,SqliteError as r,isNodeSqliteError as i,sqliteErrorMessage as a}from"./errors.js";import{ColumnTypes as o,executeStatement as s,integerColumns as c,releaseStatement as l}from"./execution.js";import{parseSql as u}from"./parse-sql.js";import{readAllRows as d,readFirstRow as f}from"./data-model-reader.js";import{convertParameterSyntax as p}from"./parameter-syntax.js";import{rewriteExistsSubqueries as m}from"./exists-subquery.js";import{bindHolders as h,releaseHolders as g}from"./param-binding.js";const _=Symbol(`StatementSync.internal`),v=`SELECT changes(), last_insert_rowid()`,y=c(2),b=new WeakMap;function counterStatement(e){let t=b.get(e);if(t)return t;let[n]=u(e,v);return b.set(e,n),n}function isNamedArgObject(e){return typeof e==`object`&&!!e&&!(e instanceof Uint8Array)&&!ArrayBuffer.isView(e)}function validateBindValue(e,n){if(e==null)return;let r=typeof e;if(!(r===`number`||r===`bigint`||r===`string`||r===`boolean`)&&!(e instanceof Uint8Array||e instanceof ArrayBuffer)&&!ArrayBuffer.isView(e))throw new t(`Provided value cannot be bound to SQLite parameter ${n}.`)}function holderBinding(e){if(typeof e==`string`)return{type:`gchararray`,value:e};if(typeof e==`number`)return{type:`gdouble`,value:e};if(typeof e==`bigint`){if(e>9223372036854775807n||e<-9223372036854775808n)throw new n(`BigInt value is too large to bind.`);return{type:`gint64`,value:e}}return typeof e==`boolean`?{type:`gint64`,value:+!!e}:null}function sqlLiteral(e){if(e instanceof Uint8Array){let t=``;for(let n=0;n<e.length;n++)t+=e[n].toString(16).padStart(2,`0`);return`X'`+t+`'`}return ArrayBuffer.isView(e)?sqlLiteral(new Uint8Array(e.buffer)):`NULL`}var x=class StatementSync{#e;#t;#n;#r;#i;#a;#o;#s=new o;#c=new Map;constructor(t,n,r,i,a){if(t!==_)throw new e;this.#e=n,this.#t=r,this.#n=a,this.#r=i.readBigInts??!1,this.#i=i.returnArrays??!1,this.#a=i.allowBareNamedParameters??!0,this.#o=i.allowUnknownNamedParameters??!1}static _create(e,t,n,r){return new StatementSync(_,e,t,n,r)}get sourceSQL(){return this.#t}get expandedSQL(){return this.#t}#l(e){return{readBigInts:this.#r,returnArrays:this.#i,textColumns:e}}#u(){let e=-1;for(let t of this.#n)t.position>e&&(e=t.position);return e}#d(e){let t=new Map;if(this.#n.length===0){if(e.length>0&&!isNamedArgObject(e[0]))throw new r(`column index out of range`,25,`column index out of range`);return{sql:this.#t,bindings:t}}let n=null,i=e;e.length>0&&isNamedArgObject(e[0])&&(n=e[0],i=e.slice(1));let a=new Map;if(n){for(let e of this.#n){if(e.position>=0)continue;let t=e.originalName,i,o=!1;if(t in n&&(i=n[t],o=!0),!o&&this.#a){let e=t.replace(/^[$:@]/,``);e in n&&(i=n[e],o=!0)}if(!o&&!this.#a){let e=t.replace(/^[$:@]/,``);if(e in n)throw new r(`Unknown named parameter '${e}'`,0,`Unknown named parameter '${e}'`)}o&&(validateBindValue(i,this.#n.indexOf(e)+1),a.set(e.gdaId,i))}if(!this.#o){let e=new Set;for(let t of this.#n)t.position>=0||(e.add(t.originalName),e.add(t.originalName.replace(/^[$:@]/,``)));for(let t of Object.keys(n))if(!e.has(t)&&!e.has(t.replace(/^[$:@]/,``)))throw new r(`Unknown named parameter '${t}'`,0,`Unknown named parameter '${t}'`)}for(let e=0;e<i.length;e++){if(e>this.#u())throw new r(`column index out of range`,25,`column index out of range`);validateBindValue(i[e],e+1),a.set(`p${e}`,i[e])}}else{let e=this.#u()+1;if(i.length>e&&e>0)throw new r(`column index out of range`,25,`column index out of range`);for(let t=0;t<Math.min(i.length,e);t++)validateBindValue(i[t],t+1),a.set(`p${t}`,i[t])}let[o]=p(this.#t,e=>{let n=a.get(e.gdaId),r=holderBinding(n);return r?(t.set(e.gdaId,r),`##${e.gdaId}::${r.type}`):sqlLiteral(n)});return{sql:o,bindings:t}}#f(e){let t=this.#c.get(e);if(t)return this.#c.delete(e),this.#c.set(e,t),t;let n=u(this.#e,m(e));for(this.#c.set(e,n);this.#c.size>8;){let[e,[t]]=this.#c.entries().next().value;this.#c.delete(e),l(this.#e,t)}return n}#p(e,t,n){let{sql:o,bindings:c}=this.#d(e),l=null;try{let e;return[e,l]=this.#f(o),h(l,c),s(this.#e,e,l,t,{columns:n,retain:!0})}catch(e){throw i(e)?e:new r(a(e))}finally{g(l,c)}}run(...e){this.#p(e,()=>void 0);let[t,n]=s(this.#e,counterStatement(this.#e),null,e=>{if(!e||e.get_n_rows()===0)throw new r(`${v} returned no row`);return[BigInt(e.get_value_at(0,0)),BigInt(e.get_value_at(1,0))]},{columns:y,retain:!0});return this.#r?{changes:t,lastInsertRowid:n}:{changes:Number(t),lastInsertRowid:Number(n)}}get(...e){return this.#p(e,(e,t)=>{if(!(!e||e.get_n_rows()===0))return f(e,this.#l(t))},this.#s)}all(...e){return this.#p(e,(e,t)=>e?d(e,this.#l(t)):[],this.#s)}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}};export{x as StatementSync};
|
package/lib/types/execution.d.ts
CHANGED
|
@@ -17,6 +17,41 @@ export declare class ColumnTypes {
|
|
|
17
17
|
}
|
|
18
18
|
/** Every column read as text — for a query whose columns are all known to be integers. */
|
|
19
19
|
export declare function integerColumns(count: number): ColumnTypes;
|
|
20
|
+
/**
|
|
21
|
+
* Drop the connection's prepared-statement cache entry for `stmt`.
|
|
22
|
+
*
|
|
23
|
+
* Call this when a statement is discarded rather than executed again — a reused one is
|
|
24
|
+
* retained by `executeStatement` instead. It is also the remedy for a stale entry: a
|
|
25
|
+
* retained `SELECT *` keeps the column count it was prepared with across an
|
|
26
|
+
* `ALTER TABLE … ADD COLUMN`, and deleting the entry is what makes the next execution see
|
|
27
|
+
* the new one (no reparse needed). `matches()` below is what notices.
|
|
28
|
+
*
|
|
29
|
+
* `del_prepared_statement()` does not check for a missing cache, which libgda creates on
|
|
30
|
+
* the first successful prepare. open()'s first PRAGMA is always one, so every connection
|
|
31
|
+
* this package hands out already has it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function releaseStatement(connection: Gda.Connection, stmt: Gda.Statement): void;
|
|
34
|
+
/**
|
|
35
|
+
* Give back every cache entry retained on `connection`.
|
|
36
|
+
*
|
|
37
|
+
* A `StatementSync` asks for retention and is then collected without telling anyone, so
|
|
38
|
+
* the connection's own lifecycle is the only seam that can give its entries back — and it
|
|
39
|
+
* must: a parked connection is handed to the NEXT consumer, who can recreate a table a
|
|
40
|
+
* retained statement was compiled against. A never-closed `DatabaseSync` pins its
|
|
41
|
+
* connection plus at most `MAX_RETAINED` compiled statements — bounded, by design.
|
|
42
|
+
*/
|
|
43
|
+
export declare function releaseRetained(connection: Gda.Connection): void;
|
|
44
|
+
export interface ExecuteOptions {
|
|
45
|
+
/** How to read the result columns. Pass only when `read` reads rows. */
|
|
46
|
+
columns?: ColumnTypes;
|
|
47
|
+
/**
|
|
48
|
+
* Keep the connection's prepared-statement cache entry when the execution leaves the
|
|
49
|
+
* statement drained, so the next execution of the SAME `Gda.Statement` reuses the
|
|
50
|
+
* compiled `sqlite3_stmt` (see `retained`). Only a caller that HOLDS its statement for
|
|
51
|
+
* reuse asks for this; a one-shot statement would just occupy the bound.
|
|
52
|
+
*/
|
|
53
|
+
retain?: boolean;
|
|
54
|
+
}
|
|
20
55
|
/**
|
|
21
56
|
* Execute `stmt`, hand its result to `read`, and leave NOTHING behind on the connection.
|
|
22
57
|
*
|
|
@@ -41,12 +76,13 @@ export declare function integerColumns(count: number): ColumnTypes;
|
|
|
41
76
|
* connection cached as above, where no caller can reach it to release it.
|
|
42
77
|
*
|
|
43
78
|
* So: non-SELECTs go through `batch_execute()`, which passes `last_insert_row` as NULL;
|
|
44
|
-
* the connection's cache entry is deleted after every execution
|
|
45
|
-
*
|
|
46
|
-
*
|
|
79
|
+
* the connection's cache entry is deleted after every execution unless the caller asks to
|
|
80
|
+
* keep it for a statement it will run again (`ExecuteOptions.retain`, bounded by
|
|
81
|
+
* `retained`); and the data model lets go of its prepared statement as soon as `read`
|
|
82
|
+
* returns. Every object an execution creates is then released before this function does.
|
|
47
83
|
*
|
|
48
84
|
* Do NOT use `GObject.Object.run_dispose()` on the model instead: `GdaSqliteRecordset`'s
|
|
49
85
|
* dispose clears a GWeakRef without re-initialising it, so the second dispose the
|
|
50
86
|
* finalizer runs dereferences a cleared weak ref and the process dies with SIGSEGV.
|
|
51
87
|
*/
|
|
52
|
-
export declare function executeStatement<T>(connection: Gda.Connection, stmt: Gda.Statement, params: Gda.Set | null, read: (model: Gda.DataModel | null, textColumns: boolean[]) => T,
|
|
88
|
+
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,13 +1,46 @@
|
|
|
1
1
|
import type Gda from '@girs/gda-6.0';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
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.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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).
|
|
8
41
|
*
|
|
9
|
-
* A missing holder is a bug in this package
|
|
10
|
-
* same `convertParameterSyntax` pass
|
|
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
|
|
11
44
|
* silently writing NULL.
|
|
12
45
|
*/
|
|
13
|
-
export declare function
|
|
46
|
+
export declare function bindHolders(paramSet: Gda.Set | null, bindings: Map<string, HolderBinding>): void;
|
|
@@ -8,9 +8,10 @@ export interface ParamInfo {
|
|
|
8
8
|
* Decides what a placeholder becomes in the SQL handed to libgda.
|
|
9
9
|
*
|
|
10
10
|
* `StatementSync` substitutes this per execution, because the choice depends on the value:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* that
|
|
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.
|
|
14
15
|
*/
|
|
15
16
|
export type PlaceholderRenderer = (param: ParamInfo) => string;
|
|
16
17
|
export declare const asStringHolder: PlaceholderRenderer;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/sqlite",
|
|
3
|
-
"version": "0.64.
|
|
3
|
+
"version": "0.64.4",
|
|
4
4
|
"description": "Node.js sqlite module for Gjs using libgda",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"libgda"
|
|
41
41
|
],
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@gjsify/cli": "0.64.
|
|
43
|
+
"@gjsify/cli": "^0.64.4",
|
|
44
44
|
"@gjsify/node-gi": "file:../../../packages/node-gi/node-gi",
|
|
45
|
-
"@gjsify/unit": "0.64.
|
|
45
|
+
"@gjsify/unit": "^0.64.4",
|
|
46
46
|
"@types/node": "^25.9.2",
|
|
47
47
|
"typescript": "^6.0.3"
|
|
48
48
|
},
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@girs/gio-2.0": "5.4.0",
|
|
52
52
|
"@girs/glib-2.0": "5.4.0",
|
|
53
53
|
"@girs/gobject-2.0": "5.4.0",
|
|
54
|
-
"@gjsify/utils": "0.64.
|
|
54
|
+
"@gjsify/utils": "^0.64.4"
|
|
55
55
|
},
|
|
56
56
|
"gjsify": {
|
|
57
57
|
"runtimes": {
|
|
@@ -71,6 +71,5 @@
|
|
|
71
71
|
"bugs": {
|
|
72
72
|
"url": "https://github.com/gjsify/gjsify/issues"
|
|
73
73
|
},
|
|
74
|
-
"homepage": "https://github.com/gjsify/gjsify/tree/main/packages/node/sqlite#readme"
|
|
75
|
-
"gitHead": "0f5ca82aab25bf9df8d1e790d28483b1f90fe3a9"
|
|
74
|
+
"homepage": "https://github.com/gjsify/gjsify/tree/main/packages/node/sqlite#readme"
|
|
76
75
|
}
|