sails-sqlite 0.1.0 → 0.2.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.
Files changed (29) hide show
  1. package/lib/index.js +204 -28
  2. package/lib/private/build-std-adapter-method.js +8 -4
  3. package/lib/private/machines/avg-records.js +1 -1
  4. package/lib/private/machines/begin-transaction.js +51 -0
  5. package/lib/private/machines/commit-transaction.js +50 -0
  6. package/lib/private/machines/count-records.js +1 -1
  7. package/lib/private/machines/create-each-record.js +1 -1
  8. package/lib/private/machines/create-record.js +2 -2
  9. package/lib/private/machines/define-physical-model.js +18 -9
  10. package/lib/private/machines/destroy-records.js +21 -8
  11. package/lib/private/machines/drop-physical-model.js +2 -2
  12. package/lib/private/machines/find-records.js +3 -3
  13. package/lib/private/machines/join.js +232 -66
  14. package/lib/private/machines/lease-connection.js +58 -0
  15. package/lib/private/machines/private/build-sqlite-where-clause.js +10 -8
  16. package/lib/private/machines/private/compile-statement.js +334 -0
  17. package/lib/private/machines/private/generate-join-sql-query.js +14 -6
  18. package/lib/private/machines/private/process-each-record.js +9 -2
  19. package/lib/private/machines/private/process-native-error.js +85 -40
  20. package/lib/private/machines/rollback-transaction.js +50 -0
  21. package/lib/private/machines/sum-records.js +1 -1
  22. package/lib/private/machines/update-records.js +27 -10
  23. package/package.json +8 -3
  24. package/tests/index.js +1 -1
  25. package/tests/runner.js +99 -0
  26. package/tests/transaction.test.js +562 -0
  27. package/tests/adapter.test.js +0 -534
  28. package/tests/datatypes.test.js +0 -293
  29. package/tests/sequence.test.js +0 -153
package/lib/index.js CHANGED
@@ -18,7 +18,11 @@ const DRY_MACHINES = {
18
18
  definePhysicalModel: require('./private/machines/define-physical-model'),
19
19
  dropPhysicalModel: require('./private/machines/drop-physical-model'),
20
20
  setPhysicalSequence: require('./private/machines/set-physical-sequence'),
21
- join: require('./private/machines/join')
21
+ join: require('./private/machines/join'),
22
+ beginTransaction: require('./private/machines/begin-transaction'),
23
+ commitTransaction: require('./private/machines/commit-transaction'),
24
+ rollbackTransaction: require('./private/machines/rollback-transaction'),
25
+ leaseConnection: require('./private/machines/lease-connection')
22
26
  }
23
27
 
24
28
  const WET_MACHINES = Object.fromEntries(
@@ -255,11 +259,16 @@ module.exports = {
255
259
  )
256
260
  }
257
261
 
262
+ const modelDefinition = modelInfo.definition || modelInfo.attributes
263
+
258
264
  registeredDryModels[modelIdentity] = {
265
+ identity: modelIdentity,
259
266
  primaryKey: modelInfo.primaryKey,
260
- attributes: modelInfo.definition || modelInfo.attributes,
267
+ definition: modelDefinition,
268
+ attributes: modelDefinition,
261
269
  tableName: modelInfo.tableName,
262
- identity: modelInfo.identity
270
+ identity: modelInfo.identity,
271
+ datastore: datastoreName
263
272
  }
264
273
 
265
274
  // Uncomment for detailed debugging:
@@ -354,6 +363,14 @@ module.exports = {
354
363
  delete registeredDryModels[modelIdentity]
355
364
  }
356
365
  })
366
+
367
+ // Safety cleanup: If this is the last datastore being torn down,
368
+ // clear any remaining models to prevent registration conflicts
369
+ if (Object.keys(registeredDsEntries).length === 0) {
370
+ Object.keys(registeredDryModels).forEach((modelIdentity) => {
371
+ delete registeredDryModels[modelIdentity]
372
+ })
373
+ }
357
374
  } catch (err) {
358
375
  return done(err)
359
376
  }
@@ -533,30 +550,12 @@ module.exports = {
533
550
  // ║║║╠═╣ ║ ║╚╗╔╝║╣ ││ │││││ └─┐│ │├─┘├─┘│ │├┬┘ │
534
551
  // ╝╚╝╩ ╩ ╩ ╩ ╚╝ ╚═╝ └┘└─┘┴┘└┘ └─┘└─┘┴ ┴ └─┘┴└─ ┴
535
552
  // Build up native joins to run on the adapter.
536
- join: function join(datastoreName, query, cb) {
537
- var datastore = registeredDsEntries[datastoreName]
538
- // Models are stored globally, not per datastore
539
- var models = registeredDryModels
540
-
541
- // Add redactPasswords function if not defined
542
- function redactPasswords(err) {
543
- // Simple implementation - in production you might want more sophisticated password redaction
544
- return err
545
- }
546
-
547
- WET_MACHINES.join({
548
- datastore: datastore,
549
- models: models,
550
- query: query
551
- }).switch({
552
- error: function error(err) {
553
- return cb(redactPasswords(err))
554
- },
555
- success: function success(report) {
556
- return cb(undefined, report)
557
- }
558
- })
559
- },
553
+ join: buildStdAdapterMethod(
554
+ require('./private/machines/join'),
555
+ WET_MACHINES,
556
+ registeredDsEntries,
557
+ registeredDryModels
558
+ ),
560
559
  //////////////////////////////////////////////////////////////////////////////////////////////////
561
560
  // ██████╗ ██████╗ ██╗ //
562
561
  // ██╔══██╗██╔═══██╗██║ //
@@ -924,5 +923,182 @@ module.exports = {
924
923
  *
925
924
  * > https://github.com/node-machine/driver-interface/blob/master/layers/migratable/set-physical-sequence.js
926
925
  */
927
- setPhysicalSequence: DRY_MACHINES.setPhysicalSequence
926
+ setPhysicalSequence: DRY_MACHINES.setPhysicalSequence,
927
+
928
+ //////////////////////////////////////////////////////////////////////////////////////////////////
929
+ // ████████╗██████╗ █████╗ ███╗ ███╗███████╗ █████╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗ //
930
+ // ╚══██╔══╝██╔══██╗██╔══██╗████╗ ████║██╔════╝██╔══██╗██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║ //
931
+ // ██║ ██████╔╝███████║██╔████╔██║███████╗███████║██║ ██║ ██║██║ ██║██╔██╗ ██║ //
932
+ // ██║ ██╔══██╗██╔══██║██║╚██╔╝██║╚════██║██╔══██║██║ ██║ ██║██║ ██║██║╚██╗██║ //
933
+ // ██║ ██║ ██║██║ ██║██║ ╚═╝ ██║███████║██║ ██║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║ //
934
+ // ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ //
935
+ // //
936
+ // Transaction methods: //
937
+ // Methods related to database transactions (begin, commit, rollback). //
938
+ //////////////////////////////////////////////////////////////////////////////////////////////////
939
+
940
+ /**
941
+ * ╔╗ ╔═╗╔═╗╦╔╗╔ ┌┬┐┬─┐┌─┐┌┐┌┌─┐┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
942
+ * ╠╩╗║╣ ║ ╦║║║║ │ ├┬┘├─┤│││└─┐├─┤│ │ ││ ││││
943
+ * ╚═╝╚═╝╚═╝╩╝╚╝ ┴ ┴└─┴ ┴┘└┘└─┘┴ ┴└─┘ ┴ ┴└─┘┘└┘
944
+ * Begin a new database transaction.
945
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
946
+ * @param {String} datastoreName The name of the datastore to perform the query on.
947
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
948
+ * @param {Dictionary} options Transaction options (connection, meta).
949
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
950
+ * @param {Function} done Callback
951
+ * @param {Error?}
952
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
953
+ */
954
+ beginTransaction: function (datastoreName, options, done) {
955
+ const dsEntry = registeredDsEntries[datastoreName]
956
+ const connection = options.connection
957
+ const meta = options.meta || {}
958
+
959
+ if (!dsEntry) {
960
+ return done(
961
+ new Error(
962
+ `Consistency violation: Cannot do that with datastore (${datastoreName}) because no matching datastore entry is registered in this adapter! This is usually due to a race condition (e.g. a lifecycle callback still running after the ORM has been torn down), or it could be due to a bug in this adapter. (If you get stumped, reach out at http://sailsjs.com/support.)`
963
+ )
964
+ )
965
+ }
966
+
967
+ WET_MACHINES.beginTransaction({
968
+ connection: connection,
969
+ meta: meta
970
+ }).switch({
971
+ error: function (err) {
972
+ return done(err)
973
+ },
974
+ success: function () {
975
+ return done()
976
+ }
977
+ })
978
+ },
979
+
980
+ /**
981
+ * ╔═╗╔═╗╔╦╗╔╦╗╦╔╦╗ ┌┬┐┬─┐┌─┐┌┐┌┌─┐┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
982
+ * ║ ║ ║║║║║║║║ ║ │ ├┬┘├─┤│││└─┐├─┤│ │ ││ ││││
983
+ * ╚═╝╚═╝╩ ╩╩ ╩╩ ╩ ┴ ┴└─┴ ┴┘└┘└─┘┴ ┴└─┘ ┴ ┴└─┘┘└┘
984
+ * Commit the database transaction on the provided connection.
985
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
986
+ * @param {String} datastoreName The name of the datastore to perform the query on.
987
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
988
+ * @param {Dictionary} options Transaction options (connection, meta).
989
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
990
+ * @param {Function} done Callback
991
+ * @param {Error?}
992
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
993
+ */
994
+ commitTransaction: function (datastoreName, options, done) {
995
+ const dsEntry = registeredDsEntries[datastoreName]
996
+ const connection = options.connection
997
+ const meta = options.meta || {}
998
+
999
+ if (!dsEntry) {
1000
+ return done(
1001
+ new Error(
1002
+ `Consistency violation: Cannot do that with datastore (${datastoreName}) because no matching datastore entry is registered in this adapter! This is usually due to a race condition (e.g. a lifecycle callback still running after the ORM has been torn down), or it could be due to a bug in this adapter. (If you get stumped, reach out at http://sailsjs.com/support.)`
1003
+ )
1004
+ )
1005
+ }
1006
+
1007
+ WET_MACHINES.commitTransaction({
1008
+ connection: connection,
1009
+ meta: meta
1010
+ }).switch({
1011
+ error: function (err) {
1012
+ return done(err)
1013
+ },
1014
+ success: function () {
1015
+ return done()
1016
+ }
1017
+ })
1018
+ },
1019
+
1020
+ /**
1021
+ * ╦═╗╔═╗╦ ╦ ╔╗ ╔═╗╔═╗╦╔═
1022
+ * ╠╦╝║ ║║ ║ ╠╩╗╠═╣║ ╠╩╗
1023
+ * ╩╚═╚═╝╩═╝╩═╝╚═╝╩ ╩╚═╝╩ ╩
1024
+ * ┌┬┐┬─┐┌─┐┌┐┌┌─┐┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
1025
+ * │ ├┬┘├─┤│││└─┐├─┤│ │ ││ ││││
1026
+ * ┴ ┴└─┴ ┴┘└┘└─┘┴ ┴└─┘ ┴ ┴└─┘┘└┘
1027
+ * Rollback the database transaction on the provided connection.
1028
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1029
+ * @param {String} datastoreName The name of the datastore to perform the query on.
1030
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1031
+ * @param {Dictionary} options Transaction options (connection, meta).
1032
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1033
+ * @param {Function} done Callback
1034
+ * @param {Error?}
1035
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1036
+ */
1037
+ rollbackTransaction: function (datastoreName, options, done) {
1038
+ const dsEntry = registeredDsEntries[datastoreName]
1039
+ const connection = options.connection
1040
+ const meta = options.meta || {}
1041
+
1042
+ if (!dsEntry) {
1043
+ return done(
1044
+ new Error(
1045
+ `Consistency violation: Cannot do that with datastore (${datastoreName}) because no matching datastore entry is registered in this adapter! This is usually due to a race condition (e.g. a lifecycle callback still running after the ORM has been torn down), or it could be due to a bug in this adapter. (If you get stumped, reach out at http://sailsjs.com/support.)`
1046
+ )
1047
+ )
1048
+ }
1049
+
1050
+ WET_MACHINES.rollbackTransaction({
1051
+ connection: connection,
1052
+ meta: meta
1053
+ }).switch({
1054
+ error: function (err) {
1055
+ return done(err)
1056
+ },
1057
+ success: function () {
1058
+ return done()
1059
+ }
1060
+ })
1061
+ },
1062
+
1063
+ /**
1064
+ * ╦ ╔═╗╔═╗╔═╗╔═╗ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
1065
+ * ║ ║╣ ╠═╣╚═╗║╣ │ │ │││││││├┤ │ │ ││ ││││
1066
+ * ╩═╝╚═╝╩ ╩╚═╝╚═╝ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
1067
+ * Lease a connection from the datastore for use in a transaction.
1068
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1069
+ * @param {String} datastoreName The name of the datastore to lease from.
1070
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1071
+ * @param {Dictionary} meta Meta options.
1072
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1073
+ * @param {Function} done Callback
1074
+ * @param {Error?}
1075
+ * @param {Dictionary?} connection
1076
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1077
+ */
1078
+ leaseConnection: function (datastoreName, meta, done) {
1079
+ const dsEntry = registeredDsEntries[datastoreName]
1080
+
1081
+ if (!dsEntry) {
1082
+ return done(
1083
+ new Error(
1084
+ `Consistency violation: Cannot do that with datastore (${datastoreName}) because no matching datastore entry is registered in this adapter! This is usually due to a race condition (e.g. a lifecycle callback still running after the ORM has been torn down), or it could be due to a bug in this adapter. (If you get stumped, reach out at http://sailsjs.com/support.)`
1085
+ )
1086
+ )
1087
+ }
1088
+
1089
+ WET_MACHINES.leaseConnection({
1090
+ manager: dsEntry.manager,
1091
+ meta: meta || {}
1092
+ }).switch({
1093
+ error: function (err) {
1094
+ return done(err)
1095
+ },
1096
+ failed: function (err) {
1097
+ return done(err)
1098
+ },
1099
+ success: function (connection) {
1100
+ return done(null, connection)
1101
+ }
1102
+ })
1103
+ }
928
1104
  }
@@ -48,10 +48,14 @@ module.exports = function buildStdAdapterMethod(
48
48
 
49
49
  // Only add notUnique handler if the machine defines this exit
50
50
  if (machineDef.exits.notUnique) {
51
- switchHandlers.notUnique = function (err) {
52
- return done(
53
- Object.assign(new Error('Not unique'), { code: 'E_UNIQUE' })
54
- )
51
+ switchHandlers.notUnique = function (errInfo) {
52
+ // Create error in same format as sails-postgresql
53
+ const e = new Error(errInfo.message || 'Not unique')
54
+ e.code = 'E_UNIQUE'
55
+ if (errInfo.footprint) {
56
+ e.footprint = errInfo.footprint
57
+ }
58
+ return done(e)
55
59
  }
56
60
  }
57
61
 
@@ -58,7 +58,7 @@ module.exports = {
58
58
  const db = inputs.connection
59
59
 
60
60
  try {
61
- let avgQuery = `SELECT COALESCE(AVG(${numericFieldName}), 0) as average FROM ${tableName}`
61
+ let avgQuery = `SELECT COALESCE(AVG(\`${numericFieldName}\`), 0) as average FROM \`${tableName}\``
62
62
  if (whereClause) {
63
63
  avgQuery += ` WHERE ${whereClause}`
64
64
  }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Module dependencies
3
+ */
4
+
5
+ /**
6
+ * Begin Transaction
7
+ *
8
+ * Begin a new database transaction on the provided connection.
9
+ */
10
+
11
+ module.exports = {
12
+ friendlyName: 'Begin transaction',
13
+
14
+ description: 'Begin a new database transaction on the provided connection.',
15
+
16
+ moreInfoUrl:
17
+ 'https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md#transactionfunction---function',
18
+
19
+ inputs: {
20
+ connection: {
21
+ description:
22
+ 'An active database connection that was acquired from a manager.',
23
+ example: '===',
24
+ required: true
25
+ },
26
+
27
+ meta: {
28
+ description: 'Additional options for this query.',
29
+ example: '==='
30
+ }
31
+ },
32
+
33
+ fn: function beginTransaction(inputs, exits) {
34
+ const db = inputs.connection
35
+ const meta = inputs.meta || {}
36
+
37
+ try {
38
+ if (db.inTransaction) {
39
+ return exits.error(
40
+ new Error('Transaction is already active on this connection.')
41
+ )
42
+ }
43
+
44
+ db.prepare('BEGIN TRANSACTION').run()
45
+
46
+ return exits.success()
47
+ } catch (err) {
48
+ return exits.error(err)
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Module dependencies
3
+ */
4
+
5
+ /**
6
+ * Commit Transaction
7
+ *
8
+ * Commit the current database transaction on the provided connection.
9
+ */
10
+
11
+ module.exports = {
12
+ friendlyName: 'Commit transaction',
13
+
14
+ description:
15
+ 'Commit the current database transaction on the provided connection.',
16
+
17
+ moreInfoUrl:
18
+ 'https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md#transactionfunction---function',
19
+
20
+ inputs: {
21
+ connection: {
22
+ description:
23
+ 'An active database connection that was acquired from a manager.',
24
+ example: '===',
25
+ required: true
26
+ },
27
+
28
+ meta: {
29
+ description: 'Additional options for this query.',
30
+ example: '==='
31
+ }
32
+ },
33
+
34
+ fn: function commitTransaction(inputs, exits) {
35
+ const db = inputs.connection
36
+ const meta = inputs.meta || {}
37
+
38
+ try {
39
+ if (!db.inTransaction) {
40
+ return exits.error(new Error('No active transaction to commit.'))
41
+ }
42
+
43
+ db.prepare('COMMIT TRANSACTION').run()
44
+
45
+ return exits.success()
46
+ } catch (err) {
47
+ return exits.error(err)
48
+ }
49
+ }
50
+ }
@@ -62,7 +62,7 @@ module.exports = {
62
62
  const db = inputs.connection
63
63
 
64
64
  try {
65
- let countQuery = `SELECT COUNT(*) as count FROM ${tableName}`
65
+ let countQuery = `SELECT COUNT(*) as count FROM \`${tableName}\``
66
66
  if (whereClause) {
67
67
  countQuery += ` WHERE ${whereClause}`
68
68
  }
@@ -94,7 +94,7 @@ module.exports = {
94
94
  )
95
95
  }
96
96
 
97
- const columns = columnNames.join(', ')
97
+ const columns = columnNames.map((col) => `\`${col}\``).join(', ')
98
98
  const valueClause = `(${columnNames.map(() => '?').join(', ')})`
99
99
  const allValueClauses = Array(s3q.newRecords.length)
100
100
  .fill(valueClause)
@@ -74,7 +74,7 @@ module.exports = {
74
74
  }
75
75
 
76
76
  // Prepare the INSERT statement with proper SQL escaping
77
- const columns = columnNames.join(', ')
77
+ const columns = columnNames.map((col) => `\`${col}\``).join(', ')
78
78
  const placeholders = columnNames.map(() => '?').join(', ')
79
79
  const sql = `INSERT INTO \`${tableName}\` (${columns}) VALUES (${placeholders})`
80
80
 
@@ -94,7 +94,7 @@ module.exports = {
94
94
  }
95
95
 
96
96
  // Otherwise, fetch the newly created record
97
- const selectSql = `SELECT * FROM ${tableName} WHERE rowid = ?`
97
+ const selectSql = `SELECT * FROM \`${tableName}\` WHERE rowid = ?`
98
98
  const selectStmt = db.prepare(selectSql)
99
99
  const phRecord = selectStmt.get(info.lastInsertRowid)
100
100
 
@@ -61,15 +61,20 @@ module.exports = {
61
61
  }
62
62
  }
63
63
 
64
+ // Check if we're already in a transaction
65
+ const wasInTransaction = db.inTransaction
66
+
64
67
  try {
65
- // Start a transaction
66
- db.prepare('BEGIN').run()
68
+ // Start a transaction only if we're not already in one
69
+ if (!wasInTransaction) {
70
+ db.prepare('BEGIN').run()
71
+ }
67
72
 
68
73
  // Build and execute the CREATE TABLE statement
69
- let createTableSQL = `CREATE TABLE IF NOT EXISTS ${inputs.tableName} (`
74
+ let createTableSQL = `CREATE TABLE IF NOT EXISTS \`${inputs.tableName}\` (`
70
75
  let columnDefs = inputs.columns.map((column) => {
71
76
  const columnType = column.columnType ?? column.type
72
- let def = `${column.columnName} ${column.autoIncrement ? 'INTEGER' : getSqliteType(columnType)}`
77
+ let def = `\`${column.columnName}\` ${column.autoIncrement ? 'INTEGER' : getSqliteType(columnType)}`
73
78
  if (column.autoIncrement) {
74
79
  def += ' PRIMARY KEY AUTOINCREMENT NOT NULL'
75
80
  }
@@ -82,18 +87,22 @@ module.exports = {
82
87
  // Create indexes
83
88
  inputs.columns.forEach((column) => {
84
89
  if (column.unique && !column.autoIncrement) {
85
- const indexSQL = `CREATE UNIQUE INDEX IF NOT EXISTS idx_${inputs.tableName}_${column.columnName} ON ${inputs.tableName} (${column.columnName})`
90
+ const indexSQL = `CREATE UNIQUE INDEX IF NOT EXISTS \`idx_${inputs.tableName}_${column.columnName}\` ON \`${inputs.tableName}\` (\`${column.columnName}\`)`
86
91
  db.prepare(indexSQL).run()
87
92
  }
88
93
  })
89
94
 
90
- // Commit the transaction
91
- db.prepare('COMMIT').run()
95
+ // Commit the transaction only if we started it
96
+ if (!wasInTransaction) {
97
+ db.prepare('COMMIT').run()
98
+ }
92
99
 
93
100
  return exits.success()
94
101
  } catch (error) {
95
- // If there's an error, roll back the transaction
96
- db.prepare('ROLLBACK').run()
102
+ // If there's an error, roll back the transaction (only if we started it)
103
+ if (!wasInTransaction) {
104
+ db.prepare('ROLLBACK').run()
105
+ }
97
106
  return exits.error(
98
107
  new Error(`Error defining table ${inputs.tableName}: ${error.message}`)
99
108
  )
@@ -62,25 +62,36 @@ module.exports = {
62
62
 
63
63
  const db = inputs.connection
64
64
 
65
+ // Check if we're already in a transaction
66
+ const wasInTransaction = db.inTransaction
67
+
65
68
  try {
66
- // Start a transaction
67
- db.exec('BEGIN TRANSACTION')
69
+ // Start a transaction only if we're not already in one
70
+ if (!wasInTransaction) {
71
+ db.exec('BEGIN TRANSACTION')
72
+ }
68
73
 
69
74
  let phRecords
70
75
  if (isFetchEnabled) {
71
76
  // Fetch matching records before deletion
72
- const selectSql = `SELECT * FROM ${tableName} WHERE ${sqliteWhere}`
77
+ const selectSql = sqliteWhere
78
+ ? `SELECT * FROM \`${tableName}\` WHERE ${sqliteWhere}`
79
+ : `SELECT * FROM \`${tableName}\``
73
80
  const selectStmt = db.prepare(selectSql)
74
81
  phRecords = selectStmt.all()
75
82
  }
76
83
 
77
84
  // Perform the deletion
78
- const deleteSql = `DELETE FROM ${tableName} WHERE ${sqliteWhere}`
85
+ const deleteSql = sqliteWhere
86
+ ? `DELETE FROM \`${tableName}\` WHERE ${sqliteWhere}`
87
+ : `DELETE FROM \`${tableName}\``
79
88
  const deleteStmt = db.prepare(deleteSql)
80
89
  const deleteInfo = deleteStmt.run()
81
90
 
82
- // Commit the transaction
83
- db.exec('COMMIT')
91
+ // Commit the transaction only if we started it
92
+ if (!wasInTransaction) {
93
+ db.exec('COMMIT')
94
+ }
84
95
 
85
96
  if (!isFetchEnabled) {
86
97
  return exits.success()
@@ -93,8 +104,10 @@ module.exports = {
93
104
 
94
105
  return exits.success(phRecords)
95
106
  } catch (err) {
96
- // Rollback the transaction in case of error
97
- db.exec('ROLLBACK')
107
+ // Rollback the transaction in case of error (only if we started it)
108
+ if (!wasInTransaction) {
109
+ db.exec('ROLLBACK')
110
+ }
98
111
  return exits.error(err)
99
112
  }
100
113
  }
@@ -24,8 +24,8 @@ module.exports = {
24
24
  const db = inputs.connection
25
25
 
26
26
  try {
27
- // SQL to drop the table
28
- const dropTableSQL = `DROP TABLE IF EXISTS ${inputs.tableName}`
27
+ // SQL to drop the table (properly escape the table name)
28
+ const dropTableSQL = `DROP TABLE IF EXISTS \`${inputs.tableName}\``
29
29
 
30
30
  // Execute the drop table operation
31
31
  db.prepare(dropTableSQL).run()
@@ -57,12 +57,12 @@ module.exports = {
57
57
 
58
58
  // Handle SELECT clause
59
59
  if (s3q.criteria.select) {
60
- sqlQuery += s3q.criteria.select.join(', ')
60
+ sqlQuery += s3q.criteria.select.map((col) => `\`${col}\``).join(', ')
61
61
  } else {
62
62
  sqlQuery += '*'
63
63
  }
64
64
 
65
- sqlQuery += ` FROM ${tableName}`
65
+ sqlQuery += ` FROM \`${tableName}\``
66
66
 
67
67
  // Handle WHERE clause
68
68
  const whereClause = buildSqliteWhereClause(
@@ -79,7 +79,7 @@ module.exports = {
79
79
  const sortClauses = s3q.criteria.sort.map((sortObj) => {
80
80
  const key = Object.keys(sortObj)[0]
81
81
  const direction = sortObj[key] === 'ASC' ? 'ASC' : 'DESC'
82
- return `${key} ${direction}`
82
+ return `\`${key}\` ${direction}`
83
83
  })
84
84
  sqlQuery += ` ORDER BY ${sortClauses.join(', ')}`
85
85
  }