react-native-nitro-sqlite 9.8.1 → 10.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.
- package/RNNitroSQLite.podspec +7 -3
- package/android/CMakeLists.txt +3 -2
- package/android/build.gradle +2 -0
- package/android/sqlite-flags.gradle +47 -0
- package/cpp/NitroSQLiteDatabaseConnections.cpp +306 -0
- package/cpp/NitroSQLiteDatabaseConnections.hpp +86 -0
- package/cpp/{databaseMigration.cpp → NitroSQLiteDatabaseMigration.cpp} +2 -2
- package/cpp/{sqliteExecuteBatch.cpp → NitroSQLiteExecuteBatch.cpp} +4 -4
- package/cpp/{sqliteExecuteBatch.hpp → NitroSQLiteExecuteBatch.hpp} +3 -6
- package/cpp/{importSqlFile.cpp → NitroSQLiteImportSqlFile.cpp} +4 -4
- package/cpp/{importSqlFile.hpp → NitroSQLiteImportSqlFile.hpp} +3 -3
- package/cpp/{macros.hpp → NitroSQLiteMacros.hpp} +3 -3
- package/cpp/NitroSQLiteOperations.cpp +396 -0
- package/cpp/NitroSQLiteOperations.hpp +72 -0
- package/cpp/{types.hpp → NitroSQLiteTypes.hpp} +3 -6
- package/cpp/{utils.hpp → NitroSQLiteUtils.hpp} +2 -2
- package/cpp/hybridObjects/HybridNitroSQLite.cpp +108 -22
- package/cpp/hybridObjects/HybridNitroSQLite.hpp +49 -5
- package/cpp/hybridObjects/HybridNitroSQLitePreparedStatement.cpp +59 -0
- package/cpp/hybridObjects/HybridNitroSQLitePreparedStatement.hpp +33 -0
- package/cpp/hybridObjects/HybridNitroSQLiteQueryResult.hpp +6 -4
- package/ios/OnLoad.mm +38 -2
- package/lib/commonjs/DatabaseQueue.js +52 -16
- package/lib/commonjs/DatabaseQueue.js.map +1 -1
- package/lib/commonjs/NitroSQLiteError.js +6 -7
- package/lib/commonjs/NitroSQLiteError.js.map +1 -1
- package/lib/commonjs/OnLoad.js +1 -1
- package/lib/commonjs/index.js +8 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/operations/execute.js +19 -4
- package/lib/commonjs/operations/execute.js.map +1 -1
- package/lib/commonjs/operations/executeBatch.js +19 -6
- package/lib/commonjs/operations/executeBatch.js.map +1 -1
- package/lib/commonjs/operations/prepare.js +54 -0
- package/lib/commonjs/operations/prepare.js.map +1 -0
- package/lib/commonjs/operations/session.js +106 -30
- package/lib/commonjs/operations/session.js.map +1 -1
- package/lib/commonjs/operations/transaction.js +30 -5
- package/lib/commonjs/operations/transaction.js.map +1 -1
- package/lib/commonjs/specs/NitroSQLitePreparedStatement.nitro.js +6 -0
- package/lib/commonjs/specs/NitroSQLitePreparedStatement.nitro.js.map +1 -0
- package/lib/commonjs/typeORM.js +10 -3
- package/lib/commonjs/typeORM.js.map +1 -1
- package/lib/commonjs/types.js +35 -9
- package/lib/commonjs/types.js.map +1 -1
- package/lib/module/DatabaseQueue.js +52 -16
- package/lib/module/DatabaseQueue.js.map +1 -1
- package/lib/module/NitroSQLiteError.js +6 -7
- package/lib/module/NitroSQLiteError.js.map +1 -1
- package/lib/module/OnLoad.js +1 -1
- package/lib/module/index.js +8 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/operations/execute.js +20 -5
- package/lib/module/operations/execute.js.map +1 -1
- package/lib/module/operations/executeBatch.js +20 -7
- package/lib/module/operations/executeBatch.js.map +1 -1
- package/lib/module/operations/prepare.js +49 -0
- package/lib/module/operations/prepare.js.map +1 -0
- package/lib/module/operations/session.js +107 -31
- package/lib/module/operations/session.js.map +1 -1
- package/lib/module/operations/transaction.js +30 -5
- package/lib/module/operations/transaction.js.map +1 -1
- package/lib/module/specs/NitroSQLitePreparedStatement.nitro.js +4 -0
- package/lib/module/specs/NitroSQLitePreparedStatement.nitro.js.map +1 -0
- package/lib/module/typeORM.js +11 -3
- package/lib/module/typeORM.js.map +1 -1
- package/lib/module/types.js +48 -9
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/commonjs/DatabaseQueue.d.ts +15 -7
- package/lib/typescript/commonjs/DatabaseQueue.d.ts.map +1 -1
- package/lib/typescript/commonjs/NitroSQLiteError.d.ts +6 -7
- package/lib/typescript/commonjs/NitroSQLiteError.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +9 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/operations/execute.d.ts +17 -2
- package/lib/typescript/commonjs/operations/execute.d.ts.map +1 -1
- package/lib/typescript/commonjs/operations/executeBatch.d.ts +15 -2
- package/lib/typescript/commonjs/operations/executeBatch.d.ts.map +1 -1
- package/lib/typescript/commonjs/operations/prepare.d.ts +13 -0
- package/lib/typescript/commonjs/operations/prepare.d.ts.map +1 -0
- package/lib/typescript/commonjs/operations/session.d.ts +8 -0
- package/lib/typescript/commonjs/operations/session.d.ts.map +1 -1
- package/lib/typescript/commonjs/operations/transaction.d.ts +11 -1
- package/lib/typescript/commonjs/operations/transaction.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/NitroSQLite.nitro.d.ts +83 -2
- package/lib/typescript/commonjs/specs/NitroSQLite.nitro.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/NitroSQLitePreparedStatement.nitro.d.ts +26 -0
- package/lib/typescript/commonjs/specs/NitroSQLitePreparedStatement.nitro.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/NitroSQLiteQueryResult.nitro.d.ts +9 -15
- package/lib/typescript/commonjs/specs/NitroSQLiteQueryResult.nitro.d.ts.map +1 -1
- package/lib/typescript/commonjs/typeORM.d.ts +14 -3
- package/lib/typescript/commonjs/typeORM.d.ts.map +1 -1
- package/lib/typescript/commonjs/types.d.ts +124 -21
- package/lib/typescript/commonjs/types.d.ts.map +1 -1
- package/lib/typescript/module/DatabaseQueue.d.ts +15 -7
- package/lib/typescript/module/DatabaseQueue.d.ts.map +1 -1
- package/lib/typescript/module/NitroSQLiteError.d.ts +6 -7
- package/lib/typescript/module/NitroSQLiteError.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +9 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/operations/execute.d.ts +17 -2
- package/lib/typescript/module/operations/execute.d.ts.map +1 -1
- package/lib/typescript/module/operations/executeBatch.d.ts +15 -2
- package/lib/typescript/module/operations/executeBatch.d.ts.map +1 -1
- package/lib/typescript/module/operations/prepare.d.ts +13 -0
- package/lib/typescript/module/operations/prepare.d.ts.map +1 -0
- package/lib/typescript/module/operations/session.d.ts +8 -0
- package/lib/typescript/module/operations/session.d.ts.map +1 -1
- package/lib/typescript/module/operations/transaction.d.ts +11 -1
- package/lib/typescript/module/operations/transaction.d.ts.map +1 -1
- package/lib/typescript/module/specs/NitroSQLite.nitro.d.ts +83 -2
- package/lib/typescript/module/specs/NitroSQLite.nitro.d.ts.map +1 -1
- package/lib/typescript/module/specs/NitroSQLitePreparedStatement.nitro.d.ts +26 -0
- package/lib/typescript/module/specs/NitroSQLitePreparedStatement.nitro.d.ts.map +1 -0
- package/lib/typescript/module/specs/NitroSQLiteQueryResult.nitro.d.ts +9 -15
- package/lib/typescript/module/specs/NitroSQLiteQueryResult.nitro.d.ts.map +1 -1
- package/lib/typescript/module/typeORM.d.ts +14 -3
- package/lib/typescript/module/typeORM.d.ts.map +1 -1
- package/lib/typescript/module/types.d.ts +124 -21
- package/lib/typescript/module/types.d.ts.map +1 -1
- package/nitrogen/generated/android/RNNitroSQLite+autolinking.cmake +1 -0
- package/nitrogen/generated/shared/c++/HybridNitroSQLitePreparedStatementSpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridNitroSQLitePreparedStatementSpec.hpp +73 -0
- package/nitrogen/generated/shared/c++/HybridNitroSQLiteSpec.cpp +3 -0
- package/nitrogen/generated/shared/c++/HybridNitroSQLiteSpec.hpp +8 -2
- package/package.json +4 -2
- package/src/DatabaseQueue.ts +81 -25
- package/src/NitroSQLiteError.ts +6 -7
- package/src/OnLoad.ts +1 -1
- package/src/index.ts +7 -3
- package/src/operations/execute.ts +22 -3
- package/src/operations/executeBatch.ts +20 -5
- package/src/operations/prepare.ts +69 -0
- package/src/operations/session.ts +136 -45
- package/src/operations/transaction.ts +37 -4
- package/src/specs/NitroSQLite.nitro.ts +84 -2
- package/src/specs/NitroSQLitePreparedStatement.nitro.ts +28 -0
- package/src/specs/NitroSQLiteQueryResult.nitro.ts +9 -15
- package/src/typeORM.ts +14 -3
- package/src/types.ts +135 -21
- package/cpp/operations.cpp +0 -358
- package/cpp/operations.hpp +0 -56
- /package/android/{cpp-adapter.cpp → RNNitroSQLiteAdapter.cpp} +0 -0
- /package/cpp/{databaseMigration.hpp → NitroSQLiteDatabaseMigration.hpp} +0 -0
- /package/cpp/{logs.hpp → NitroSQLiteLogs.hpp} +0 -0
package/src/types.ts
CHANGED
|
@@ -1,104 +1,218 @@
|
|
|
1
1
|
import type { NitroSQLiteQueryResult } from './specs/NitroSQLiteQueryResult.nitro'
|
|
2
2
|
|
|
3
|
+
/** Options for `open()` and `NitroSQLite.open()`. */
|
|
3
4
|
export interface NitroSQLiteConnectionOptions {
|
|
5
|
+
/** Database file name. Only one managed connection may use a name at a time. */
|
|
4
6
|
name: string
|
|
7
|
+
/** Directory relative to the platform's database directory. */
|
|
5
8
|
location?: string
|
|
9
|
+
/**
|
|
10
|
+
* Choose a connection to the database file. The default connection is addressed
|
|
11
|
+
* by `name`, so opening it twice throws. Each `independent` connection has its
|
|
12
|
+
* own native handle and operation queue and can share a file with other connections.
|
|
13
|
+
* Defaults to `'default'`.
|
|
14
|
+
*/
|
|
15
|
+
connection?: 'default' | 'independent'
|
|
16
|
+
/**
|
|
17
|
+
* Open an existing database without write access. Opening fails if the file does
|
|
18
|
+
* not exist. A read-only connection cannot write, attach, or delete a database.
|
|
19
|
+
* Defaults to `false`.
|
|
20
|
+
*/
|
|
21
|
+
readOnly?: boolean
|
|
6
22
|
}
|
|
7
23
|
|
|
24
|
+
/** A managed connection bound to one database name. Do not use it after closing or deleting it. */
|
|
8
25
|
export interface NitroSQLiteConnection {
|
|
26
|
+
/** Close the connection. Throws if a queued operation is running or pending. */
|
|
9
27
|
close(): void
|
|
28
|
+
/** Delete the database file and end this connection. Throws if the connection is busy.
|
|
29
|
+
* This also closes the native handle if it is open.
|
|
30
|
+
*/
|
|
10
31
|
delete(): void
|
|
32
|
+
/** Attach another database under `alias` for queries against this connection.
|
|
33
|
+
* @param dbNameToAttach File name of the database to attach.
|
|
34
|
+
* @param alias SQL schema name for the attached database.
|
|
35
|
+
* @param location Directory relative to the platform database directory.
|
|
36
|
+
*/
|
|
11
37
|
attach(dbNameToAttach: string, alias: string, location?: string): void
|
|
38
|
+
/** Detach the database identified by `alias`.
|
|
39
|
+
* @param alias SQL schema name used when attaching the database.
|
|
40
|
+
*/
|
|
12
41
|
detach(alias: string): void
|
|
42
|
+
/** Run a callback in a queued transaction. The callback must use `tx` for database work.
|
|
43
|
+
* It commits on success and rolls back on error unless explicitly finalized.
|
|
44
|
+
* Awaiting another queued operation for this database inside the callback deadlocks.
|
|
45
|
+
* Synchronous connection methods throw while this transaction is active.
|
|
46
|
+
* @param transactionCallback Async callback receiving the transaction handle.
|
|
47
|
+
* @returns The callback's result after the transaction finishes.
|
|
48
|
+
*/
|
|
13
49
|
transaction: <Result = void>(
|
|
14
50
|
transactionCallback: (tx: Transaction) => Promise<Result>,
|
|
15
51
|
) => Promise<Result>
|
|
52
|
+
/** Execute one SQL statement synchronously. Throws while the connection is busy. */
|
|
16
53
|
execute: ExecuteQuery
|
|
54
|
+
/** Queue one SQL statement and resolve with its result. */
|
|
17
55
|
executeAsync: ExecuteAsyncQuery
|
|
56
|
+
/**
|
|
57
|
+
* Prepare one SQL statement on this connection for repeated execution.
|
|
58
|
+
* Finalize the returned statement before closing the connection.
|
|
59
|
+
* @param query SQL statement with optional positional placeholders.
|
|
60
|
+
*/
|
|
61
|
+
prepare(query: string): PreparedStatement
|
|
62
|
+
/** Execute commands in one exclusive transaction. Throws while the connection is busy.
|
|
63
|
+
* @param commands SQL commands and optional parameter sets.
|
|
64
|
+
* @returns Total affected row count.
|
|
65
|
+
*/
|
|
18
66
|
executeBatch(commands: BatchQueryCommand[]): BatchQueryResult
|
|
67
|
+
/** Queue commands in one exclusive transaction.
|
|
68
|
+
* @param commands SQL commands and optional parameter sets.
|
|
69
|
+
* @returns A promise of the total affected row count.
|
|
70
|
+
*/
|
|
19
71
|
executeBatchAsync(commands: BatchQueryCommand[]): Promise<BatchQueryResult>
|
|
72
|
+
/** Execute one non-empty SQL command per file line in an exclusive transaction.
|
|
73
|
+
* `location` is a path to the SQL file; multi-line statements are unsupported.
|
|
74
|
+
* @param location Path to the SQL file.
|
|
75
|
+
* @returns Number of executed commands and affected rows.
|
|
76
|
+
*/
|
|
20
77
|
loadFile(location: string): FileLoadResult
|
|
78
|
+
/** Queue the file import and resolve with its command and row counts.
|
|
79
|
+
* @param location Path to the SQL file.
|
|
80
|
+
*/
|
|
21
81
|
loadFileAsync(location: string): Promise<FileLoadResult>
|
|
22
82
|
}
|
|
23
83
|
|
|
84
|
+
/** SQLite value categories reported in query column metadata. */
|
|
24
85
|
export enum ColumnType {
|
|
86
|
+
/** Boolean declaration. */
|
|
25
87
|
BOOLEAN,
|
|
88
|
+
/** Floating point declaration. */
|
|
26
89
|
NUMBER,
|
|
90
|
+
/** Integer declaration. */
|
|
27
91
|
INT64,
|
|
92
|
+
/** Text declaration. */
|
|
28
93
|
TEXT,
|
|
94
|
+
/** Blob declaration. */
|
|
29
95
|
ARRAY_BUFFER,
|
|
96
|
+
/** Missing or unrecognized declaration. */
|
|
30
97
|
NULL_VALUE,
|
|
31
98
|
}
|
|
32
99
|
|
|
100
|
+
/** Values accepted by bound SQL parameters and returned in result rows. */
|
|
33
101
|
export type SQLiteValue = boolean | number | string | ArrayBuffer | null
|
|
34
102
|
|
|
103
|
+
/** Positional values for SQL placeholders. */
|
|
35
104
|
export type SQLiteQueryParams = SQLiteValue[]
|
|
36
105
|
|
|
106
|
+
/** A row keyed by result column names. */
|
|
37
107
|
export type QueryResultRow = Record<string, SQLiteValue>
|
|
38
108
|
|
|
109
|
+
/** Query result with a row adapter for TypeORM-style consumers. */
|
|
39
110
|
export type QueryResult<Row extends QueryResultRow = QueryResultRow> =
|
|
40
111
|
NitroSQLiteQueryResult & {
|
|
41
|
-
/** Query
|
|
112
|
+
/** Query rows in a TypeORM-compatible collection. */
|
|
42
113
|
rows: NitroSQLiteQueryResultRows<Row>
|
|
43
114
|
}
|
|
44
115
|
|
|
116
|
+
/** Indexable view of query rows. */
|
|
45
117
|
export type NitroSQLiteQueryResultRows<
|
|
46
118
|
Row extends Record<string, SQLiteValue> = Record<string, SQLiteValue>,
|
|
47
119
|
> = {
|
|
48
|
-
/**
|
|
120
|
+
/** All returned rows. */
|
|
49
121
|
_array: Row[]
|
|
50
122
|
|
|
51
|
-
/**
|
|
123
|
+
/** Number of returned rows. */
|
|
52
124
|
length: number
|
|
53
125
|
|
|
54
|
-
/**
|
|
55
|
-
* @param idx
|
|
56
|
-
* @returns the row structure identified by column names
|
|
126
|
+
/** Get a row by zero-based index; returns `undefined` when out of range.
|
|
127
|
+
* @param idx Row index.
|
|
57
128
|
*/
|
|
58
129
|
item: (idx: number) => Row | undefined
|
|
59
130
|
}
|
|
60
131
|
|
|
132
|
+
/** Execute one SQL statement synchronously and return its typed rows.
|
|
133
|
+
* @param query SQL statement with optional positional placeholders.
|
|
134
|
+
* @param params Values bound to the placeholders.
|
|
135
|
+
*/
|
|
61
136
|
export type ExecuteQuery = <Row extends QueryResultRow = QueryResultRow>(
|
|
62
137
|
query: string,
|
|
63
138
|
params?: SQLiteValue[],
|
|
64
139
|
) => QueryResult<Row>
|
|
65
140
|
|
|
141
|
+
/** Queue one SQL statement and resolve with its typed rows.
|
|
142
|
+
* @param query SQL statement with optional positional placeholders.
|
|
143
|
+
* @param params Values bound to the placeholders.
|
|
144
|
+
*/
|
|
66
145
|
export type ExecuteAsyncQuery = <Row extends QueryResultRow = QueryResultRow>(
|
|
67
146
|
query: string,
|
|
68
147
|
params?: SQLiteQueryParams,
|
|
69
148
|
) => Promise<QueryResult<Row>>
|
|
70
149
|
|
|
150
|
+
/**
|
|
151
|
+
* A reusable SQL statement bound to the connection that prepared it. Each
|
|
152
|
+
* execution resets the statement and its bindings before applying new values.
|
|
153
|
+
* Finalize it before closing the connection.
|
|
154
|
+
*/
|
|
155
|
+
export interface PreparedStatement {
|
|
156
|
+
/** Whether `finalize()` has released the native statement. */
|
|
157
|
+
readonly isFinalized: boolean
|
|
158
|
+
/** Execute on the calling thread. Throws if the statement is finalized, its connection is closed, or the managed connection is busy. */
|
|
159
|
+
execute: ExecutePreparedStatement
|
|
160
|
+
/** Queue execution on a background thread and resolve with the query result. */
|
|
161
|
+
executeAsync: ExecutePreparedStatementAsync
|
|
162
|
+
/** Release the native statement. Calling this more than once is safe. */
|
|
163
|
+
finalize(): void
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Execute a prepared statement with optional positional values and return typed rows.
|
|
168
|
+
* Each call replaces the previous parameter bindings.
|
|
169
|
+
* @param params Values bound to the statement's positional placeholders.
|
|
170
|
+
*/
|
|
171
|
+
export type ExecutePreparedStatement = <
|
|
172
|
+
Row extends QueryResultRow = QueryResultRow,
|
|
173
|
+
>(
|
|
174
|
+
params?: SQLiteQueryParams,
|
|
175
|
+
) => QueryResult<Row>
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Queue a prepared statement execution and resolve with typed rows. Calls on the
|
|
179
|
+
* same managed connection run in queue order.
|
|
180
|
+
* @param params Values bound to the statement's positional placeholders.
|
|
181
|
+
*/
|
|
182
|
+
export type ExecutePreparedStatementAsync = <
|
|
183
|
+
Row extends QueryResultRow = QueryResultRow,
|
|
184
|
+
>(
|
|
185
|
+
params?: SQLiteQueryParams,
|
|
186
|
+
) => Promise<QueryResult<Row>>
|
|
187
|
+
|
|
188
|
+
/** Handle valid only while its transaction callback is active. */
|
|
71
189
|
export interface Transaction {
|
|
190
|
+
/** Commit now. Further operations on this transaction throw. */
|
|
72
191
|
commit(): NitroSQLiteQueryResult
|
|
192
|
+
/** Roll back now. Further operations on this transaction throw. */
|
|
73
193
|
rollback(): NitroSQLiteQueryResult
|
|
194
|
+
/** Execute within this transaction on the calling thread. */
|
|
74
195
|
execute: ExecuteQuery
|
|
196
|
+
/** Execute within this transaction on a background thread. */
|
|
75
197
|
executeAsync: ExecuteAsyncQuery
|
|
76
198
|
}
|
|
77
199
|
|
|
78
|
-
/**
|
|
79
|
-
* Allows the execution of bulk of sql commands
|
|
80
|
-
* inside a transaction
|
|
81
|
-
* If a single query must be executed many times with different arguments, its preferred
|
|
82
|
-
* to declare it a single time, and use an array of array parameters.
|
|
83
|
-
*/
|
|
200
|
+
/** One command in a batch. A nested `params` array repeats the query for each parameter set. */
|
|
84
201
|
export interface BatchQueryCommand {
|
|
202
|
+
/** SQL statement to execute. */
|
|
85
203
|
query: string
|
|
204
|
+
/** One parameter set, or several sets for repeated execution. */
|
|
86
205
|
params?: SQLiteQueryParams | SQLiteQueryParams[]
|
|
87
206
|
}
|
|
88
207
|
|
|
89
|
-
/**
|
|
90
|
-
* status: 0 or undefined for correct execution, 1 for error
|
|
91
|
-
* message: if status === 1, here you will find error description
|
|
92
|
-
* rowsAffected: Number of affected rows if status == 0
|
|
93
|
-
*/
|
|
208
|
+
/** Result of a committed SQL batch. Errors are thrown rather than returned here. */
|
|
94
209
|
export interface BatchQueryResult {
|
|
210
|
+
/** Total number of rows changed by the batch. */
|
|
95
211
|
rowsAffected?: number
|
|
96
212
|
}
|
|
97
213
|
|
|
98
|
-
/**
|
|
99
|
-
* Result of loading a file and executing every line as a SQL command
|
|
100
|
-
* Similar to BatchQueryResult
|
|
101
|
-
*/
|
|
214
|
+
/** Result of importing a SQL file in one transaction. */
|
|
102
215
|
export interface FileLoadResult extends BatchQueryResult {
|
|
216
|
+
/** Number of non-empty lines executed as SQL commands. */
|
|
103
217
|
commands?: number
|
|
104
218
|
}
|
package/cpp/operations.cpp
DELETED
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
#include "operations.hpp"
|
|
2
|
-
#include "NitroSQLiteException.hpp"
|
|
3
|
-
#include "hybridObjects/HybridNitroSQLiteQueryResult.hpp"
|
|
4
|
-
#include "logs.hpp"
|
|
5
|
-
#include "utils.hpp"
|
|
6
|
-
#include <NitroModules/ArrayBuffer.hpp>
|
|
7
|
-
#include <cmath>
|
|
8
|
-
#include <ctime>
|
|
9
|
-
#include <iostream>
|
|
10
|
-
#include <limits>
|
|
11
|
-
#include <map>
|
|
12
|
-
#include <memory>
|
|
13
|
-
#include <mutex>
|
|
14
|
-
#include <optional>
|
|
15
|
-
#include <sqlite3.h>
|
|
16
|
-
#include <sstream>
|
|
17
|
-
#include <unistd.h>
|
|
18
|
-
|
|
19
|
-
#ifdef NITRO_SQLITE_VEC
|
|
20
|
-
// Angle-bracket so it resolves via -I (CocoaPods intercepts quoted includes).
|
|
21
|
-
#include <registerVectorExtensions.hpp>
|
|
22
|
-
#endif
|
|
23
|
-
|
|
24
|
-
using namespace facebook;
|
|
25
|
-
using namespace margelo::nitro;
|
|
26
|
-
using namespace margelo::nitro::rnnitrosqlite;
|
|
27
|
-
|
|
28
|
-
namespace margelo::rnnitrosqlite {
|
|
29
|
-
|
|
30
|
-
static constexpr double kInt64MinAsDouble = static_cast<double>(std::numeric_limits<int64_t>::min());
|
|
31
|
-
static constexpr double kInt64UpperBoundAsDouble = -kInt64MinAsDouble;
|
|
32
|
-
|
|
33
|
-
namespace {
|
|
34
|
-
|
|
35
|
-
std::map<std::string, SQLiteConnectionPtr> dbMap;
|
|
36
|
-
std::mutex dbMapMutex;
|
|
37
|
-
std::mutex dbLifecycleMutex;
|
|
38
|
-
|
|
39
|
-
} // namespace
|
|
40
|
-
|
|
41
|
-
SQLiteConnection::SQLiteConnection(std::string connectionName, sqlite3* database) : name(std::move(connectionName)), database(database) {}
|
|
42
|
-
|
|
43
|
-
SQLiteConnection::~SQLiteConnection() {
|
|
44
|
-
close();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
void SQLiteConnection::close() noexcept {
|
|
48
|
-
std::lock_guard lock(mutex);
|
|
49
|
-
if (database == nullptr) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
sqlite3_close_v2(database);
|
|
54
|
-
database = nullptr;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
void sqliteOpenDb(const std::string& dbName, const std::string& docPath) {
|
|
58
|
-
std::lock_guard lifecycleLock(dbLifecycleMutex);
|
|
59
|
-
{
|
|
60
|
-
std::lock_guard lock(dbMapMutex);
|
|
61
|
-
if (dbMap.contains(dbName)) {
|
|
62
|
-
throw NitroSQLiteException::DatabaseAlreadyOpen(dbName);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
#ifdef NITRO_SQLITE_VEC
|
|
67
|
-
// Register before opening so the connection exposes vec0 + vec_*.
|
|
68
|
-
margelo::rnnitrosqlitevec::registerVectorExtensions();
|
|
69
|
-
#endif
|
|
70
|
-
|
|
71
|
-
std::string dbPath = get_db_path(dbName, docPath);
|
|
72
|
-
|
|
73
|
-
int sqlOpenFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
|
|
74
|
-
|
|
75
|
-
sqlite3* rawDatabase = nullptr;
|
|
76
|
-
const int openStatus = sqlite3_open_v2(dbPath.c_str(), &rawDatabase, sqlOpenFlags, nullptr);
|
|
77
|
-
std::unique_ptr<sqlite3, decltype(&sqlite3_close_v2)> database(rawDatabase, sqlite3_close_v2);
|
|
78
|
-
|
|
79
|
-
if (openStatus != SQLITE_OK) {
|
|
80
|
-
const std::string errorMessage = rawDatabase == nullptr ? sqlite3_errstr(openStatus) : sqlite3_errmsg(rawDatabase);
|
|
81
|
-
throw NitroSQLiteException(NitroSQLiteExceptionType::DatabaseCannotBeOpened, errorMessage);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
auto connection = std::make_shared<SQLiteConnection>(dbName, database.get());
|
|
85
|
-
database.release();
|
|
86
|
-
{
|
|
87
|
-
std::lock_guard lock(dbMapMutex);
|
|
88
|
-
const bool inserted = dbMap.emplace(dbName, connection).second;
|
|
89
|
-
if (!inserted) {
|
|
90
|
-
throw NitroSQLiteException::DatabaseAlreadyOpen(dbName);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
void sqliteCloseDb(const std::string& dbName) {
|
|
96
|
-
std::lock_guard lifecycleLock(dbLifecycleMutex);
|
|
97
|
-
SQLiteConnectionPtr connection;
|
|
98
|
-
{
|
|
99
|
-
std::lock_guard lock(dbMapMutex);
|
|
100
|
-
auto iterator = dbMap.find(dbName);
|
|
101
|
-
if (iterator == dbMap.end()) {
|
|
102
|
-
throw NitroSQLiteException::DatabaseNotOpen(dbName);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
connection = std::move(iterator->second);
|
|
106
|
-
dbMap.erase(iterator);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
connection->close();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
void sqliteCloseAll() {
|
|
113
|
-
std::lock_guard lifecycleLock(dbLifecycleMutex);
|
|
114
|
-
std::map<std::string, SQLiteConnectionPtr> connections;
|
|
115
|
-
{
|
|
116
|
-
std::lock_guard lock(dbMapMutex);
|
|
117
|
-
connections.swap(dbMap);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
for (const auto& [_, connection] : connections) {
|
|
121
|
-
connection->close();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
void sqliteAttachDb(const std::string& mainDBName, const std::string& docPath, const std::string& databaseToAttach,
|
|
126
|
-
const std::string& alias) {
|
|
127
|
-
/**
|
|
128
|
-
* There is no need to check if mainDBName is opened because sqliteExecuteCommand will do that.
|
|
129
|
-
* */
|
|
130
|
-
std::string dbPath = get_db_path(databaseToAttach, docPath);
|
|
131
|
-
std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias;
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
sqliteExecuteCommand(mainDBName, statement);
|
|
135
|
-
} catch (NitroSQLiteException& e) {
|
|
136
|
-
throw NitroSQLiteException(NitroSQLiteExceptionType::UnableToAttachToDatabase,
|
|
137
|
-
mainDBName + " was unable to attach another database: " + std::string(e.what()));
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
void sqliteDetachDb(const std::string& mainDBName, const std::string& alias) {
|
|
142
|
-
/**
|
|
143
|
-
* There is no need to check if mainDBName is opened because sqliteExecuteCommand will do that.
|
|
144
|
-
* */
|
|
145
|
-
std::string statement = "DETACH DATABASE " + alias;
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
sqliteExecuteCommand(mainDBName, statement);
|
|
149
|
-
} catch (NitroSQLiteException& e) {
|
|
150
|
-
throw NitroSQLiteException(NitroSQLiteExceptionType::UnableToAttachToDatabase,
|
|
151
|
-
mainDBName + " was unable to detach database: " + std::string(e.what()));
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
void sqliteRemoveDb(const std::string& dbName, const std::string& docPath) {
|
|
156
|
-
std::lock_guard lifecycleLock(dbLifecycleMutex);
|
|
157
|
-
const std::string dbFilePath = get_db_path(dbName, docPath);
|
|
158
|
-
if (!file_exists(dbFilePath)) {
|
|
159
|
-
throw NitroSQLiteException::DatabaseFileNotFound(dbFilePath);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
SQLiteConnectionPtr connection;
|
|
163
|
-
{
|
|
164
|
-
std::lock_guard lock(dbMapMutex);
|
|
165
|
-
auto iterator = dbMap.find(dbName);
|
|
166
|
-
if (iterator != dbMap.end()) {
|
|
167
|
-
connection = std::move(iterator->second);
|
|
168
|
-
dbMap.erase(iterator);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (connection) {
|
|
173
|
-
connection->close();
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
remove(dbFilePath.c_str());
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
void bindStatement(sqlite3_stmt* statement, const SQLiteQueryParams& values) {
|
|
180
|
-
for (int valueIndex = 0; valueIndex < values.size(); valueIndex++) {
|
|
181
|
-
int sqliteIndex = valueIndex + 1;
|
|
182
|
-
SQLiteValue value = values.at(valueIndex);
|
|
183
|
-
if (std::holds_alternative<NullType>(value)) {
|
|
184
|
-
sqlite3_bind_null(statement, sqliteIndex);
|
|
185
|
-
} else if (std::holds_alternative<bool>(value)) {
|
|
186
|
-
sqlite3_bind_int(statement, sqliteIndex, std::get<bool>(value));
|
|
187
|
-
} else if (std::holds_alternative<double>(value)) {
|
|
188
|
-
// Bind whole numbers as INTEGER so vec0 rowid/pk/partition (which reject REAL) work; SQLite still coerces to REAL for REAL columns.
|
|
189
|
-
double doubleValue = std::get<double>(value);
|
|
190
|
-
if (std::trunc(doubleValue) == doubleValue && doubleValue >= kInt64MinAsDouble && doubleValue < kInt64UpperBoundAsDouble) {
|
|
191
|
-
sqlite3_bind_int64(statement, sqliteIndex, static_cast<sqlite3_int64>(doubleValue));
|
|
192
|
-
} else {
|
|
193
|
-
sqlite3_bind_double(statement, sqliteIndex, doubleValue);
|
|
194
|
-
}
|
|
195
|
-
} else if (std::holds_alternative<std::string>(value)) {
|
|
196
|
-
const auto stringValue = std::get<std::string>(value);
|
|
197
|
-
sqlite3_bind_text(statement, sqliteIndex, stringValue.c_str(), stringValue.length(), SQLITE_TRANSIENT);
|
|
198
|
-
} else if (std::holds_alternative<std::shared_ptr<ArrayBuffer>>(value)) {
|
|
199
|
-
const auto arrayBufferValue = std::get<std::shared_ptr<ArrayBuffer>>(value);
|
|
200
|
-
sqlite3_bind_blob(statement, sqliteIndex, arrayBufferValue->data(), arrayBufferValue->size(), SQLITE_STATIC);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
namespace {
|
|
206
|
-
|
|
207
|
-
struct SQLiteStatementFinalizer {
|
|
208
|
-
void operator()(sqlite3_stmt* statement) const noexcept {
|
|
209
|
-
if (statement != nullptr) {
|
|
210
|
-
sqlite3_finalize(statement);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
using SQLiteStatement = std::unique_ptr<sqlite3_stmt, SQLiteStatementFinalizer>;
|
|
216
|
-
|
|
217
|
-
SQLiteStatement prepareStatement(sqlite3* db, const std::string& query, const std::optional<SQLiteQueryParams>& params) {
|
|
218
|
-
sqlite3_stmt* rawStatement = nullptr;
|
|
219
|
-
int statementStatus = sqlite3_prepare_v2(db, query.c_str(), -1, &rawStatement, nullptr);
|
|
220
|
-
SQLiteStatement statement(rawStatement);
|
|
221
|
-
|
|
222
|
-
if (statementStatus != SQLITE_OK) {
|
|
223
|
-
throw NitroSQLiteException::SqlExecution(sqlite3_errmsg(db));
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (params) {
|
|
227
|
-
bindStatement(statement.get(), *params);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return statement;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
template <typename OnRow>
|
|
234
|
-
void consumeStatement(sqlite3* db, sqlite3_stmt* statement, OnRow&& onRow) {
|
|
235
|
-
while (true) {
|
|
236
|
-
int result = sqlite3_step(statement);
|
|
237
|
-
|
|
238
|
-
if (result == SQLITE_ROW) {
|
|
239
|
-
onRow(statement);
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (result == SQLITE_DONE) {
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
throw NitroSQLiteException::SqlExecution(sqlite3_errmsg(db));
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
} // namespace
|
|
252
|
-
|
|
253
|
-
SQLiteConnectionPtr sqliteGetOpenDatabase(const std::string& dbName) {
|
|
254
|
-
std::lock_guard lock(dbMapMutex);
|
|
255
|
-
auto iterator = dbMap.find(dbName);
|
|
256
|
-
if (iterator == dbMap.end()) {
|
|
257
|
-
throw NitroSQLiteException::DatabaseNotOpen(dbName);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return iterator->second;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
std::shared_ptr<HybridNitroSQLiteQueryResult> sqliteExecute(const std::string& dbName, const std::string& query,
|
|
264
|
-
const std::optional<SQLiteQueryParams>& params) {
|
|
265
|
-
return sqliteExecute(sqliteGetOpenDatabase(dbName), query, params);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
std::shared_ptr<HybridNitroSQLiteQueryResult> sqliteExecute(const SQLiteConnectionPtr& connection, const std::string& query,
|
|
269
|
-
const std::optional<SQLiteQueryParams>& params) {
|
|
270
|
-
std::lock_guard lock(connection->mutex);
|
|
271
|
-
sqlite3* db = connection->database;
|
|
272
|
-
if (db == nullptr) {
|
|
273
|
-
throw NitroSQLiteException::DatabaseNotOpen(connection->name);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
auto statement = prepareStatement(db, query, params);
|
|
277
|
-
SQLiteQueryResults results;
|
|
278
|
-
|
|
279
|
-
consumeStatement(db, statement.get(), [&](sqlite3_stmt* currentStatement) {
|
|
280
|
-
SQLiteQueryResultRow row;
|
|
281
|
-
int count = sqlite3_column_count(currentStatement);
|
|
282
|
-
|
|
283
|
-
for (int i = 0; i < count; i++) {
|
|
284
|
-
int columnType = sqlite3_column_type(currentStatement, i);
|
|
285
|
-
std::string columnName = sqlite3_column_name(currentStatement, i);
|
|
286
|
-
|
|
287
|
-
switch (columnType) {
|
|
288
|
-
case SQLITE_INTEGER:
|
|
289
|
-
case SQLITE_FLOAT:
|
|
290
|
-
row[columnName] = sqlite3_column_double(currentStatement, i);
|
|
291
|
-
break;
|
|
292
|
-
case SQLITE_TEXT: {
|
|
293
|
-
auto columnValue = reinterpret_cast<const char*>(sqlite3_column_text(currentStatement, i));
|
|
294
|
-
row[columnName] = columnValue;
|
|
295
|
-
break;
|
|
296
|
-
}
|
|
297
|
-
case SQLITE_BLOB: {
|
|
298
|
-
int blobSize = sqlite3_column_bytes(currentStatement, i);
|
|
299
|
-
const void* blob = sqlite3_column_blob(currentStatement, i);
|
|
300
|
-
if (blobSize > 0) {
|
|
301
|
-
const auto* blobData = reinterpret_cast<const uint8_t*>(blob);
|
|
302
|
-
row[columnName] = ArrayBuffer::copy(blobData, static_cast<size_t>(blobSize));
|
|
303
|
-
} else {
|
|
304
|
-
row[columnName] = ArrayBuffer::allocate(0);
|
|
305
|
-
}
|
|
306
|
-
break;
|
|
307
|
-
}
|
|
308
|
-
case SQLITE_NULL:
|
|
309
|
-
default:
|
|
310
|
-
row[columnName] = NullType::null;
|
|
311
|
-
break;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
results.push_back(std::move(row));
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
std::optional<SQLiteQueryTableMetadata> metadata = std::nullopt;
|
|
319
|
-
int count = sqlite3_column_count(statement.get());
|
|
320
|
-
for (int i = 0; i < count; i++) {
|
|
321
|
-
std::string columnName = sqlite3_column_name(statement.get(), i);
|
|
322
|
-
ColumnType columnDeclaredType = mapSQLiteTypeToColumnType(sqlite3_column_decltype(statement.get(), i));
|
|
323
|
-
auto columnMeta = NitroSQLiteQueryColumnMetadata(columnName, std::move(columnDeclaredType), i);
|
|
324
|
-
|
|
325
|
-
if (!metadata) {
|
|
326
|
-
metadata = std::make_optional<SQLiteQueryTableMetadata>();
|
|
327
|
-
}
|
|
328
|
-
metadata->insert({columnName, std::move(columnMeta)});
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
int rowsAffected = sqlite3_changes(db);
|
|
332
|
-
long long latestInsertRowId = sqlite3_last_insert_rowid(db);
|
|
333
|
-
return std::make_shared<HybridNitroSQLiteQueryResult>(std::move(results), static_cast<double>(latestInsertRowId), rowsAffected,
|
|
334
|
-
std::move(metadata));
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
SQLiteOperationResult sqliteExecuteCommand(const std::string& dbName, const std::string& query,
|
|
338
|
-
const std::optional<SQLiteQueryParams>& params) {
|
|
339
|
-
return sqliteExecuteCommand(sqliteGetOpenDatabase(dbName), query, params);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
SQLiteOperationResult sqliteExecuteCommand(const SQLiteConnectionPtr& connection, const std::string& query,
|
|
343
|
-
const std::optional<SQLiteQueryParams>& params) {
|
|
344
|
-
std::lock_guard lock(connection->mutex);
|
|
345
|
-
sqlite3* db = connection->database;
|
|
346
|
-
if (db == nullptr) {
|
|
347
|
-
throw NitroSQLiteException::DatabaseNotOpen(connection->name);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
auto statement = prepareStatement(db, query, params);
|
|
351
|
-
bool isReadOnly = sqlite3_stmt_readonly(statement.get()) != 0;
|
|
352
|
-
|
|
353
|
-
consumeStatement(db, statement.get(), [](sqlite3_stmt*) {});
|
|
354
|
-
|
|
355
|
-
return {.rowsAffected = isReadOnly ? 0 : sqlite3_changes(db)};
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
} // namespace margelo::rnnitrosqlite
|
package/cpp/operations.hpp
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "hybridObjects/HybridNitroSQLiteQueryResult.hpp"
|
|
4
|
-
#include "types.hpp"
|
|
5
|
-
#include <memory>
|
|
6
|
-
#include <mutex>
|
|
7
|
-
#include <sqlite3.h>
|
|
8
|
-
#include <string>
|
|
9
|
-
|
|
10
|
-
namespace margelo::rnnitrosqlite {
|
|
11
|
-
|
|
12
|
-
// Calls against one connection are serialized by `mutex`. Separate connections
|
|
13
|
-
// intentionally remain independent, so SQLITE_THREADSAFE=0 still requires the
|
|
14
|
-
// caller to serialize SQLite calls globally.
|
|
15
|
-
struct SQLiteConnection final {
|
|
16
|
-
SQLiteConnection(std::string name, sqlite3* database);
|
|
17
|
-
~SQLiteConnection();
|
|
18
|
-
|
|
19
|
-
SQLiteConnection(const SQLiteConnection&) = delete;
|
|
20
|
-
SQLiteConnection& operator=(const SQLiteConnection&) = delete;
|
|
21
|
-
|
|
22
|
-
void close() noexcept;
|
|
23
|
-
|
|
24
|
-
const std::string name;
|
|
25
|
-
sqlite3* database;
|
|
26
|
-
std::recursive_mutex mutex;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
using SQLiteConnectionPtr = std::shared_ptr<SQLiteConnection>;
|
|
30
|
-
|
|
31
|
-
void sqliteOpenDb(const std::string& dbName, const std::string& docPath);
|
|
32
|
-
|
|
33
|
-
void sqliteCloseDb(const std::string& dbName);
|
|
34
|
-
|
|
35
|
-
void sqliteRemoveDb(const std::string& dbName, const std::string& docPath);
|
|
36
|
-
|
|
37
|
-
void sqliteAttachDb(const std::string& mainDBName, const std::string& docPath, const std::string& databaseToAttach,
|
|
38
|
-
const std::string& alias);
|
|
39
|
-
|
|
40
|
-
void sqliteDetachDb(const std::string& mainDBName, const std::string& alias);
|
|
41
|
-
|
|
42
|
-
SQLiteConnectionPtr sqliteGetOpenDatabase(const std::string& dbName);
|
|
43
|
-
|
|
44
|
-
std::shared_ptr<HybridNitroSQLiteQueryResult> sqliteExecute(const std::string& dbName, const std::string& query,
|
|
45
|
-
const std::optional<SQLiteQueryParams>& params);
|
|
46
|
-
std::shared_ptr<HybridNitroSQLiteQueryResult> sqliteExecute(const SQLiteConnectionPtr& connection, const std::string& query,
|
|
47
|
-
const std::optional<SQLiteQueryParams>& params);
|
|
48
|
-
|
|
49
|
-
SQLiteOperationResult sqliteExecuteCommand(const std::string& dbName, const std::string& query,
|
|
50
|
-
const std::optional<SQLiteQueryParams>& params = std::nullopt);
|
|
51
|
-
SQLiteOperationResult sqliteExecuteCommand(const SQLiteConnectionPtr& connection, const std::string& query,
|
|
52
|
-
const std::optional<SQLiteQueryParams>& params = std::nullopt);
|
|
53
|
-
|
|
54
|
-
void sqliteCloseAll();
|
|
55
|
-
|
|
56
|
-
} // namespace margelo::rnnitrosqlite
|
|
File without changes
|
|
File without changes
|
|
File without changes
|