expo-sqlite 12.2.1 → 13.0.0

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.
@@ -9,42 +9,28 @@ export class Statement {
9
9
  this.nativeStatement = nativeStatement;
10
10
  }
11
11
  async runAsync(...params) {
12
- const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);
13
- if (shouldPassAsObject) {
14
- return await this.nativeStatement.objectRunAsync(this.nativeDatabase, bindParams);
15
- }
16
- else {
17
- return await this.nativeStatement.arrayRunAsync(this.nativeDatabase, bindParams);
18
- }
12
+ return await this.nativeStatement.runAsync(this.nativeDatabase, ...normalizeParams(...params));
19
13
  }
20
14
  async *eachAsync(...params) {
21
- const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);
22
- const func = shouldPassAsObject
23
- ? this.nativeStatement.objectGetAsync.bind(this.nativeStatement)
24
- : this.nativeStatement.arrayGetAsync.bind(this.nativeStatement);
15
+ const paramTuple = normalizeParams(...params);
16
+ const func = this.nativeStatement.getAsync.bind(this.nativeStatement);
25
17
  const columnNames = await this.getColumnNamesAsync();
26
18
  let result = null;
27
19
  do {
28
- result = await func(this.nativeDatabase, bindParams);
20
+ result = await func(this.nativeDatabase, ...paramTuple);
29
21
  if (result != null) {
30
22
  yield composeRow(columnNames, result);
31
23
  }
32
24
  } while (result != null);
33
25
  }
34
26
  async getAsync(...params) {
35
- const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);
36
27
  const columnNames = await this.getColumnNamesAsync();
37
- const columnValues = shouldPassAsObject
38
- ? await this.nativeStatement.objectGetAsync(this.nativeDatabase, bindParams)
39
- : await this.nativeStatement.arrayGetAsync(this.nativeDatabase, bindParams);
28
+ const columnValues = await this.nativeStatement.getAsync(this.nativeDatabase, ...normalizeParams(...params));
40
29
  return columnValues != null ? composeRow(columnNames, columnValues) : null;
41
30
  }
42
31
  async allAsync(...params) {
43
- const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);
44
32
  const columnNames = await this.getColumnNamesAsync();
45
- const columnValuesList = shouldPassAsObject
46
- ? await this.nativeStatement.objectGetAllAsync(this.nativeDatabase, bindParams)
47
- : await this.nativeStatement.arrayGetAllAsync(this.nativeDatabase, bindParams);
33
+ const columnValuesList = await this.nativeStatement.getAllAsync(this.nativeDatabase, ...normalizeParams(...params));
48
34
  return composeRows(columnNames, columnValuesList);
49
35
  }
50
36
  /**
@@ -67,42 +53,28 @@ export class Statement {
67
53
  await this.nativeStatement.finalizeAsync(this.nativeDatabase);
68
54
  }
69
55
  runSync(...params) {
70
- const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);
71
- if (shouldPassAsObject) {
72
- return this.nativeStatement.objectRunSync(this.nativeDatabase, bindParams);
73
- }
74
- else {
75
- return this.nativeStatement.arrayRunSync(this.nativeDatabase, bindParams);
76
- }
56
+ return this.nativeStatement.runSync(this.nativeDatabase, ...normalizeParams(...params));
77
57
  }
78
58
  *eachSync(...params) {
79
- const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);
80
- const func = shouldPassAsObject
81
- ? this.nativeStatement.objectGetSync.bind(this.nativeStatement)
82
- : this.nativeStatement.arrayGetSync.bind(this.nativeStatement);
59
+ const paramTuple = normalizeParams(...params);
60
+ const func = this.nativeStatement.getSync.bind(this.nativeStatement);
83
61
  const columnNames = this.getColumnNamesSync();
84
62
  let result = null;
85
63
  do {
86
- result = func(this.nativeDatabase, bindParams);
64
+ result = func(this.nativeDatabase, ...paramTuple);
87
65
  if (result != null) {
88
66
  yield composeRow(columnNames, result);
89
67
  }
90
68
  } while (result != null);
91
69
  }
92
70
  getSync(...params) {
93
- const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);
94
71
  const columnNames = this.getColumnNamesSync();
95
- const columnValues = shouldPassAsObject
96
- ? this.nativeStatement.objectGetSync(this.nativeDatabase, bindParams)
97
- : this.nativeStatement.arrayGetSync(this.nativeDatabase, bindParams);
72
+ const columnValues = this.nativeStatement.getSync(this.nativeDatabase, ...normalizeParams(...params));
98
73
  return columnValues != null ? composeRow(columnNames, columnValues) : null;
99
74
  }
100
75
  allSync(...params) {
101
- const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);
102
76
  const columnNames = this.getColumnNamesSync();
103
- const columnValuesList = shouldPassAsObject
104
- ? this.nativeStatement.objectGetAllSync(this.nativeDatabase, bindParams)
105
- : this.nativeStatement.arrayGetAllSync(this.nativeDatabase, bindParams);
77
+ const columnValuesList = this.nativeStatement.getAllSync(this.nativeDatabase, ...normalizeParams(...params));
106
78
  return composeRows(columnNames, columnValuesList);
107
79
  }
108
80
  /**
@@ -128,7 +100,8 @@ export class Statement {
128
100
  }
129
101
  }
130
102
  /**
131
- * Normalize the bind params to an array or object.
103
+ * Normalize the bind params to data structure that can be passed to native module.
104
+ * The data structure is a tuple of [primitiveParams, blobParams, shouldPassAsArray].
132
105
  * @hidden
133
106
  */
134
107
  export function normalizeParams(...params) {
@@ -136,14 +109,30 @@ export function normalizeParams(...params) {
136
109
  if (bindParams == null) {
137
110
  bindParams = [];
138
111
  }
139
- if (typeof bindParams !== 'object') {
112
+ if (typeof bindParams !== 'object' ||
113
+ bindParams instanceof ArrayBuffer ||
114
+ ArrayBuffer.isView(bindParams)) {
140
115
  bindParams = [bindParams];
141
116
  }
142
- const shouldPassAsObject = !Array.isArray(bindParams);
143
- return {
144
- params: bindParams,
145
- shouldPassAsObject,
146
- };
117
+ const shouldPassAsArray = Array.isArray(bindParams);
118
+ if (Array.isArray(bindParams)) {
119
+ bindParams = bindParams.reduce((acc, value, index) => {
120
+ acc[index] = value;
121
+ return acc;
122
+ }, {});
123
+ }
124
+ const primitiveParams = {};
125
+ const blobParams = {};
126
+ for (const key in bindParams) {
127
+ const value = bindParams[key];
128
+ if (value instanceof Uint8Array) {
129
+ blobParams[key] = value;
130
+ }
131
+ else {
132
+ primitiveParams[key] = value;
133
+ }
134
+ }
135
+ return [primitiveParams, blobParams, shouldPassAsArray];
147
136
  }
148
137
  /**
149
138
  * Compose `columnNames` and `columnValues` to an row object.
@@ -1 +1 @@
1
- {"version":3,"file":"Statement.js","sourceRoot":"","sources":["../../src/next/Statement.ts"],"names":[],"mappings":"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","sourcesContent":["import { NativeDatabase } from './NativeDatabase';\nimport {\n BindParams,\n BindValue,\n NativeStatement,\n RunResult,\n VariadicBindParams,\n type ColumnNames,\n type ColumnValues,\n} from './NativeStatement';\n\nexport { BindParams, BindValue, RunResult, VariadicBindParams };\n\n/**\n * A prepared statement returned by [`Database.prepareAsync()`](#prepareasyncsource) or [`Database.prepareSync()`](#preparesyncsource) that can be binded with parameters and executed.\n */\nexport class Statement {\n constructor(\n private readonly nativeDatabase: NativeDatabase,\n private readonly nativeStatement: NativeStatement\n ) {}\n\n //#region Asynchronous API\n\n /**\n * Run the prepared statement and return the result.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public runAsync(params: BindParams): Promise<RunResult>;\n /**\n * @hidden\n */\n public runAsync(...params: VariadicBindParams): Promise<RunResult>;\n public async runAsync(...params: unknown[]): Promise<RunResult> {\n const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);\n if (shouldPassAsObject) {\n return await this.nativeStatement.objectRunAsync(this.nativeDatabase, bindParams);\n } else {\n return await this.nativeStatement.arrayRunAsync(this.nativeDatabase, bindParams);\n }\n }\n\n /**\n * Iterate the prepared statement and return results as an async iterable.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n * @example\n * ```ts\n * const statement = await db.prepareAsync('SELECT * FROM test');\n * for await (const row of statement.eachAsync<any>()) {\n * console.log(row);\n * }\n * await statement.finalizeAsync();\n * ```\n */\n public eachAsync<T>(params: BindParams): AsyncIterableIterator<T>;\n /**\n * @hidden\n */\n public eachAsync<T>(...params: VariadicBindParams): AsyncIterableIterator<T>;\n public async *eachAsync<T>(...params: unknown[]): AsyncIterableIterator<T> {\n const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);\n const func = shouldPassAsObject\n ? this.nativeStatement.objectGetAsync.bind(this.nativeStatement)\n : this.nativeStatement.arrayGetAsync.bind(this.nativeStatement);\n\n const columnNames = await this.getColumnNamesAsync();\n let result = null;\n do {\n result = await func(this.nativeDatabase, bindParams);\n if (result != null) {\n yield composeRow<T>(columnNames, result);\n }\n } while (result != null);\n }\n\n /**\n * Get one row from the prepared statement.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public getAsync<T>(params: BindParams): Promise<T | null>;\n /**\n * @hidden\n */\n public getAsync<T>(...params: VariadicBindParams): Promise<T | null>;\n public async getAsync<T>(...params: unknown[]): Promise<T | null> {\n const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);\n const columnNames = await this.getColumnNamesAsync();\n const columnValues = shouldPassAsObject\n ? await this.nativeStatement.objectGetAsync(this.nativeDatabase, bindParams)\n : await this.nativeStatement.arrayGetAsync(this.nativeDatabase, bindParams);\n return columnValues != null ? composeRow<T>(columnNames, columnValues) : null;\n }\n\n /**\n * Get all rows from the prepared statement.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public allAsync<T>(params: BindParams): Promise<T[]>;\n /**\n * @hidden\n */\n public allAsync<T>(...params: VariadicBindParams): Promise<T[]>;\n public async allAsync<T>(...params: unknown[]): Promise<T[]> {\n const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);\n const columnNames = await this.getColumnNamesAsync();\n const columnValuesList = shouldPassAsObject\n ? await this.nativeStatement.objectGetAllAsync(this.nativeDatabase, bindParams)\n : await this.nativeStatement.arrayGetAllAsync(this.nativeDatabase, bindParams);\n return composeRows<T>(columnNames, columnValuesList);\n }\n\n /**\n * Get the column names of the prepared statement.\n */\n public getColumnNamesAsync(): Promise<string[]> {\n return this.nativeStatement.getColumnNamesAsync();\n }\n\n /**\n * Reset the prepared statement cursor.\n */\n public async resetAsync(): Promise<void> {\n await this.nativeStatement.resetAsync(this.nativeDatabase);\n }\n\n /**\n * Finalize the prepared statement.\n * > **Note:** Remember to finalize the prepared statement whenever you call `prepareAsync()` to avoid resource leaks.\n */\n public async finalizeAsync(): Promise<void> {\n await this.nativeStatement.finalizeAsync(this.nativeDatabase);\n }\n\n //#endregion\n\n //#region Synchronous API\n\n /**\n * Run the prepared statement and return the result.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public runSync(params: BindParams): RunResult;\n /**\n * @hidden\n */\n public runSync(...params: VariadicBindParams): RunResult;\n public runSync(...params: unknown[]): RunResult {\n const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);\n if (shouldPassAsObject) {\n return this.nativeStatement.objectRunSync(this.nativeDatabase, bindParams);\n } else {\n return this.nativeStatement.arrayRunSync(this.nativeDatabase, bindParams);\n }\n }\n\n /**\n * Iterate the prepared statement and return results as an iterable.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public eachSync<T>(params: BindParams): IterableIterator<T>;\n /**\n * @hidden\n */\n public eachSync<T>(...params: VariadicBindParams): IterableIterator<T>;\n public *eachSync<T>(...params: unknown[]): IterableIterator<T> {\n const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);\n const func = shouldPassAsObject\n ? this.nativeStatement.objectGetSync.bind(this.nativeStatement)\n : this.nativeStatement.arrayGetSync.bind(this.nativeStatement);\n\n const columnNames = this.getColumnNamesSync();\n let result = null;\n do {\n result = func(this.nativeDatabase, bindParams);\n if (result != null) {\n yield composeRow<T>(columnNames, result);\n }\n } while (result != null);\n }\n\n /**\n * Get one row from the prepared statement.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public getSync<T>(params: BindParams): T | null;\n /**\n * @hidden\n */\n public getSync<T>(...params: VariadicBindParams): T | null;\n public getSync<T>(...params: unknown[]): T | null {\n const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);\n const columnNames = this.getColumnNamesSync();\n const columnValues = shouldPassAsObject\n ? this.nativeStatement.objectGetSync(this.nativeDatabase, bindParams)\n : this.nativeStatement.arrayGetSync(this.nativeDatabase, bindParams);\n return columnValues != null ? composeRow<T>(columnNames, columnValues) : null;\n }\n\n /**\n * Get all rows from the prepared statement.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public allSync<T>(params: BindParams): T[];\n /**\n * @hidden\n */\n public allSync<T>(...params: VariadicBindParams): T[];\n public allSync<T>(...params: unknown[]): T[] {\n const { params: bindParams, shouldPassAsObject } = normalizeParams(...params);\n const columnNames = this.getColumnNamesSync();\n const columnValuesList = shouldPassAsObject\n ? this.nativeStatement.objectGetAllSync(this.nativeDatabase, bindParams)\n : this.nativeStatement.arrayGetAllSync(this.nativeDatabase, bindParams);\n return composeRows<T>(columnNames, columnValuesList);\n }\n\n /**\n * Get the column names of the prepared statement.\n */\n public getColumnNamesSync(): string[] {\n return this.nativeStatement.getColumnNamesSync();\n }\n\n /**\n * Reset the prepared statement cursor.\n */\n public resetSync(): void {\n this.nativeStatement.resetSync(this.nativeDatabase);\n }\n\n /**\n * Finalize the prepared statement.\n *\n * > **Note:** Remember to finalize the prepared statement whenever you call `prepareSync()` to avoid resource leaks.\n *\n */\n public finalizeSync(): void {\n this.nativeStatement.finalizeSync(this.nativeDatabase);\n }\n\n //#endregion\n}\n\n/**\n * Normalize the bind params to an array or object.\n * @hidden\n */\nexport function normalizeParams(...params: any[]): {\n params: BindParams;\n shouldPassAsObject: boolean;\n} {\n let bindParams = params.length > 1 ? params : (params[0] as BindParams);\n if (bindParams == null) {\n bindParams = [];\n }\n if (typeof bindParams !== 'object') {\n bindParams = [bindParams];\n }\n const shouldPassAsObject = !Array.isArray(bindParams);\n return {\n params: bindParams,\n shouldPassAsObject,\n };\n}\n\n/**\n * Compose `columnNames` and `columnValues` to an row object.\n * @hidden\n */\nexport function composeRow<T>(columnNames: ColumnNames, columnValues: ColumnValues): T {\n const row = {};\n if (columnNames.length !== columnValues.length) {\n throw new Error(\n `Column names and values count mismatch. Names: ${columnNames.length}, Values: ${columnValues.length}`\n );\n }\n for (let i = 0; i < columnNames.length; i++) {\n row[columnNames[i]] = columnValues[i];\n }\n return row as T;\n}\n\n/**\n * Compose `columnNames` and `columnValuesList` to an array of row objects.\n * @hidden\n */\nexport function composeRows<T>(columnNames: ColumnNames, columnValuesList: ColumnValues[]): T[] {\n if (columnValuesList.length === 0) {\n return [];\n }\n if (columnNames.length !== columnValuesList[0].length) {\n // We only check the first row because SQLite returns the same column count for all rows.\n throw new Error(\n `Column names and values count mismatch. Names: ${columnNames.length}, Values: ${columnValuesList[0].length}`\n );\n }\n const results: T[] = [];\n for (const columnValues of columnValuesList) {\n const row = {};\n for (let i = 0; i < columnNames.length; i++) {\n row[columnNames[i]] = columnValues[i];\n }\n results.push(row as T);\n }\n return results;\n}\n"]}
1
+ {"version":3,"file":"Statement.js","sourceRoot":"","sources":["../../src/next/Statement.ts"],"names":[],"mappings":"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","sourcesContent":["import { NativeDatabase } from './NativeDatabase';\nimport {\n BindBlobParams,\n BindParams,\n BindPrimitiveParams,\n BindValue,\n NativeStatement,\n RunResult,\n VariadicBindParams,\n type ColumnNames,\n type ColumnValues,\n} from './NativeStatement';\n\nexport { BindParams, BindValue, RunResult, VariadicBindParams };\n\n/**\n * A prepared statement returned by [`Database.prepareAsync()`](#prepareasyncsource) or [`Database.prepareSync()`](#preparesyncsource) that can be binded with parameters and executed.\n */\nexport class Statement {\n constructor(\n private readonly nativeDatabase: NativeDatabase,\n private readonly nativeStatement: NativeStatement\n ) {}\n\n //#region Asynchronous API\n\n /**\n * Run the prepared statement and return the result.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public runAsync(params: BindParams): Promise<RunResult>;\n /**\n * @hidden\n */\n public runAsync(...params: VariadicBindParams): Promise<RunResult>;\n public async runAsync(...params: unknown[]): Promise<RunResult> {\n return await this.nativeStatement.runAsync(this.nativeDatabase, ...normalizeParams(...params));\n }\n\n /**\n * Iterate the prepared statement and return results as an async iterable.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n * @example\n * ```ts\n * const statement = await db.prepareAsync('SELECT * FROM test');\n * for await (const row of statement.eachAsync<any>()) {\n * console.log(row);\n * }\n * await statement.finalizeAsync();\n * ```\n */\n public eachAsync<T>(params: BindParams): AsyncIterableIterator<T>;\n /**\n * @hidden\n */\n public eachAsync<T>(...params: VariadicBindParams): AsyncIterableIterator<T>;\n public async *eachAsync<T>(...params: unknown[]): AsyncIterableIterator<T> {\n const paramTuple = normalizeParams(...params);\n const func = this.nativeStatement.getAsync.bind(this.nativeStatement);\n\n const columnNames = await this.getColumnNamesAsync();\n let result = null;\n do {\n result = await func(this.nativeDatabase, ...paramTuple);\n if (result != null) {\n yield composeRow<T>(columnNames, result);\n }\n } while (result != null);\n }\n\n /**\n * Get one row from the prepared statement.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public getAsync<T>(params: BindParams): Promise<T | null>;\n /**\n * @hidden\n */\n public getAsync<T>(...params: VariadicBindParams): Promise<T | null>;\n public async getAsync<T>(...params: unknown[]): Promise<T | null> {\n const columnNames = await this.getColumnNamesAsync();\n const columnValues = await this.nativeStatement.getAsync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return columnValues != null ? composeRow<T>(columnNames, columnValues) : null;\n }\n\n /**\n * Get all rows from the prepared statement.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public allAsync<T>(params: BindParams): Promise<T[]>;\n /**\n * @hidden\n */\n public allAsync<T>(...params: VariadicBindParams): Promise<T[]>;\n public async allAsync<T>(...params: unknown[]): Promise<T[]> {\n const columnNames = await this.getColumnNamesAsync();\n const columnValuesList = await this.nativeStatement.getAllAsync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return composeRows<T>(columnNames, columnValuesList);\n }\n\n /**\n * Get the column names of the prepared statement.\n */\n public getColumnNamesAsync(): Promise<string[]> {\n return this.nativeStatement.getColumnNamesAsync();\n }\n\n /**\n * Reset the prepared statement cursor.\n */\n public async resetAsync(): Promise<void> {\n await this.nativeStatement.resetAsync(this.nativeDatabase);\n }\n\n /**\n * Finalize the prepared statement.\n * > **Note:** Remember to finalize the prepared statement whenever you call `prepareAsync()` to avoid resource leaks.\n */\n public async finalizeAsync(): Promise<void> {\n await this.nativeStatement.finalizeAsync(this.nativeDatabase);\n }\n\n //#endregion\n\n //#region Synchronous API\n\n /**\n * Run the prepared statement and return the result.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public runSync(params: BindParams): RunResult;\n /**\n * @hidden\n */\n public runSync(...params: VariadicBindParams): RunResult;\n public runSync(...params: unknown[]): RunResult {\n return this.nativeStatement.runSync(this.nativeDatabase, ...normalizeParams(...params));\n }\n\n /**\n * Iterate the prepared statement and return results as an iterable.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public eachSync<T>(params: BindParams): IterableIterator<T>;\n /**\n * @hidden\n */\n public eachSync<T>(...params: VariadicBindParams): IterableIterator<T>;\n public *eachSync<T>(...params: unknown[]): IterableIterator<T> {\n const paramTuple = normalizeParams(...params);\n const func = this.nativeStatement.getSync.bind(this.nativeStatement);\n\n const columnNames = this.getColumnNamesSync();\n let result = null;\n do {\n result = func(this.nativeDatabase, ...paramTuple);\n if (result != null) {\n yield composeRow<T>(columnNames, result);\n }\n } while (result != null);\n }\n\n /**\n * Get one row from the prepared statement.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public getSync<T>(params: BindParams): T | null;\n /**\n * @hidden\n */\n public getSync<T>(...params: VariadicBindParams): T | null;\n public getSync<T>(...params: unknown[]): T | null {\n const columnNames = this.getColumnNamesSync();\n const columnValues = this.nativeStatement.getSync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return columnValues != null ? composeRow<T>(columnNames, columnValues) : null;\n }\n\n /**\n * Get all rows from the prepared statement.\n * > **Note:** Running heavy tasks with this function can block the JavaScript thread and affect performance.\n * @param params The parameters to bind to the prepared statement. You can pass values in array, object, or variadic arguments. See [`BindValue`](#bindvalue) for more information about binding values.\n */\n public allSync<T>(params: BindParams): T[];\n /**\n * @hidden\n */\n public allSync<T>(...params: VariadicBindParams): T[];\n public allSync<T>(...params: unknown[]): T[] {\n const columnNames = this.getColumnNamesSync();\n const columnValuesList = this.nativeStatement.getAllSync(\n this.nativeDatabase,\n ...normalizeParams(...params)\n );\n return composeRows<T>(columnNames, columnValuesList);\n }\n\n /**\n * Get the column names of the prepared statement.\n */\n public getColumnNamesSync(): string[] {\n return this.nativeStatement.getColumnNamesSync();\n }\n\n /**\n * Reset the prepared statement cursor.\n */\n public resetSync(): void {\n this.nativeStatement.resetSync(this.nativeDatabase);\n }\n\n /**\n * Finalize the prepared statement.\n *\n * > **Note:** Remember to finalize the prepared statement whenever you call `prepareSync()` to avoid resource leaks.\n *\n */\n public finalizeSync(): void {\n this.nativeStatement.finalizeSync(this.nativeDatabase);\n }\n\n //#endregion\n}\n\n/**\n * Normalize the bind params to data structure that can be passed to native module.\n * The data structure is a tuple of [primitiveParams, blobParams, shouldPassAsArray].\n * @hidden\n */\nexport function normalizeParams(...params: any[]): [BindPrimitiveParams, BindBlobParams, boolean] {\n let bindParams = params.length > 1 ? params : (params[0] as BindParams);\n if (bindParams == null) {\n bindParams = [];\n }\n if (\n typeof bindParams !== 'object' ||\n bindParams instanceof ArrayBuffer ||\n ArrayBuffer.isView(bindParams)\n ) {\n bindParams = [bindParams];\n }\n const shouldPassAsArray = Array.isArray(bindParams);\n if (Array.isArray(bindParams)) {\n bindParams = bindParams.reduce<Record<string, BindValue>>((acc, value, index) => {\n acc[index] = value;\n return acc;\n }, {});\n }\n\n const primitiveParams: BindPrimitiveParams = {};\n const blobParams: BindBlobParams = {};\n for (const key in bindParams) {\n const value = bindParams[key];\n if (value instanceof Uint8Array) {\n blobParams[key] = value;\n } else {\n primitiveParams[key] = value;\n }\n }\n\n return [primitiveParams, blobParams, shouldPassAsArray];\n}\n\n/**\n * Compose `columnNames` and `columnValues` to an row object.\n * @hidden\n */\nexport function composeRow<T>(columnNames: ColumnNames, columnValues: ColumnValues): T {\n const row = {};\n if (columnNames.length !== columnValues.length) {\n throw new Error(\n `Column names and values count mismatch. Names: ${columnNames.length}, Values: ${columnValues.length}`\n );\n }\n for (let i = 0; i < columnNames.length; i++) {\n row[columnNames[i]] = columnValues[i];\n }\n return row as T;\n}\n\n/**\n * Compose `columnNames` and `columnValuesList` to an array of row objects.\n * @hidden\n */\nexport function composeRows<T>(columnNames: ColumnNames, columnValuesList: ColumnValues[]): T[] {\n if (columnValuesList.length === 0) {\n return [];\n }\n if (columnNames.length !== columnValuesList[0].length) {\n // We only check the first row because SQLite returns the same column count for all rows.\n throw new Error(\n `Column names and values count mismatch. Names: ${columnNames.length}, Values: ${columnValuesList[0].length}`\n );\n }\n const results: T[] = [];\n for (const columnValues of columnValuesList) {\n const row = {};\n for (let i = 0; i < columnNames.length; i++) {\n row[columnNames[i]] = columnValues[i];\n }\n results.push(row as T);\n }\n return results;\n}\n"]}
@@ -52,6 +52,18 @@ internal class InvalidArgumentsException: Exception {
52
52
  }
53
53
  }
54
54
 
55
+ internal class InvalidBindParameterException: Exception {
56
+ override var reason: String {
57
+ "Invalid bind parameter"
58
+ }
59
+ }
60
+
61
+ internal class AccessClosedResourceException: Exception {
62
+ override var reason: String {
63
+ "Access to closed resource"
64
+ }
65
+ }
66
+
55
67
  internal class SQLiteErrorException: GenericException<String> {
56
68
  override var code: String {
57
69
  "ERR_INTERNAL_SQLITE_ERROR"
@@ -5,6 +5,7 @@ import ExpoModulesCore
5
5
  final class NativeDatabase: SharedRef<OpaquePointer?>, Equatable, Hashable {
6
6
  let dbName: String
7
7
  let openOptions: OpenDatabaseOptions
8
+ var isClosed = false
8
9
 
9
10
  init(_ pointer: OpaquePointer?, dbName: String, openOptions: OpenDatabaseOptions) {
10
11
  self.dbName = dbName
@@ -4,6 +4,7 @@ import ExpoModulesCore
4
4
 
5
5
  final class NativeStatement: SharedObject, Equatable {
6
6
  var pointer: OpaquePointer?
7
+ var isFinalized = false
7
8
 
8
9
  // MARK: - Equatable
9
10
 
@@ -63,12 +63,11 @@ public final class SQLiteModule: Module {
63
63
  }
64
64
 
65
65
  private func pathForDatabaseName(name: String) -> URL? {
66
- guard let fileSystem = appContext?.fileSystem else {
66
+ guard let path = appContext?.config.documentDirectory?.path else {
67
67
  return nil
68
68
  }
69
-
70
- let directory = URL(string: fileSystem.documentDirectory)?.appendingPathComponent("SQLite")
71
- fileSystem.ensureDirExists(withPath: directory?.absoluteString)
69
+ let directory = URL(string: path)?.appendingPathComponent("SQLite")
70
+ FileSystemUtilities.ensureDirExists(at: directory)
72
71
 
73
72
  return directory?.appendingPathComponent(name)
74
73
  }
@@ -6,6 +6,7 @@ import sqlite3
6
6
  private typealias ColumnNames = [String]
7
7
  private typealias ColumnValues = [Any]
8
8
  private let SQLITE_TRANSIENT = unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite3_destructor_type.self)
9
+ private let MEMORY_DB_NAME = ":memory:"
9
10
 
10
11
  public final class SQLiteModuleNext: Module {
11
12
  // Store unmanaged (SQLiteModuleNext, Database) pairs for sqlite callbacks,
@@ -68,16 +69,18 @@ public final class SQLiteModuleNext: Module {
68
69
  }
69
70
 
70
71
  AsyncFunction("initAsync") { (database: NativeDatabase) in
71
- initDb(database: database)
72
+ try initDb(database: database)
72
73
  }
73
74
  Function("initSync") { (database: NativeDatabase) in
74
- initDb(database: database)
75
+ try initDb(database: database)
75
76
  }
76
77
 
77
78
  AsyncFunction("isInTransactionAsync") { (database: NativeDatabase) -> Bool in
79
+ try maybeThrowForClosedDatabase(database)
78
80
  return sqlite3_get_autocommit(database.pointer) == 0
79
81
  }
80
82
  Function("isInTransactionSync") { (database: NativeDatabase) -> Bool in
83
+ try maybeThrowForClosedDatabase(database)
81
84
  return sqlite3_get_autocommit(database.pointer) == 0
82
85
  }
83
86
 
@@ -111,53 +114,36 @@ public final class SQLiteModuleNext: Module {
111
114
  return NativeStatement()
112
115
  }
113
116
 
114
- AsyncFunction("arrayRunAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) -> [String: Int] in
115
- return try arrayRun(statement: statement, database: database, bindParams: bindParams)
116
- }
117
- Function("arrayRunSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) -> [String: Int] in
118
- return try arrayRun(statement: statement, database: database, bindParams: bindParams)
119
- }
117
+ // swiftlint:disable line_length
120
118
 
121
- AsyncFunction("objectRunAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) -> [String: Int] in
122
- return try objectRun(statement: statement, database: database, bindParams: bindParams)
119
+ AsyncFunction("runAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) -> [String: Any] in
120
+ return try run(statement: statement, database: database, bindParams: bindParams, bindBlobParams: bindBlobParams, shouldPassAsArray: shouldPassAsArray)
123
121
  }
124
- Function("objectRunSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) -> [String: Int] in
125
- return try objectRun(statement: statement, database: database, bindParams: bindParams)
122
+ Function("runSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) -> [String: Int] in
123
+ return try run(statement: statement, database: database, bindParams: bindParams, bindBlobParams: bindBlobParams, shouldPassAsArray: shouldPassAsArray)
126
124
  }
127
125
 
128
- AsyncFunction("arrayGetAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) -> ColumnValues? in
129
- return try arrayGet(statement: statement, database: database, bindParams: bindParams)
126
+ AsyncFunction("getAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) -> ColumnValues? in
127
+ return try get(statement: statement, database: database, bindParams: bindParams, bindBlobParams: bindBlobParams, shouldPassAsArray: shouldPassAsArray)
130
128
  }
131
- Function("arrayGetSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) -> ColumnValues? in
132
- return try arrayGet(statement: statement, database: database, bindParams: bindParams)
129
+ Function("getSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) -> ColumnValues? in
130
+ return try get(statement: statement, database: database, bindParams: bindParams, bindBlobParams: bindBlobParams, shouldPassAsArray: shouldPassAsArray)
133
131
  }
134
132
 
135
- AsyncFunction("objectGetAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) -> ColumnValues? in
136
- return try objectGet(statement: statement, database: database, bindParams: bindParams)
133
+ AsyncFunction("getAllAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) -> [ColumnValues] in
134
+ return try getAll(statement: statement, database: database, bindParams: bindParams, bindBlobParams: bindBlobParams, shouldPassAsArray: shouldPassAsArray)
137
135
  }
138
- Function("objectGetSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) -> ColumnValues? in
139
- return try objectGet(statement: statement, database: database, bindParams: bindParams)
136
+ Function("getAllSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) -> [ColumnValues] in
137
+ return try getAll(statement: statement, database: database, bindParams: bindParams, bindBlobParams: bindBlobParams, shouldPassAsArray: shouldPassAsArray)
140
138
  }
141
139
 
142
- AsyncFunction("arrayGetAllAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) -> [ColumnValues] in
143
- return try arrayGetAll(statement: statement, database: database, bindParams: bindParams)
144
- }
145
- Function("arrayGetAllSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) -> [ColumnValues] in
146
- return try arrayGetAll(statement: statement, database: database, bindParams: bindParams)
147
- }
148
-
149
- AsyncFunction("objectGetAllAsync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) -> [ColumnValues] in
150
- return try objectGetAll(statement: statement, database: database, bindParams: bindParams)
151
- }
152
- Function("objectGetAllSync") { (statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) -> [ColumnValues] in
153
- return try objectGetAll(statement: statement, database: database, bindParams: bindParams)
154
- }
140
+ // swiftlint:enable line_length
155
141
 
156
142
  AsyncFunction("getColumnNamesAsync") { (statement: NativeStatement) -> ColumnNames in
157
- return getColumnNames(statement: statement)
143
+ return try getColumnNames(statement: statement)
158
144
  }
159
145
  Function("getColumnNamesSync") { (statement: NativeStatement) -> ColumnNames in
160
- return getColumnNames(statement: statement)
146
+ return try getColumnNames(statement: statement)
161
147
  }
162
148
 
163
149
  AsyncFunction("resetAsync") { (statement: NativeStatement, database: NativeDatabase) in
@@ -177,6 +163,9 @@ public final class SQLiteModuleNext: Module {
177
163
  }
178
164
 
179
165
  private func pathForDatabaseName(name: String) -> URL? {
166
+ if name == MEMORY_DB_NAME {
167
+ return URL(string: name)
168
+ }
180
169
  guard let fileSystem = appContext?.fileSystem else {
181
170
  return nil
182
171
  }
@@ -187,7 +176,8 @@ public final class SQLiteModuleNext: Module {
187
176
  return directory?.appendingPathComponent(name)
188
177
  }
189
178
 
190
- private func initDb(database: NativeDatabase) {
179
+ private func initDb(database: NativeDatabase) throws {
180
+ try maybeThrowForClosedDatabase(database)
191
181
  if database.openOptions.enableCRSQLite {
192
182
  crsqlite_init_from_swift(database.pointer)
193
183
  }
@@ -197,6 +187,7 @@ public final class SQLiteModuleNext: Module {
197
187
  }
198
188
 
199
189
  private func exec(database: NativeDatabase, source: String) throws {
190
+ try maybeThrowForClosedDatabase(database)
200
191
  var error: UnsafeMutablePointer<CChar>?
201
192
  let ret = sqlite3_exec(database.pointer, source, nil, nil, &error)
202
193
  if ret != SQLITE_OK, let error = error {
@@ -207,33 +198,32 @@ public final class SQLiteModuleNext: Module {
207
198
  }
208
199
 
209
200
  private func prepareStatement(database: NativeDatabase, statement: NativeStatement, source: String) throws {
201
+ try maybeThrowForClosedDatabase(database)
202
+ try maybeThrowForFinalizedStatement(statement)
210
203
  if sqlite3_prepare_v2(database.pointer, source, Int32(source.count), &statement.pointer, nil) != SQLITE_OK {
211
204
  throw SQLiteErrorException(convertSqlLiteErrorToString(database))
212
205
  }
213
206
  maybeAddCachedStatement(database: database, statement: statement)
214
207
  }
215
208
 
216
- private func arrayRun(statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) throws -> [String: Int] {
217
- for (index, param) in bindParams.enumerated() {
218
- try bindStatementParam(statement: statement, with: param, at: Int32(index + 1))
219
- }
220
- let ret = sqlite3_step(statement.pointer)
221
- if ret != SQLITE_ROW && ret != SQLITE_DONE {
222
- throw SQLiteErrorException(convertSqlLiteErrorToString(database))
223
- }
224
- return [
225
- "lastInsertRowid": Int(sqlite3_last_insert_rowid(database.pointer)),
226
- "changes": Int(sqlite3_changes(database.pointer))
227
- ]
228
- }
209
+ // swiftlint:disable line_length
229
210
 
230
- private func objectRun(statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) throws -> [String: Int] {
231
- for (name, param) in bindParams {
232
- let index = sqlite3_bind_parameter_index(statement.pointer, name.cString(using: .utf8))
211
+ private func run(statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) throws -> [String: Int] {
212
+ try maybeThrowForClosedDatabase(database)
213
+ try maybeThrowForFinalizedStatement(statement)
214
+ for (key, param) in bindParams {
215
+ let index = try getBindParamIndex(statement: statement, key: key, shouldPassAsArray: shouldPassAsArray)
216
+ if index > 0 {
217
+ try bindStatementParam(statement: statement, with: param, at: index)
218
+ }
219
+ }
220
+ for (key, param) in bindBlobParams {
221
+ let index = try getBindParamIndex(statement: statement, key: key, shouldPassAsArray: shouldPassAsArray)
233
222
  if index > 0 {
234
223
  try bindStatementParam(statement: statement, with: param, at: index)
235
224
  }
236
225
  }
226
+
237
227
  let ret = sqlite3_step(statement.pointer)
238
228
  if ret != SQLITE_ROW && ret != SQLITE_DONE {
239
229
  throw SQLiteErrorException(convertSqlLiteErrorToString(database))
@@ -244,27 +234,22 @@ public final class SQLiteModuleNext: Module {
244
234
  ]
245
235
  }
246
236
 
247
- private func arrayGet(statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) throws -> ColumnValues? {
248
- for (index, param) in bindParams.enumerated() {
249
- try bindStatementParam(statement: statement, with: param, at: Int32(index + 1))
250
- }
251
- let ret = sqlite3_step(statement.pointer)
252
- if ret == SQLITE_ROW {
253
- return try getColumnValues(statement: statement)
254
- }
255
- if ret != SQLITE_DONE {
256
- throw SQLiteErrorException(convertSqlLiteErrorToString(database))
237
+ private func get(statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) throws -> ColumnValues? {
238
+ try maybeThrowForClosedDatabase(database)
239
+ try maybeThrowForFinalizedStatement(statement)
240
+ for (key, param) in bindParams {
241
+ let index = try getBindParamIndex(statement: statement, key: key, shouldPassAsArray: shouldPassAsArray)
242
+ if index > 0 {
243
+ try bindStatementParam(statement: statement, with: param, at: index)
244
+ }
257
245
  }
258
- return nil
259
- }
260
-
261
- private func objectGet(statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) throws -> ColumnValues? {
262
- for (name, param) in bindParams {
263
- let index = sqlite3_bind_parameter_index(statement.pointer, name.cString(using: .utf8))
246
+ for (key, param) in bindBlobParams {
247
+ let index = try getBindParamIndex(statement: statement, key: key, shouldPassAsArray: shouldPassAsArray)
264
248
  if index > 0 {
265
249
  try bindStatementParam(statement: statement, with: param, at: index)
266
250
  }
267
251
  }
252
+
268
253
  let ret = sqlite3_step(statement.pointer)
269
254
  if ret == SQLITE_ROW {
270
255
  return try getColumnValues(statement: statement)
@@ -275,31 +260,22 @@ public final class SQLiteModuleNext: Module {
275
260
  return nil
276
261
  }
277
262
 
278
- private func arrayGetAll(statement: NativeStatement, database: NativeDatabase, bindParams: [Any]) throws -> [ColumnValues] {
279
- for (index, param) in bindParams.enumerated() {
280
- try bindStatementParam(statement: statement, with: param, at: Int32(index + 1))
281
- }
282
- var columnValuesList: [ColumnValues] = []
283
- while true {
284
- let ret = sqlite3_step(statement.pointer)
285
- if ret == SQLITE_ROW {
286
- columnValuesList.append(try getColumnValues(statement: statement))
287
- continue
288
- } else if ret == SQLITE_DONE {
289
- break
263
+ private func getAll(statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any], bindBlobParams: [String: Data], shouldPassAsArray: Bool) throws -> [ColumnValues] {
264
+ try maybeThrowForClosedDatabase(database)
265
+ try maybeThrowForFinalizedStatement(statement)
266
+ for (key, param) in bindParams {
267
+ let index = try getBindParamIndex(statement: statement, key: key, shouldPassAsArray: shouldPassAsArray)
268
+ if index > 0 {
269
+ try bindStatementParam(statement: statement, with: param, at: index)
290
270
  }
291
- throw SQLiteErrorException(convertSqlLiteErrorToString(database))
292
271
  }
293
- return columnValuesList
294
- }
295
-
296
- private func objectGetAll(statement: NativeStatement, database: NativeDatabase, bindParams: [String: Any]) throws -> [ColumnValues] {
297
- for (name, param) in bindParams {
298
- let index = sqlite3_bind_parameter_index(statement.pointer, name.cString(using: .utf8))
272
+ for (key, param) in bindBlobParams {
273
+ let index = try getBindParamIndex(statement: statement, key: key, shouldPassAsArray: shouldPassAsArray)
299
274
  if index > 0 {
300
275
  try bindStatementParam(statement: statement, with: param, at: index)
301
276
  }
302
277
  }
278
+
303
279
  var columnValuesList: [ColumnValues] = []
304
280
  while true {
305
281
  let ret = sqlite3_step(statement.pointer)
@@ -314,17 +290,24 @@ public final class SQLiteModuleNext: Module {
314
290
  return columnValuesList
315
291
  }
316
292
 
293
+ // swiftlint:enable line_length
294
+
317
295
  private func reset(statement: NativeStatement, database: NativeDatabase) throws {
296
+ try maybeThrowForClosedDatabase(database)
297
+ try maybeThrowForFinalizedStatement(statement)
318
298
  if sqlite3_reset(statement.pointer) != SQLITE_OK {
319
299
  throw SQLiteErrorException(convertSqlLiteErrorToString(database))
320
300
  }
321
301
  }
322
302
 
323
303
  private func finalize(statement: NativeStatement, database: NativeDatabase) throws {
304
+ try maybeThrowForClosedDatabase(database)
305
+ try maybeThrowForFinalizedStatement(statement)
324
306
  maybeRemoveCachedStatement(database: database, statement: statement)
325
307
  if sqlite3_finalize(statement.pointer) != SQLITE_OK {
326
308
  throw SQLiteErrorException(convertSqlLiteErrorToString(database))
327
309
  }
310
+ statement.isFinalized = true
328
311
  }
329
312
 
330
313
  private func convertSqlLiteErrorToString(_ db: NativeDatabase) -> String {
@@ -334,6 +317,7 @@ public final class SQLiteModuleNext: Module {
334
317
  }
335
318
 
336
319
  private func closeDatabase(_ db: NativeDatabase) throws {
320
+ try maybeThrowForClosedDatabase(db)
337
321
  for removedStatement in maybeRemoveAllCachedStatements(database: db) {
338
322
  sqlite3_finalize(removedStatement.pointer)
339
323
  }
@@ -342,6 +326,7 @@ public final class SQLiteModuleNext: Module {
342
326
  sqlite3_exec(db.pointer, "SELECT crsql_finalize()", nil, nil, nil)
343
327
  }
344
328
  let ret = sqlite3_close(db.pointer)
329
+ db.isClosed = true
345
330
 
346
331
  if let index = contextPairs.firstIndex(where: {
347
332
  guard let pair = $0.takeUnretainedValue() as? (SQLiteModuleNext, NativeDatabase) else {
@@ -366,6 +351,9 @@ public final class SQLiteModuleNext: Module {
366
351
  throw DeleteDatabaseException(dbName)
367
352
  }
368
353
 
354
+ if dbName == MEMORY_DB_NAME {
355
+ return
356
+ }
369
357
  guard let path = pathForDatabaseName(name: dbName) else {
370
358
  throw Exceptions.FileSystemModuleNotFound()
371
359
  }
@@ -407,7 +395,8 @@ public final class SQLiteModuleNext: Module {
407
395
  contextPair.toOpaque())
408
396
  }
409
397
 
410
- private func getColumnNames(statement: NativeStatement) -> ColumnNames {
398
+ private func getColumnNames(statement: NativeStatement) throws -> ColumnNames {
399
+ try maybeThrowForFinalizedStatement(statement)
411
400
  let columnCount = Int(sqlite3_column_count(statement.pointer))
412
401
  var columnNames: ColumnNames = Array(repeating: "", count: columnCount)
413
402
  for i in 0..<columnCount {
@@ -417,6 +406,7 @@ public final class SQLiteModuleNext: Module {
417
406
  }
418
407
 
419
408
  private func getColumnValues(statement: NativeStatement) throws -> ColumnValues {
409
+ try maybeThrowForFinalizedStatement(statement)
420
410
  let columnCount = Int(sqlite3_column_count(statement.pointer))
421
411
  var columnValues: ColumnValues = Array(repeating: 0, count: columnCount)
422
412
  for i in 0..<columnCount {
@@ -465,7 +455,7 @@ public final class SQLiteModuleNext: Module {
465
455
  case let param as Double:
466
456
  sqlite3_bind_double(instance, index, param)
467
457
  case let param as String:
468
- sqlite3_bind_text(instance, index, param, Int32(param.count), SQLITE_TRANSIENT)
458
+ sqlite3_bind_text(instance, index, param, -1, SQLITE_TRANSIENT)
469
459
  case let param as Data:
470
460
  _ = param.withUnsafeBytes {
471
461
  sqlite3_bind_blob(instance, index, $0.baseAddress, Int32(param.count), SQLITE_TRANSIENT)
@@ -477,6 +467,32 @@ public final class SQLiteModuleNext: Module {
477
467
  }
478
468
  }
479
469
 
470
+ private func maybeThrowForClosedDatabase(_ database: NativeDatabase) throws {
471
+ if database.isClosed {
472
+ throw AccessClosedResourceException()
473
+ }
474
+ }
475
+
476
+ private func maybeThrowForFinalizedStatement(_ statement: NativeStatement) throws {
477
+ if statement.isFinalized {
478
+ throw AccessClosedResourceException()
479
+ }
480
+ }
481
+
482
+ @inline(__always)
483
+ private func getBindParamIndex(statement: NativeStatement, key: String, shouldPassAsArray: Bool) throws -> Int32 {
484
+ let index: Int32
485
+ if shouldPassAsArray {
486
+ guard let intKey = Int32(key) else {
487
+ throw InvalidBindParameterException()
488
+ }
489
+ index = intKey + 1
490
+ } else {
491
+ index = sqlite3_bind_parameter_index(statement.pointer, key.cString(using: .utf8))
492
+ }
493
+ return index
494
+ }
495
+
480
496
  // MARK: - cachedDatabases managements
481
497
 
482
498
  private func addCachedDatabase(_ database: NativeDatabase) {