@quatrain/backend-sqlite 1.1.1 → 1.1.3

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.
@@ -148,7 +148,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
148
148
  id TEXT PRIMARY KEY`;
149
149
  // Add columns based on dataObject properties
150
150
  Object.entries(dataObject.properties).forEach(([prop, propDef]) => {
151
- const propName = prop.toLowerCase();
151
+ const propName = prop;
152
152
  let columnType = 'TEXT';
153
153
  // Map property types to SQLite column types
154
154
  if (propDef.constructor.name === 'NumberProperty') {
@@ -166,7 +166,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
166
166
  else if (propDef.constructor.name === 'ObjectProperty') {
167
167
  columnType = 'TEXT'; // Store reference ID
168
168
  }
169
- query += `,\n${propName} ${columnType}`;
169
+ query += `,\n"${propName}" ${columnType}`;
170
170
  });
171
171
  query += `)`;
172
172
  yield db.exec(query);
@@ -190,6 +190,8 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
190
190
  const uid = desiredUid || (0, crypto_1.randomUUID)();
191
191
  // Make sure table exists
192
192
  yield this._ensureTable(dataObject);
193
+ // Set uid before middlewares so they can use it
194
+ dataObject.uri.path = this._buildPath(dataObject, uid);
193
195
  // execute middlewares
194
196
  yield this.executeMiddlewares(dataObject, backend_1.BackendAction.CREATE, {
195
197
  useDateFormat: true,
@@ -206,7 +208,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
206
208
  let placeholders = ['?'];
207
209
  let values = [uid];
208
210
  Object.entries(data).forEach(([key, value]) => {
209
- columns.push(`"${key.toLowerCase()}"`);
211
+ columns.push(`"${key}"`);
210
212
  placeholders.push('?');
211
213
  // Convert arrays and objects to JSON strings
212
214
  if (Array.isArray(value) ||
@@ -222,7 +224,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
222
224
  backend_1.Backend.debug(`[SQLA] ${query}`);
223
225
  backend_1.Backend.debug(`[SQLA] Values ${JSON.stringify(values)}`);
224
226
  yield db.run(query, values);
225
- dataObject.uri.path = this._buildPath(dataObject, uid);
227
+ // uri.path is already set before middlewares
226
228
  dataObject.uri.label = data && Reflect.get(data, 'name');
227
229
  dataObject.isPersisted(true);
228
230
  backend_1.Backend.info(`[SQLA] Saved object "${data.name}" at path ${dataObject.path}`);
@@ -261,7 +263,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
261
263
  const propDef = dataObject.properties[prop];
262
264
  if (propDef.constructor.name === 'ObjectProperty' &&
263
265
  propDef.instanceOf) {
264
- const propValue = result[prop.toLowerCase()];
266
+ const propValue = result[prop];
265
267
  if (propValue) {
266
268
  let refTable = undefined;
267
269
  if (this._params.mapping && this._params.mapping[propDef.instanceOf]) {
@@ -286,18 +288,14 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
286
288
  else if (propDef.constructor.name === 'ArrayProperty' || propDef.constructor.name === 'MapProperty') {
287
289
  // Parse JSON arrays and objects
288
290
  try {
289
- if (result[prop.toLowerCase()]) {
290
- result[prop] = JSON.parse(result[prop.toLowerCase()]);
291
+ if (result[prop]) {
292
+ result[prop] = JSON.parse(result[prop]);
291
293
  }
292
294
  }
293
295
  catch (e) {
294
296
  backend_1.Backend.warn(`[SQLA] Failed to parse JSON for ${prop}: ${e}`);
295
297
  }
296
298
  }
297
- // Normalize property name case
298
- if (prop.toLowerCase() !== prop) {
299
- result[prop] = result[prop.toLowerCase()];
300
- }
301
299
  }
302
300
  dataObject.populate(result);
303
301
  return dataObject;
@@ -329,7 +327,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
329
327
  let updates = [];
330
328
  let values = [];
331
329
  Object.entries(data).forEach(([key, value]) => {
332
- updates.push(`"${key.toLowerCase()}" = ?`);
330
+ updates.push(`"${key}" = ?`);
333
331
  // Convert arrays and objects to JSON strings
334
332
  if (Array.isArray(value) ||
335
333
  (typeof value === 'object' && value !== null)) {
@@ -428,7 +426,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
428
426
  Object.entries(dataObject.properties).forEach(([prop, propDef]) => {
429
427
  if (propDef.constructor.name === 'ObjectProperty' &&
430
428
  propDef.instanceOf) {
431
- const propName = prop.toLowerCase();
429
+ const propName = prop;
432
430
  const joinAlias = `${propName}_table`;
433
431
  let table = undefined;
434
432
  if (this._params.mapping && this._params.mapping[propDef.instanceOf]) {
@@ -459,14 +457,14 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
459
457
  // list of filters objects
460
458
  filters.forEach((filter, i) => {
461
459
  query.push(parent && i === 0 ? 'AND' : i > 0 ? 'AND' : 'WHERE');
462
- let realProp = filter.prop.toLowerCase();
460
+ let realProp = filter.prop;
463
461
  let realOperator = operatorsMap[filter.operator];
464
462
  let realValue = filter.value;
465
463
  if (filter.prop === 'keywords') {
466
464
  const keywordFilters = [];
467
465
  const props = dataObject.getProperties(core_1.StringProperty.name);
468
466
  Object.keys(props).forEach((rp) => {
469
- keywordFilters.push(`${collection.toLowerCase()}.${rp.toLowerCase()} LIKE ?`);
467
+ keywordFilters.push(`${collection.toLowerCase()}.${rp} LIKE ?`);
470
468
  params.push(`%${filter.value}%`);
471
469
  });
472
470
  query.push(`(${keywordFilters.join(' OR ')})`);
@@ -480,7 +478,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
480
478
  }
481
479
  else {
482
480
  const property = dataObject.get(filter.prop);
483
- realProp = filter.prop.toLowerCase();
481
+ realProp = filter.prop;
484
482
  if (property.constructor.name === 'ArrayProperty' &&
485
483
  Array.isArray(realValue)) {
486
484
  // Use EXISTS with json_each for array containment in SQLite
@@ -587,7 +585,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
587
585
  if (pagination && pagination.sortings) {
588
586
  pagination.sortings.forEach((sorting, i) => {
589
587
  query.push(i === 0 ? `ORDER BY` : ',');
590
- query.push(`${collection.toLowerCase()}.${sorting.prop.toLowerCase()} ${sorting.order}`);
588
+ query.push(`${collection.toLowerCase()}.${sorting.prop} ${sorting.order}`);
591
589
  if (sorting.prop !== undefined) {
592
590
  sortField.push(`${sorting.prop} ${sorting.order.toUpperCase()}`);
593
591
  }
@@ -617,15 +615,14 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
617
615
  for (let doc of results || []) {
618
616
  // Process document before populating
619
617
  Object.entries(dataObject.properties).forEach(([prop, propDef]) => {
620
- const lcProp = prop.toLowerCase();
621
618
  // Handle ObjectProperty references
622
619
  if (propDef.constructor.name === 'ObjectProperty' &&
623
620
  propDef.instanceOf) {
624
- const refValue = doc[lcProp];
621
+ const refValue = doc[prop];
625
622
  if (refValue) {
626
623
  const info = joinTables[prop];
627
624
  if (info) {
628
- const label = doc[`${lcProp}_table_name`] || '';
625
+ const label = doc[`${prop}_table_name`] || '';
629
626
  doc[prop] = {
630
627
  ref: `${info.table}/${refValue}`,
631
628
  path: `${info.table}/${refValue}`,
@@ -655,18 +652,14 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
655
652
  // Handle array and map properties
656
653
  else if (propDef.constructor.name === 'ArrayProperty' || propDef.constructor.name === 'MapProperty') {
657
654
  try {
658
- if (doc[lcProp]) {
659
- doc[prop] = JSON.parse(doc[lcProp]);
655
+ if (doc[prop] && typeof doc[prop] === 'string') {
656
+ doc[prop] = JSON.parse(doc[prop]);
660
657
  }
661
658
  }
662
659
  catch (e) {
663
660
  backend_1.Backend.warn(`[SQLA] Failed to parse JSON for ${prop}: ${e}`);
664
661
  }
665
662
  }
666
- // Ensure property is available with original case
667
- if (prop !== lcProp) {
668
- doc[prop] = doc[lcProp];
669
- }
670
663
  });
671
664
  // Map SQLite 'id' column back to Quatrain 'uid' property
672
665
  if (doc.id && !doc.uid) {
@@ -711,7 +704,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
711
704
  generateCreateSql(collection, properties) {
712
705
  let query = `CREATE TABLE IF NOT EXISTS "${collection.toLowerCase()}" (\n id TEXT PRIMARY KEY`;
713
706
  properties.forEach((propDef) => {
714
- const propName = propDef.name.toLowerCase();
707
+ const propName = propDef.name;
715
708
  let columnType = 'TEXT';
716
709
  const type = propDef.type || propDef.constructor.name;
717
710
  if (type === 'NumberProperty') {
@@ -745,7 +738,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
745
738
  const downSql = [];
746
739
  // Added columns
747
740
  delta.added.forEach((propDef) => {
748
- const propName = propDef.name.toLowerCase();
741
+ const propName = propDef.name;
749
742
  let columnType = 'TEXT';
750
743
  const type = propDef.type || propDef.constructor.name;
751
744
  if (type === 'NumberProperty') {
@@ -763,7 +756,7 @@ class SQLiteAdapter extends backend_1.AbstractBackendAdapter {
763
756
  });
764
757
  // Removed columns
765
758
  delta.removed.forEach((propDef) => {
766
- const propName = propDef.name.toLowerCase();
759
+ const propName = propDef.name;
767
760
  let columnType = 'TEXT';
768
761
  const type = propDef.type || propDef.constructor.name;
769
762
  if (type === 'NumberProperty')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/backend-sqlite",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "license": "AGPL-3.0-only",
5
5
  "description": "Backend adapter for SQLite",
6
6
  "main": "dist/index.js",
@@ -20,8 +20,8 @@
20
20
  },
21
21
  "author": "Quatrain Développement SAS <developers@quatrain.com>",
22
22
  "dependencies": {
23
- "@quatrain/backend": "^1.2.1",
24
- "@quatrain/core": "^1.2.0",
23
+ "@quatrain/backend": "^1.2.2",
24
+ "@quatrain/core": "^1.2.2",
25
25
  "sqlite": "^5.1.1",
26
26
  "sqlite3": "^5.1.7"
27
27
  },
@@ -178,7 +178,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
178
178
  // Add columns based on dataObject properties
179
179
  Object.entries(dataObject.properties).forEach(
180
180
  ([prop, propDef]: [prop: string, propDef: any]) => {
181
- const propName = prop.toLowerCase()
181
+ const propName = prop
182
182
  let columnType = 'TEXT'
183
183
 
184
184
  // Map property types to SQLite column types
@@ -194,7 +194,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
194
194
  columnType = 'TEXT' // Store reference ID
195
195
  }
196
196
 
197
- query += `,\n${propName} ${columnType}`
197
+ query += `,\n"${propName}" ${columnType}`
198
198
  }
199
199
  )
200
200
 
@@ -227,6 +227,9 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
227
227
  // Make sure table exists
228
228
  await this._ensureTable(dataObject)
229
229
 
230
+ // Set uid before middlewares so they can use it
231
+ dataObject.uri.path = this._buildPath(dataObject, uid)
232
+
230
233
  // execute middlewares
231
234
  await this.executeMiddlewares(dataObject, BackendAction.CREATE, {
232
235
  useDateFormat: true,
@@ -248,7 +251,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
248
251
 
249
252
  Object.entries(data).forEach(
250
253
  ([key, value]: [key: string, value: any]) => {
251
- columns.push(`"${key.toLowerCase()}"`)
254
+ columns.push(`"${key}"`)
252
255
  placeholders.push('?')
253
256
 
254
257
  // Convert arrays and objects to JSON strings
@@ -273,7 +276,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
273
276
 
274
277
  await db.run(query, values)
275
278
 
276
- dataObject.uri.path = this._buildPath(dataObject, uid)
279
+ // uri.path is already set before middlewares
277
280
  dataObject.uri.label = data && Reflect.get(data, 'name')
278
281
  dataObject.isPersisted(true)
279
282
 
@@ -332,7 +335,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
332
335
  propDef.constructor.name === 'ObjectProperty' &&
333
336
  propDef.instanceOf
334
337
  ) {
335
- const propValue = result[prop.toLowerCase()]
338
+ const propValue = result[prop]
336
339
 
337
340
  if (propValue) {
338
341
  let refTable = undefined
@@ -361,18 +364,15 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
361
364
  } else if (propDef.constructor.name === 'ArrayProperty' || propDef.constructor.name === 'MapProperty') {
362
365
  // Parse JSON arrays and objects
363
366
  try {
364
- if (result[prop.toLowerCase()]) {
365
- result[prop] = JSON.parse(result[prop.toLowerCase()])
367
+ if (result[prop]) {
368
+ result[prop] = JSON.parse(result[prop])
366
369
  }
367
370
  } catch (e) {
368
371
  Backend.warn(`[SQLA] Failed to parse JSON for ${prop}: ${e}`)
369
372
  }
370
373
  }
371
374
 
372
- // Normalize property name case
373
- if (prop.toLowerCase() !== prop) {
374
- result[prop] = result[prop.toLowerCase()]
375
- }
375
+
376
376
  }
377
377
 
378
378
  dataObject.populate(result)
@@ -415,7 +415,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
415
415
 
416
416
  Object.entries(data).forEach(
417
417
  ([key, value]: [key: string, value: any]) => {
418
- updates.push(`"${key.toLowerCase()}" = ?`)
418
+ updates.push(`"${key}" = ?`)
419
419
 
420
420
  // Convert arrays and objects to JSON strings
421
421
  if (
@@ -556,7 +556,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
556
556
  propDef.constructor.name === 'ObjectProperty' &&
557
557
  propDef.instanceOf
558
558
  ) {
559
- const propName = prop.toLowerCase()
559
+ const propName = prop
560
560
  const joinAlias = `${propName}_table`
561
561
 
562
562
  let table = undefined
@@ -595,7 +595,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
595
595
  filters.forEach((filter, i) => {
596
596
  query.push(parent && i === 0 ? 'AND' : i > 0 ? 'AND' : 'WHERE')
597
597
 
598
- let realProp: any = filter.prop.toLowerCase()
598
+ let realProp: any = filter.prop
599
599
  let realOperator: string = operatorsMap[filter.operator]
600
600
  let realValue = filter.value
601
601
 
@@ -605,7 +605,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
605
605
  const props = dataObject.getProperties(StringProperty.name)
606
606
  Object.keys(props).forEach((rp) => {
607
607
  keywordFilters.push(
608
- `${collection.toLowerCase()}.${rp.toLowerCase()} LIKE ?`
608
+ `${collection.toLowerCase()}.${rp} LIKE ?`
609
609
  )
610
610
  params.push(`%${filter.value as string}%`)
611
611
  })
@@ -624,7 +624,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
624
624
  realProp = 'id'
625
625
  } else {
626
626
  const property = dataObject.get(filter.prop)
627
- realProp = filter.prop.toLowerCase()
627
+ realProp = filter.prop
628
628
 
629
629
  if (
630
630
  property.constructor.name === 'ArrayProperty' &&
@@ -770,7 +770,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
770
770
  pagination.sortings.forEach((sorting: Sorting, i) => {
771
771
  query.push(i === 0 ? `ORDER BY` : ',')
772
772
  query.push(
773
- `${collection.toLowerCase()}.${sorting.prop.toLowerCase()} ${
773
+ `${collection.toLowerCase()}.${sorting.prop} ${
774
774
  sorting.order
775
775
  }`
776
776
  )
@@ -810,19 +810,17 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
810
810
  for (let doc of results || []) {
811
811
  // Process document before populating
812
812
  Object.entries(dataObject.properties).forEach(([prop, propDef]: [prop: string, propDef: any]) => {
813
- const lcProp = prop.toLowerCase()
814
-
815
813
  // Handle ObjectProperty references
816
814
  if (
817
815
  propDef.constructor.name === 'ObjectProperty' &&
818
816
  propDef.instanceOf
819
817
  ) {
820
- const refValue = doc[lcProp]
818
+ const refValue = doc[prop]
821
819
  if (refValue) {
822
820
  const info = joinTables[prop]
823
821
 
824
822
  if (info) {
825
- const label = doc[`${lcProp}_table_name`] || ''
823
+ const label = doc[`${prop}_table_name`] || ''
826
824
 
827
825
  doc[prop] = {
828
826
  ref: `${info.table}/${refValue}`,
@@ -852,8 +850,8 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
852
850
  // Handle array and map properties
853
851
  else if (propDef.constructor.name === 'ArrayProperty' || propDef.constructor.name === 'MapProperty') {
854
852
  try {
855
- if (doc[lcProp]) {
856
- doc[prop] = JSON.parse(doc[lcProp])
853
+ if (doc[prop] && typeof doc[prop] === 'string') {
854
+ doc[prop] = JSON.parse(doc[prop])
857
855
  }
858
856
  } catch (e) {
859
857
  Backend.warn(
@@ -861,11 +859,6 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
861
859
  )
862
860
  }
863
861
  }
864
-
865
- // Ensure property is available with original case
866
- if (prop !== lcProp) {
867
- doc[prop] = doc[lcProp]
868
- }
869
862
  })
870
863
 
871
864
  // Map SQLite 'id' column back to Quatrain 'uid' property
@@ -931,7 +924,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
931
924
  let query = `CREATE TABLE IF NOT EXISTS "${collection.toLowerCase()}" (\n id TEXT PRIMARY KEY`
932
925
 
933
926
  properties.forEach((propDef: any) => {
934
- const propName = propDef.name.toLowerCase()
927
+ const propName = propDef.name
935
928
  let columnType = 'TEXT'
936
929
 
937
930
  const type = propDef.type || propDef.constructor.name
@@ -967,7 +960,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
967
960
 
968
961
  // Added columns
969
962
  delta.added.forEach((propDef: any) => {
970
- const propName = propDef.name.toLowerCase()
963
+ const propName = propDef.name
971
964
  let columnType = 'TEXT'
972
965
 
973
966
  const type = propDef.type || propDef.constructor.name
@@ -986,7 +979,7 @@ export class SQLiteAdapter extends AbstractBackendAdapter {
986
979
 
987
980
  // Removed columns
988
981
  delta.removed.forEach((propDef: any) => {
989
- const propName = propDef.name.toLowerCase()
982
+ const propName = propDef.name
990
983
  let columnType = 'TEXT'
991
984
 
992
985
  const type = propDef.type || propDef.constructor.name