@quatrain/backend-sqlite 1.1.6 → 1.1.8

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.
@@ -2,16 +2,20 @@ import { DataObjectClass, AbstractBackendAdapter, BackendParameters, QueryResult
2
2
  import sqlite3 from 'sqlite3';
3
3
  import { Database } from 'sqlite';
4
4
  /**
5
- * SQLite Backend Adapter for Quatrain
5
+ * Backend adapter implementation for SQLite databases.
6
+ * Uses the `sqlite` driver to provide a fast, local relational store without external dependencies.
7
+ * Highly useful for local development, CI/CD testing environments, or lightweight local deployments.
6
8
  */
7
9
  export declare class SQLiteAdapter extends AbstractBackendAdapter {
8
10
  protected _connection: undefined | Database<sqlite3.Database>;
9
11
  protected _dbPath: string;
10
12
  constructor(params?: BackendParameters);
11
- protected _buildPath(dataObject: DataObjectClass<any>, uid?: string): string;
12
13
  /**
13
- * Executes a raw query on the backend.
14
- * Only supported by SQL adapters.
14
+ * Executes an arbitrary raw SQL query against the SQLite database.
15
+ *
16
+ * @param sql - The SQL statement with optional `?` parameterized placeholders.
17
+ * @param params - The array of parameter values.
18
+ * @returns A promise resolving to the SQLite result rows.
15
19
  */
16
20
  rawQuery(sql: string, params?: any[]): Promise<any>;
17
21
  protected _connect(): Promise<Database<sqlite3.Database>>;
@@ -21,22 +25,51 @@ export declare class SQLiteAdapter extends AbstractBackendAdapter {
21
25
  * @param filterNulls
22
26
  * @returns
23
27
  */
24
- protected _prepareData(data: any, filterNulls?: boolean): any;
28
+ protected _prepareData(data: any, filterNulls?: boolean): any[];
25
29
  /**
26
30
  * Ensure the collection table exists in SQLite
27
31
  * @param dataObject DataObject to create table for
28
32
  */
29
33
  private _ensureTable;
30
34
  /**
31
- * Create record in backend
32
- * @param dataObject DataObject instance to persist in backend
33
- * @param desiredUid Desired unique ID for record
34
- * @returns DataObject
35
+ * Translates a DataObject creation request into an `INSERT INTO` SQL query.
36
+ * SQLite handles JSON by parsing array properties internally.
37
+ *
38
+ * @param dataObject - The DataObject payload.
39
+ * @param desiredUid - Optional explicit UUID.
40
+ * @returns A promise resolving to the saved DataObject.
35
41
  */
36
42
  create(dataObject: DataObjectClass<any>, desiredUid: string | undefined): Promise<DataObjectClass<any>>;
43
+ /**
44
+ * Executes a `SELECT *` query to retrieve a document by its UID.
45
+ * Handles mapping of JSON text columns back into arrays/objects.
46
+ *
47
+ * @param dataObject - The empty DataObject containing the target path.
48
+ * @returns A promise resolving to the hydrated DataObject.
49
+ */
37
50
  read(dataObject: DataObjectClass<any>): Promise<DataObjectClass<any>>;
51
+ /**
52
+ * Processes an `UPDATE` command for modified object properties.
53
+ * Automatically ensures the table exists and properly escapes JSON-backed properties.
54
+ *
55
+ * @param dataObject - The modified DataObject.
56
+ * @returns A promise resolving to the updated instance.
57
+ */
38
58
  update(dataObject: DataObjectClass<any>): Promise<DataObjectClass<any>>;
59
+ /**
60
+ * Generates a `DELETE FROM` or `UPDATE` query depending on the `hardDelete` parameter.
61
+ *
62
+ * @param dataObject - The DataObject to remove.
63
+ * @param hardDelete - Force permanent deletion over soft delete.
64
+ * @returns A promise resolving upon completion.
65
+ */
39
66
  delete(dataObject: DataObjectClass<any>, hardDelete?: boolean): Promise<DataObjectClass<any>>;
67
+ /**
68
+ * Wipes all records from a table by executing a blanket `DELETE FROM`.
69
+ *
70
+ * @param collection - The table name to purge.
71
+ * @param batchSize - Ignored for SQLite bulk deletes.
72
+ */
40
73
  deleteCollection(collection: string, batchSize?: number): Promise<void>;
41
74
  /**
42
75
  * Convert array into SQL expression
@@ -45,12 +78,14 @@ export declare class SQLiteAdapter extends AbstractBackendAdapter {
45
78
  */
46
79
  protected _array2String(from: (string | number)[]): string;
47
80
  /**
48
- * Execute a query on a collection
49
- * @param dataObject
50
- * @param filters
51
- * @param pagination
52
- * @params parent
53
- * @returns
81
+ * Translates the Quatrain `Filters` logic into SQLite query syntax.
82
+ * Employs internal `json_each` extensions for Array-contains searches when JSON1 is available.
83
+ *
84
+ * @param dataObject - The targeted collection object.
85
+ * @param filters - Requested Query filters.
86
+ * @param pagination - Query Limits & Pagination rules.
87
+ * @param parent - Optional parent linkage.
88
+ * @returns A promise resolving to hydrated objects and metadata.
54
89
  */
55
90
  find(dataObject: DataObjectClass<any>, filters?: Filters | Filter[] | undefined, pagination?: SortAndLimit | undefined, parent?: DataObjectClass<any> | undefined): Promise<QueryResultType<DataObjectClass<any>>>;
56
91
  /**
@@ -34,7 +34,9 @@ const operatorsMap = {
34
34
  isNotNull: 'IS NOT NULL',
35
35
  };
36
36
  /**
37
- * SQLite Backend Adapter for Quatrain
37
+ * Backend adapter implementation for SQLite databases.
38
+ * Uses the `sqlite` driver to provide a fast, local relational store without external dependencies.
39
+ * Highly useful for local development, CI/CD testing environments, or lightweight local deployments.
38
40
  */
39
41
  class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
40
42
  constructor(params = {}) {
@@ -42,27 +44,12 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
42
44
  super(params);
43
45
  this._dbPath = ((_a = params.config) === null || _a === void 0 ? void 0 : _a.database) || ':memory:';
44
46
  }
45
- _buildPath(dataObject, uid) {
46
- const collection = this.getCollection(dataObject);
47
- if (!collection) {
48
- throw new backend_1.BackendError(`[SQLA] Can't define record path without a collection name`);
49
- }
50
- // define document path
51
- let path = `${collection}/${uid}`;
52
- if (this._params.hierarchy &&
53
- this._params.hierarchy[collection] ===
54
- backend_1.CollectionHierarchy.SUBCOLLECTION &&
55
- dataObject.parentProp &&
56
- dataObject.has(dataObject.parentProp) &&
57
- dataObject.val(dataObject.parentProp)) {
58
- path = `${dataObject.val(dataObject.parentProp).path}/${path}`;
59
- }
60
- backend_1.Backend.info(`[SQLA] Record path is '${path}'`);
61
- return path;
62
- }
63
47
  /**
64
- * Executes a raw query on the backend.
65
- * Only supported by SQL adapters.
48
+ * Executes an arbitrary raw SQL query against the SQLite database.
49
+ *
50
+ * @param sql - The SQL statement with optional `?` parameterized placeholders.
51
+ * @param params - The array of parameter values.
52
+ * @returns A promise resolving to the SQLite result rows.
66
53
  */
67
54
  rawQuery(sql_1) {
68
55
  return __awaiter(this, arguments, void 0, function* (sql, params = []) {
@@ -114,21 +101,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
114
101
  data[key] = JSON.stringify(el);
115
102
  }
116
103
  });
117
- if (this._params['useNativeForeignKeys'] &&
118
- this._params['useNativeForeignKeys'] === true) {
119
- data.forEach((el, key) => {
120
- if (typeof el === 'object' &&
121
- el !== null &&
122
- Reflect.has(el, 'ref')) {
123
- const resourcePart = el.ref.split('/').pop();
124
- if (resourcePart.indexOf('.') === -1) {
125
- // convert reference for database objects only
126
- data[key] = el.ref.split('/').pop();
127
- }
128
- }
129
- });
130
- }
131
- return data;
104
+ return this._resolveNativeForeignKeys(data);
132
105
  }
133
106
  /**
134
107
  * Ensure the collection table exists in SQLite
@@ -175,10 +148,12 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
175
148
  });
176
149
  }
177
150
  /**
178
- * Create record in backend
179
- * @param dataObject DataObject instance to persist in backend
180
- * @param desiredUid Desired unique ID for record
181
- * @returns DataObject
151
+ * Translates a DataObject creation request into an `INSERT INTO` SQL query.
152
+ * SQLite handles JSON by parsing array properties internally.
153
+ *
154
+ * @param dataObject - The DataObject payload.
155
+ * @param desiredUid - Optional explicit UUID.
156
+ * @returns A promise resolving to the saved DataObject.
182
157
  */
183
158
  create(dataObject, desiredUid) {
184
159
  return __awaiter(this, void 0, void 0, function* () {
@@ -239,6 +214,13 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
239
214
  }
240
215
  });
241
216
  }
217
+ /**
218
+ * Executes a `SELECT *` query to retrieve a document by its UID.
219
+ * Handles mapping of JSON text columns back into arrays/objects.
220
+ *
221
+ * @param dataObject - The empty DataObject containing the target path.
222
+ * @returns A promise resolving to the hydrated DataObject.
223
+ */
242
224
  read(dataObject) {
243
225
  return __awaiter(this, void 0, void 0, function* () {
244
226
  const path = dataObject.path;
@@ -303,6 +285,13 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
303
285
  return dataObject;
304
286
  });
305
287
  }
288
+ /**
289
+ * Processes an `UPDATE` command for modified object properties.
290
+ * Automatically ensures the table exists and properly escapes JSON-backed properties.
291
+ *
292
+ * @param dataObject - The modified DataObject.
293
+ * @returns A promise resolving to the updated instance.
294
+ */
306
295
  update(dataObject) {
307
296
  return __awaiter(this, void 0, void 0, function* () {
308
297
  if (dataObject.uid === undefined) {
@@ -349,6 +338,13 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
349
338
  return dataObject;
350
339
  });
351
340
  }
341
+ /**
342
+ * Generates a `DELETE FROM` or `UPDATE` query depending on the `hardDelete` parameter.
343
+ *
344
+ * @param dataObject - The DataObject to remove.
345
+ * @param hardDelete - Force permanent deletion over soft delete.
346
+ * @returns A promise resolving upon completion.
347
+ */
352
348
  delete(dataObject_1) {
353
349
  return __awaiter(this, arguments, void 0, function* (dataObject, hardDelete = false) {
354
350
  if (dataObject.uid === undefined) {
@@ -379,6 +375,12 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
379
375
  return dataObject;
380
376
  });
381
377
  }
378
+ /**
379
+ * Wipes all records from a table by executing a blanket `DELETE FROM`.
380
+ *
381
+ * @param collection - The table name to purge.
382
+ * @param batchSize - Ignored for SQLite bulk deletes.
383
+ */
382
384
  deleteCollection(collection_1) {
383
385
  return __awaiter(this, arguments, void 0, function* (collection, batchSize = 500) {
384
386
  backend_1.Backend.log(`Deleting all records from collection '${collection}'`);
@@ -400,12 +402,14 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
400
402
  return `'${JSON.stringify(from)}'`;
401
403
  }
402
404
  /**
403
- * Execute a query on a collection
404
- * @param dataObject
405
- * @param filters
406
- * @param pagination
407
- * @params parent
408
- * @returns
405
+ * Translates the Quatrain `Filters` logic into SQLite query syntax.
406
+ * Employs internal `json_each` extensions for Array-contains searches when JSON1 is available.
407
+ *
408
+ * @param dataObject - The targeted collection object.
409
+ * @param filters - Requested Query filters.
410
+ * @param pagination - Query Limits & Pagination rules.
411
+ * @param parent - Optional parent linkage.
412
+ * @returns A promise resolving to hydrated objects and metadata.
409
413
  */
410
414
  find(dataObject_1) {
411
415
  return __awaiter(this, arguments, void 0, function* (dataObject, filters = undefined, pagination = undefined, parent = undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/backend-sqlite",
3
- "version": "1.1.6",
3
+ "version": "1.1.8",
4
4
  "license": "AGPL-3.0-only",
5
5
  "description": "Backend adapter for SQLite",
6
6
  "main": "dist/index.js",
@@ -20,14 +20,15 @@
20
20
  },
21
21
  "author": "Quatrain Développement SAS <developers@quatrain.com>",
22
22
  "dependencies": {
23
- "@quatrain/backend": "^1.2.4",
24
- "@quatrain/core": "^1.2.5",
23
+ "@quatrain/backend": "^1.2.12",
24
+ "@quatrain/core": "^1.2.14",
25
25
  "sqlite": "^5.1.1",
26
26
  "sqlite3": "^5.1.7"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@faker-js/faker": "^7.6.0",
30
30
  "@jest/expect": "^30.0.0",
31
+ "@quatrain/testing": "^1.1.4",
31
32
  "@tsconfig/recommended": "^1.0.1",
32
33
  "@types/jest": "^29.5.12",
33
34
  "@types/node": "^22.10.1",
@@ -17,7 +17,6 @@ import {
17
17
  Filter,
18
18
  SortAndLimit,
19
19
  Sorting,
20
- CollectionHierarchy,
21
20
  } from '@quatrain/backend'
22
21
  import { randomUUID } from 'node:crypto'
23
22
  import sqlite3, { Statement } from 'sqlite3'
@@ -40,7 +39,9 @@ const operatorsMap: { [x: string]: string } = {
40
39
  }
41
40
 
42
41
  /**
43
- * SQLite Backend Adapter for Quatrain
42
+ * Backend adapter implementation for SQLite databases.
43
+ * Uses the `sqlite` driver to provide a fast, local relational store without external dependencies.
44
+ * Highly useful for local development, CI/CD testing environments, or lightweight local deployments.
44
45
  */
45
46
  export class SQLiteAdapter extends AbstractBackendAdapter {
46
47
  protected _connection: undefined | Database<sqlite3.Database>
@@ -51,35 +52,14 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
51
52
  this._dbPath = (params.config?.database as string) || ':memory:'
52
53
  }
53
54
 
54
- protected _buildPath(dataObject: DataObjectClass<any>, uid?: string) {
55
- const collection = this.getCollection(dataObject)
56
- if (!collection) {
57
- throw new BackendError(
58
- `[SQLA] Can't define record path without a collection name`
59
- )
60
- }
61
-
62
- // define document path
63
- let path = `${collection}/${uid}`
64
- if (
65
- this._params.hierarchy &&
66
- this._params.hierarchy[collection] ===
67
- CollectionHierarchy.SUBCOLLECTION &&
68
- dataObject.parentProp &&
69
- dataObject.has(dataObject.parentProp) &&
70
- dataObject.val(dataObject.parentProp)
71
- ) {
72
- path = `${dataObject.val(dataObject.parentProp).path}/${path}`
73
- }
74
55
 
75
- Backend.info(`[SQLA] Record path is '${path}'`)
76
-
77
- return path
78
- }
79
56
 
80
57
  /**
81
- * Executes a raw query on the backend.
82
- * Only supported by SQL adapters.
58
+ * Executes an arbitrary raw SQL query against the SQLite database.
59
+ *
60
+ * @param sql - The SQL statement with optional `?` parameterized placeholders.
61
+ * @param params - The array of parameter values.
62
+ * @returns A promise resolving to the SQLite result rows.
83
63
  */
84
64
  async rawQuery(sql: string, params: any[] = []): Promise<any> {
85
65
  const connection = await this._connect()
@@ -132,26 +112,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
132
112
  }
133
113
  })
134
114
 
135
- if (
136
- this._params['useNativeForeignKeys'] &&
137
- this._params['useNativeForeignKeys'] === true
138
- ) {
139
- data.forEach((el: any, key: number) => {
140
- if (
141
- typeof el === 'object' &&
142
- el !== null &&
143
- Reflect.has(el, 'ref')
144
- ) {
145
- const resourcePart = el.ref.split('/').pop()
146
- if (resourcePart.indexOf('.') === -1) {
147
- // convert reference for database objects only
148
- data[key] = el.ref.split('/').pop()
149
- }
150
- }
151
- })
152
- }
153
-
154
- return data
115
+ return this._resolveNativeForeignKeys(data)
155
116
  }
156
117
 
157
118
  /**
@@ -205,10 +166,12 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
205
166
  }
206
167
 
207
168
  /**
208
- * Create record in backend
209
- * @param dataObject DataObject instance to persist in backend
210
- * @param desiredUid Desired unique ID for record
211
- * @returns DataObject
169
+ * Translates a DataObject creation request into an `INSERT INTO` SQL query.
170
+ * SQLite handles JSON by parsing array properties internally.
171
+ *
172
+ * @param dataObject - The DataObject payload.
173
+ * @param desiredUid - Optional explicit UUID.
174
+ * @returns A promise resolving to the saved DataObject.
212
175
  */
213
176
  async create(
214
177
  dataObject: DataObjectClass<any>,
@@ -295,6 +258,13 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
295
258
  }
296
259
  }
297
260
 
261
+ /**
262
+ * Executes a `SELECT *` query to retrieve a document by its UID.
263
+ * Handles mapping of JSON text columns back into arrays/objects.
264
+ *
265
+ * @param dataObject - The empty DataObject containing the target path.
266
+ * @returns A promise resolving to the hydrated DataObject.
267
+ */
298
268
  async read(dataObject: DataObjectClass<any>): Promise<DataObjectClass<any>> {
299
269
  const path = dataObject.path
300
270
  const collection = this.getCollection(dataObject)
@@ -382,6 +352,13 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
382
352
  return dataObject
383
353
  }
384
354
 
355
+ /**
356
+ * Processes an `UPDATE` command for modified object properties.
357
+ * Automatically ensures the table exists and properly escapes JSON-backed properties.
358
+ *
359
+ * @param dataObject - The modified DataObject.
360
+ * @returns A promise resolving to the updated instance.
361
+ */
385
362
  async update(
386
363
  dataObject: DataObjectClass<any>
387
364
  ): Promise<DataObjectClass<any>> {
@@ -450,6 +427,13 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
450
427
  return dataObject
451
428
  }
452
429
 
430
+ /**
431
+ * Generates a `DELETE FROM` or `UPDATE` query depending on the `hardDelete` parameter.
432
+ *
433
+ * @param dataObject - The DataObject to remove.
434
+ * @param hardDelete - Force permanent deletion over soft delete.
435
+ * @returns A promise resolving upon completion.
436
+ */
453
437
  async delete(
454
438
  dataObject: DataObjectClass<any>,
455
439
  hardDelete = false
@@ -491,6 +475,12 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
491
475
  return dataObject
492
476
  }
493
477
 
478
+ /**
479
+ * Wipes all records from a table by executing a blanket `DELETE FROM`.
480
+ *
481
+ * @param collection - The table name to purge.
482
+ * @param batchSize - Ignored for SQLite bulk deletes.
483
+ */
494
484
  async deleteCollection(collection: string, batchSize = 500): Promise<void> {
495
485
  Backend.log(`Deleting all records from collection '${collection}'`)
496
486
  const db = await this._connect()
@@ -517,12 +507,14 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
517
507
  }
518
508
 
519
509
  /**
520
- * Execute a query on a collection
521
- * @param dataObject
522
- * @param filters
523
- * @param pagination
524
- * @params parent
525
- * @returns
510
+ * Translates the Quatrain `Filters` logic into SQLite query syntax.
511
+ * Employs internal `json_each` extensions for Array-contains searches when JSON1 is available.
512
+ *
513
+ * @param dataObject - The targeted collection object.
514
+ * @param filters - Requested Query filters.
515
+ * @param pagination - Query Limits & Pagination rules.
516
+ * @param parent - Optional parent linkage.
517
+ * @returns A promise resolving to hydrated objects and metadata.
526
518
  */
527
519
  async find(
528
520
  dataObject: DataObjectClass<any>,