sails-sqlite 0.0.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 (48) hide show
  1. package/.github/FUNDING.yml +1 -0
  2. package/.github/workflows/prettier.yml +16 -0
  3. package/.github/workflows/test.yml +16 -0
  4. package/.husky/pre-commit +1 -0
  5. package/.prettierrc.js +5 -0
  6. package/CHANGELOG.md +161 -0
  7. package/LICENSE +21 -0
  8. package/README.md +247 -0
  9. package/lib/index.js +1104 -0
  10. package/lib/private/build-std-adapter-method.js +69 -0
  11. package/lib/private/constants/connection.input.js +15 -0
  12. package/lib/private/constants/dry-orm.input.js +23 -0
  13. package/lib/private/constants/meta.input.js +14 -0
  14. package/lib/private/constants/not-unique.exit.js +16 -0
  15. package/lib/private/constants/query.input.js +15 -0
  16. package/lib/private/constants/table-name.input.js +12 -0
  17. package/lib/private/machines/avg-records.js +74 -0
  18. package/lib/private/machines/begin-transaction.js +51 -0
  19. package/lib/private/machines/commit-transaction.js +50 -0
  20. package/lib/private/machines/count-records.js +78 -0
  21. package/lib/private/machines/create-each-record.js +163 -0
  22. package/lib/private/machines/create-manager.js +174 -0
  23. package/lib/private/machines/create-record.js +126 -0
  24. package/lib/private/machines/define-physical-model.js +111 -0
  25. package/lib/private/machines/destroy-manager.js +87 -0
  26. package/lib/private/machines/destroy-records.js +114 -0
  27. package/lib/private/machines/drop-physical-model.js +51 -0
  28. package/lib/private/machines/find-records.js +120 -0
  29. package/lib/private/machines/get-connection.js +54 -0
  30. package/lib/private/machines/join.js +259 -0
  31. package/lib/private/machines/lease-connection.js +58 -0
  32. package/lib/private/machines/private/build-sqlite-where-clause.js +91 -0
  33. package/lib/private/machines/private/compile-statement.js +334 -0
  34. package/lib/private/machines/private/generate-join-sql-query.js +385 -0
  35. package/lib/private/machines/private/process-each-record.js +106 -0
  36. package/lib/private/machines/private/process-native-error.js +104 -0
  37. package/lib/private/machines/private/process-native-record.js +104 -0
  38. package/lib/private/machines/private/reify-values-to-set.js +83 -0
  39. package/lib/private/machines/release-connection.js +70 -0
  40. package/lib/private/machines/rollback-transaction.js +50 -0
  41. package/lib/private/machines/set-physical-sequence.js +77 -0
  42. package/lib/private/machines/sum-records.js +75 -0
  43. package/lib/private/machines/update-records.js +162 -0
  44. package/lib/private/machines/verify-model-def.js +38 -0
  45. package/package.json +58 -5
  46. package/tests/index.js +88 -0
  47. package/tests/runner.js +99 -0
  48. package/tests/transaction.test.js +562 -0
package/lib/index.js ADDED
@@ -0,0 +1,1104 @@
1
+ const Database = require('better-sqlite3')
2
+ const Machine = require('machine')
3
+ const buildStdAdapterMethod = require('./private/build-std-adapter-method')
4
+
5
+ /**
6
+ * Module constants
7
+ */
8
+
9
+ // Private var to cache dry machine definitions.
10
+ // > This is set up in a dictionary instead of as separate variables
11
+ // > just to allow the code below to be a bit easier to read
12
+ const DRY_MACHINES = {
13
+ verifyModelDef: require('./private/machines/verify-model-def'),
14
+ createManager: require('./private/machines/create-manager'),
15
+ destroyManager: require('./private/machines/destroy-manager'),
16
+ getConnection: require('./private/machines/get-connection'),
17
+ releaseConnection: require('./private/machines/release-connection'),
18
+ definePhysicalModel: require('./private/machines/define-physical-model'),
19
+ dropPhysicalModel: require('./private/machines/drop-physical-model'),
20
+ setPhysicalSequence: require('./private/machines/set-physical-sequence'),
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')
26
+ }
27
+
28
+ const WET_MACHINES = Object.fromEntries(
29
+ Object.entries(DRY_MACHINES).map(([methodName, def]) => [
30
+ methodName,
31
+ Machine.build(def)
32
+ ])
33
+ )
34
+
35
+ /**
36
+ * Module state
37
+ */
38
+
39
+ // Private var to track of all the datastores that use this adapter. In order for your adapter
40
+ // to be able to connect to the database, you'll want to expose this var publicly as well.
41
+ // (See the `registerDatastore()` method for info on the format of each datastore entry herein.)
42
+ //
43
+ // > Note that this approach of process global state will be changing in an upcoming version of
44
+ // > the Waterline adapter spec (a breaking change). But if you follow the conventions laid out
45
+ // > below in this adapter template, future upgrades should be a breeze.
46
+ const registeredDsEntries = {}
47
+
48
+ // Keep track of all the model definitions registered by the adapter (for the entire Node process).
49
+ // (indexed by the model's `identity` -- NOT by its `tableName`!!)
50
+ const registeredDryModels = {}
51
+
52
+ /**
53
+ * ███████╗ █████╗ ██╗██╗ ███████╗ ███████╗ ██████╗ ██╗ ██╗████████╗███████╗
54
+ * ██╔════╝██╔══██╗██║██║ ██╔════╝ ██╔════╝██╔═══██╗██║ ██║╚══██╔══╝██╔════╝
55
+ * ███████╗███████║██║██║ ███████╗█████╗███████╗██║ ██║██║ ██║ ██║ █████╗
56
+ * ╚════██║██╔══██║██║██║ ╚════██║╚════╝╚════██║██║▄▄ ██║██║ ██║ ██║ ██╔══╝
57
+ * ███████║██║ ██║██║███████╗███████║ ███████║╚██████╔╝███████╗██║ ██║ ███████╗
58
+ * ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝ ╚══════╝ ╚══▀▀═╝ ╚══════╝╚═╝ ╚═╝ ╚══════╝
59
+ * (sails-sqlite)
60
+ *
61
+ * Sails.js/Waterline adapter for SQLite database.
62
+ *
63
+ * > Most of the methods below are optional.
64
+ * >
65
+ * > If you don't need / can't get to every method, just implement
66
+ * > what you have time for. The other methods will only fail if
67
+ * > you try to call them!
68
+ * >
69
+ * > For many adapters, this file is all you need. For very complex adapters, you may need more flexibility.
70
+ * > In any case, it's probably a good idea to start with one file and refactor only if necessary.
71
+ * > If you do go that route, it's conventional in Node to create a `./lib` directory for your private submodules
72
+ * > and `require` them at the top of this file with other dependencies. e.g.:
73
+ * > ```
74
+ * > var updateMethod = require('./lib/update');
75
+ * > ```
76
+ *
77
+ * @type {Dictionary}
78
+ */
79
+
80
+ // Build & expose the adapter definition.
81
+ module.exports = {
82
+ // The identity of this adapter, to be referenced by datastore configurations in a Sails app.
83
+ identity: 'sails-sqlite',
84
+
85
+ // Waterline Adapter API Version
86
+ adapterApiVersion: 1,
87
+
88
+ // Default configuration for connections
89
+ defaults: {
90
+ schema: false,
91
+ url: 'db/data.db',
92
+ pragmas: {
93
+ journal_mode: 'WAL'
94
+ }
95
+ },
96
+
97
+ // ╔═╗═╗ ╦╔═╗╔═╗╔═╗╔═╗ ┌─┐┬─┐┬┬ ┬┌─┐┌┬┐┌─┐
98
+ // ║╣ ╔╩╦╝╠═╝║ ║╚═╗║╣ ├─┘├┬┘│└┐┌┘├─┤ │ ├┤
99
+ // ╚═╝╩ ╚═╩ ╚═╝╚═╝╚═╝ ┴ ┴└─┴ └┘ ┴ ┴ ┴ └─┘
100
+ // ┌┬┐┌─┐┌┬┐┌─┐┌─┐┌┬┐┌─┐┬─┐┌─┐┌─┐
101
+ // ││├─┤ │ ├─┤└─┐ │ │ │├┬┘├┤ └─┐
102
+ // ─┴┘┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘┴└─└─┘└─┘
103
+ // This allows outside access to the datastores, for use in advanced ORM methods like `.runTransaction()`.
104
+ datastores: registeredDsEntries,
105
+
106
+ // Also give the driver a `Database` property, so that it provides access
107
+ // to the better-sqlite3 Database class for Node.js. (See https://github.com/WiseLibs/better-sqlite3)
108
+ Database: Database,
109
+
110
+ //////////////////////////////////////////////////////////////////////////////////////////////////
111
+ // ██╗ ██╗███████╗███████╗ ██████╗██╗ ██╗ ██████╗██╗ ███████╗ //
112
+ // ██║ ██║██╔════╝██╔════╝██╔════╝╚██╗ ██╔╝██╔════╝██║ ██╔════╝ //
113
+ // ██║ ██║█████╗ █████╗ ██║ ╚████╔╝ ██║ ██║ █████╗ //
114
+ // ██║ ██║██╔══╝ ██╔══╝ ██║ ╚██╔╝ ██║ ██║ ██╔══╝ //
115
+ // ███████╗██║██║ ███████╗╚██████╗ ██║ ╚██████╗███████╗███████╗ //
116
+ // ╚══════╝╚═╝╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═════╝╚══════╝╚══════╝ //
117
+ // //
118
+ // Lifecycle adapter methods: //
119
+ // Methods related to setting up and tearing down; registering/un-registering datastores. //
120
+ //////////////////////////////////////////////////////////////////////////////////////////////////
121
+
122
+ /**
123
+ * ╦═╗╔═╗╔═╗╦╔═╗╔╦╗╔═╗╦═╗ ┌┬┐┌─┐┌┬┐┌─┐┌─┐┌┬┐┌─┐┬─┐┌─┐
124
+ * ╠╦╝║╣ ║ ╦║╚═╗ ║ ║╣ ╠╦╝ ││├─┤ │ ├─┤└─┐ │ │ │├┬┘├┤
125
+ * ╩╚═╚═╝╚═╝╩╚═╝ ╩ ╚═╝╩╚═ ─┴┘┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘┴└─└─┘
126
+ *
127
+ * Register a new datastore with this adapter. This usually involves creating a new
128
+ * connection manager (e.g. SQLite database instance) for the underlying database layer.
129
+ *
130
+ * > Waterline calls this method once for every datastore that is configured to use this adapter.
131
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
132
+ * @param {Dictionary} dsConfig »-> Dictionary (plain JavaScript object) of configuration options for this datastore (e.g. storage, mode, etc.)
133
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
134
+ * @param {Dictionary} models »-> Dictionary of model definitions using this datastore.
135
+ * ˚¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\
136
+ * ˙ [identity]: {Dictionary} :: Info about a model using this datastore.
137
+ * ˚¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\
138
+ * ˙ primaryKey: {String} :: The name of the primary key attribute.
139
+ * ˙ identity: {String} :: The model's `identity`.
140
+ * ˙ tableName: {String} :: The model's `tableName`.
141
+ * ˙ definition: {Dictionary} :: The model's attribute definitions.
142
+ * ˚¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\
143
+ * ˙ [attribute]: {Dictionary} :: Info about an attribute.
144
+ * ˚¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\
145
+ * ˙ type: {String} :: The attribute's type.
146
+ * ˙ columnName: {String} :: The attribute's column name.
147
+ * ˙ required: {Boolean?} :: Whether the attribute is required.
148
+ * ˙ ... :: Other attribute properties.
149
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
150
+ * @param {Function} done »-> A callback function which should be triggered by this implementation after successfully registering this datastore, or if an error is encountered.
151
+ * @param {Error?} err <-« An Error instance, if something went wrong. (Otherwise `undefined`.)
152
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
153
+ */
154
+ registerDatastore: function registerDatastore(dsConfig, models, done) {
155
+ // Grab the unique name for this datastore for easy access below.
156
+ const datastoreName = dsConfig.identity
157
+
158
+ // Some sanity checks:
159
+ if (!datastoreName) {
160
+ return done(
161
+ new Error(
162
+ 'Consistency violation: A datastore should contain an "identity" property: a special identifier that uniquely identifies it across this app. This should have been provided by Waterline core! If you are seeing this message, there could be a bug in Waterline, or the datastore could have become corrupted by userland code, or other code in this adapter. If you determine that this is a Waterline bug, please report this at http://sailsjs.com/bugs.'
163
+ )
164
+ )
165
+ }
166
+
167
+ if (registeredDsEntries[datastoreName]) {
168
+ return done(
169
+ new Error(
170
+ 'Consistency violation: Cannot register datastore: `' +
171
+ datastoreName +
172
+ '`, because it is already registered with this adapter! This could be due to an unexpected race condition in userland code (e.g. attempting to initialize Waterline more than once), or it could be due to a bug in this adapter. (If you get stumped, reach out at http://sailsjs.com/support.)'
173
+ )
174
+ )
175
+ }
176
+
177
+ // ╔═╗╦═╗╔═╗╔═╗╔╦╗╔═╗ ┌┬┐┌─┐┌┐┌┌─┐┌─┐┌─┐┬─┐
178
+ // ║ ╠╦╝║╣ ╠═╣ ║ ║╣ │││├─┤│││├─┤│ ┬├┤ ├┬┘
179
+ // ╚═╝╩╚═╚═╝╩ ╩ ╩ ╚═╝ ┴ ┴┴ ┴┘└┘┴ ┴└─┘└─┘┴└─
180
+ // Build a "connection manager" -- an object that contains all of the state for this datastore.
181
+ // For SQLite, this is simpler than many other databases because SQLite is serverless and
182
+ // doesn't require connection pooling. Our manager will be a single Database instance from
183
+ // the better-sqlite3 library. This instance represents a connection to a SQLite database file.
184
+ // We'll use this instance for all operations on this datastore. The actual form of the
185
+ // manager is completely dependent on this adapter. In other words, it is custom and database-specific.
186
+ // This is where we'll also set up any SQLite-specific configurations, like pragmas for performance tuning.
187
+ WET_MACHINES.createManager({
188
+ connectionString: dsConfig.url,
189
+ meta: Object.fromEntries(
190
+ Object.entries(dsConfig).filter(
191
+ ([key]) => !['adapter', 'url', 'identity', 'schema'].includes(key)
192
+ )
193
+ )
194
+ }).switch({
195
+ error: function (err) {
196
+ return done(
197
+ new Error(
198
+ 'Consistency violation: Unexpected error creating db connection manager:\n```\n' +
199
+ err.stack +
200
+ '\n```'
201
+ )
202
+ )
203
+ },
204
+ success: function (report) {
205
+ try {
206
+ const manager = report.manager
207
+ // ╔╦╗╦═╗╔═╗╔═╗╦╔═ ┌┬┐┌─┐ ┌─┐┌┐┌┌┬┐┬─┐┬ ┬
208
+ // ║ ╠╦╝╠═╣║ ╠╩╗ ││└─┐ ├┤ │││ │ ├┬┘└┬┘
209
+ // ╩ ╩╚═╩ ╩╚═╝╩ ╩ ─┴┘└─┘ └─┘┘└┘ ┴ ┴└─ ┴
210
+ // ┌─ ┌┬┐┌─┐┌┬┐┌─┐┌─┐┌┬┐┌─┐┬─┐┌─┐ ┌─┐┌┐┌┌┬┐┬─┐┬ ┬ ─┐
211
+ // │ ││├─┤ │ ├─┤└─┐ │ │ │├┬┘├┤ ├┤ │││ │ ├┬┘└┬┘ │
212
+ // └─ ─┴┘┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘┴└─└─┘ └─┘┘└┘ ┴ ┴└─ ┴ ─┘
213
+ // Save information about the datastore to the `datastores` dictionary, keyed under
214
+ // the datastore's unique name. The information should itself be in the form of a
215
+ // dictionary (plain JavaScript object), and have three keys:
216
+ //
217
+ // `manager`: The database-specific "connection manager" that we just built above.
218
+ //
219
+ // `config : Configuration options for the datastore. Should be passed straight through
220
+ // from what was provided as the `dsConfig` argument to this method.
221
+ //
222
+ // `driver` : Optional. A reference to a stateless, underlying Node-Machine driver.
223
+ // (For instance `machinepack-postgresql` for the `sails-postgresql` adapter.)
224
+ // Note that this stateless, standardized driver will be merged into the main
225
+ // concept of an adapter in future versions of the Waterline adapter spec.
226
+ // (See https://github.com/node-machine/driver-interface for more informaiton.)
227
+ //
228
+ registeredDsEntries[datastoreName] = {
229
+ config: dsConfig,
230
+ manager,
231
+ driver: {
232
+ createManager: WET_MACHINES.createManager,
233
+ destroyManager: WET_MACHINES.destroyManager,
234
+ getConnection: WET_MACHINES.getConnection,
235
+ releaseConnection: WET_MACHINES.releaseConnection,
236
+ Database
237
+ }
238
+ }
239
+
240
+ // ╔╦╗╦═╗╔═╗╔═╗╦╔═ ┌─┐┬ ┬ ┌┬┐┌─┐┌┬┐┌─┐┬ ┌─┐
241
+ // ║ ╠╦╝╠═╣║ ╠╩╗ ├─┘├─┤ ││││ │ ││├┤ │ └─┐
242
+ // ╩ ╩╚═╩ ╩╚═╝╩ ╩ ┴ ┴ ┴ ┴ ┴└─┘─┴┘└─┘┴─┘└─┘
243
+ // Track physical models for SQLite tables.
244
+ // This step maps Waterline models to their corresponding SQLite table structures.
245
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
246
+ // TODO: Consider implementing a more direct method to access model information,
247
+ // potentially through an ORM accessor function, to simplify this process in future versions.
248
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
249
+
250
+ for (const [modelIdentity, modelInfo] of Object.entries(models)) {
251
+ // Uncomment for debugging:
252
+ // console.log(`In datastore: '${datastoreName}' - Tracking physical model: '${modelIdentity}' (tableName: '${modelInfo.tableName}')`);
253
+
254
+ if (registeredDryModels[modelIdentity]) {
255
+ throw new Error(
256
+ `Consistency violation: Cannot register model: '${modelIdentity}', because it is already registered with this adapter! ` +
257
+ `This could be due to an unexpected race condition in userland code (e.g. attempting to initialize multiple ORM instances at the same time), ` +
258
+ `or it could be due to a bug in this adapter. If you need assistance, please reach out at https://sailsjs.com/support.`
259
+ )
260
+ }
261
+
262
+ const modelDefinition = modelInfo.definition || modelInfo.attributes
263
+
264
+ registeredDryModels[modelIdentity] = {
265
+ identity: modelIdentity,
266
+ primaryKey: modelInfo.primaryKey,
267
+ definition: modelDefinition,
268
+ attributes: modelDefinition,
269
+ tableName: modelInfo.tableName,
270
+ identity: modelInfo.identity,
271
+ datastore: datastoreName
272
+ }
273
+
274
+ // Uncomment for detailed debugging:
275
+ // console.log('Model Info:', JSON.stringify(modelInfo, null, 2));
276
+ }
277
+ } catch (err) {
278
+ return done(err)
279
+ }
280
+ // Inform Waterline that the datastore was registered successfully.
281
+ return done(undefined, report.meta)
282
+ } //•-success>
283
+ }) //createManager()>
284
+ },
285
+ /**
286
+ * ╔╦╗╔═╗╔═╗╦═╗╔╦╗╔═╗╦ ╦╔╗╔
287
+ * ║ ║╣ ╠═╣╠╦╝ ║║║ ║║║║║║║
288
+ * ╩ ╚═╝╩ ╩╩╚══╩╝╚═╝╚╩╝╝╚╝
289
+ * Tear down (un-register) a datastore.
290
+ *
291
+ * Fired when a datastore is unregistered. Typically called once for
292
+ * each relevant datastore when the server is killed, or when Waterline
293
+ * is shut down after a series of tests. Useful for destroying the manager
294
+ * (i.e. terminating any remaining open connections, etc.).
295
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
296
+ * @param {String} datastoreName The unique name (identity) of the datastore to un-register.
297
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
298
+ * @param {Function} done Callback
299
+ * @param {Error?}
300
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
301
+ */
302
+ teardown: function (datastoreName, done) {
303
+ // Look up the datastore entry (manager/driver/config).
304
+ var dsEntry = registeredDsEntries[datastoreName]
305
+
306
+ // Sanity checks:
307
+ if (!datastoreName) {
308
+ return done(
309
+ new Error(
310
+ 'Consistency violation: Internal error in Waterline: Adapter received unexpected falsey datastore name (`' +
311
+ datastoreName +
312
+ "`)! Can't look up a DS entry from this adapter with that... (Please report this error at http://sailsjs.com/bugs.)"
313
+ )
314
+ )
315
+ }
316
+ if (dsEntry === undefined) {
317
+ return done(
318
+ new Error(
319
+ 'Consistency violation: Attempting to tear down a datastore (`' +
320
+ datastoreName +
321
+ '`) which is not currently registered with this adapter. This is usually due to a race condition in userland code (e.g. attempting to tear down the same ORM instance more than once), or it could be due to a bug in this adapter. (If you get stumped, reach out at http://sailsjs.com/support.)'
322
+ )
323
+ )
324
+ }
325
+ if (!dsEntry.manager) {
326
+ return done(
327
+ new Error(
328
+ 'Consistency violation: Missing manager for this datastore. (This datastore may already be in the process of being destroyed.)'
329
+ )
330
+ )
331
+ }
332
+
333
+ // ╔╦╗╔═╗╔═╗╔╦╗╦═╗╔═╗╦ ╦ ┌┬┐┌─┐┌┐┌┌─┐┌─┐┌─┐┬─┐
334
+ // ║║║╣ ╚═╗ ║ ╠╦╝║ ║╚╦╝ │││├─┤│││├─┤│ ┬├┤ ├┬┘
335
+ // ═╩╝╚═╝╚═╝ ╩ ╩╚═╚═╝ ╩ ┴ ┴┴ ┴┘└┘┴ ┴└─┘└─┘┴└─
336
+ // Destroy the manager.
337
+ WET_MACHINES.destroyManager({ manager: dsEntry.manager }).switch({
338
+ error: function (err) {
339
+ return done(
340
+ new Error(
341
+ 'Encountered unexpected error when attempting to destroy the connection manager.\n\n```\n' +
342
+ err.stack +
343
+ '\n```'
344
+ )
345
+ )
346
+ },
347
+ success: function (report) {
348
+ // ╦ ╦╔╗╔ ╔╦╗╦═╗╔═╗╔═╗╦╔═ ┌┬┐┌─┐ ┌─┐┌┐┌┌┬┐┬─┐┬ ┬
349
+ // ║ ║║║║───║ ╠╦╝╠═╣║ ╠╩╗ ││└─┐ ├┤ │││ │ ├┬┘└┬┘
350
+ // ╚═╝╝╚╝ ╩ ╩╚═╩ ╩╚═╝╩ ╩ ─┴┘└─┘ └─┘┘└┘ ┴ ┴└─ ┴
351
+ // ┌─ ┌┬┐┌─┐┌┬┐┌─┐┌─┐┌┬┐┌─┐┬─┐┌─┐ ┌─┐┌┐┌┌┬┐┬─┐┬ ┬ ─┐
352
+ // │ ││├─┤ │ ├─┤└─┐ │ │ │├┬┘├┤ ├┤ │││ │ ├┬┘└┬┘ │
353
+ // └─ ─┴┘┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘┴└─└─┘ └─┘┘└┘ ┴ ┴└─ ┴ ─┘
354
+ // Now, un-register the datastore, as well as any registered physical model
355
+ // definitions that use it.
356
+ try {
357
+ delete registeredDsEntries[datastoreName]
358
+
359
+ Object.keys(registeredDryModels).forEach((modelIdentity) => {
360
+ if (
361
+ registeredDryModels[modelIdentity].datastore === datastoreName
362
+ ) {
363
+ delete registeredDryModels[modelIdentity]
364
+ }
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
+ }
374
+ } catch (err) {
375
+ return done(err)
376
+ }
377
+
378
+ // Inform Waterline that we're done, and that everything went as expected.
379
+ return done(undefined, report.meta)
380
+ } //•-success>
381
+ }) //destroyManager()>
382
+ },
383
+ /**
384
+ * ╔═╗╦═╗╔═╗╔═╗╔╦╗╔═╗ ╔╦╗╔═╗╔╗╔╔═╗╔═╗╔═╗╦═╗
385
+ * ║ ╠╦╝║╣ ╠═╣ ║ ║╣ ║║║╠═╣║║║╠═╣║ ╦║╣ ╠╦╝
386
+ * ╚═╝╩╚═╚═╝╩ ╩ ╩ ╚═╝ ╩ ╩╩ ╩╝╚╝╩ ╩╚═╝╚═╝╩╚═
387
+ *
388
+ * > https://github.com/node-machine/driver-interface/blob/master/layers/connectable/create-manager.js
389
+ */
390
+ createManager: DRY_MACHINES.createManager,
391
+
392
+ /**
393
+ * ╔╦╗╔═╗╔═╗╔╦╗╦═╗╔═╗╦ ╦ ╔╦╗╔═╗╔╗╔╔═╗╔═╗╔═╗╦═╗
394
+ * ║║║╣ ╚═╗ ║ ╠╦╝║ ║╚╦╝ ║║║╠═╣║║║╠═╣║ ╦║╣ ╠╦╝
395
+ * ═╩╝╚═╝╚═╝ ╩ ╩╚═╚═╝ ╩ ╩ ╩╩ ╩╝╚╝╩ ╩╚═╝╚═╝╩╚═
396
+ *
397
+ * > https://github.com/node-machine/driver-interface/blob/master/layers/connectable/destroy-manager.js
398
+ */
399
+ destroyManager: DRY_MACHINES.destroyManager,
400
+
401
+ /**
402
+ * ╔═╗╔═╗╔╦╗ ╔═╗╔═╗╔╗╔╔╗╔╔═╗╔═╗╔╦╗╦╔═╗╔╗╔
403
+ * ║ ╦║╣ ║ ║ ║ ║║║║║║║║╣ ║ ║ ║║ ║║║║
404
+ * ╚═╝╚═╝ ╩ ╚═╝╚═╝╝╚╝╝╚╝╚═╝╚═╝ ╩ ╩╚═╝╝╚╝
405
+ *
406
+ * > https://github.com/node-machine/driver-interface/blob/master/layers/connectable/get-connection.js
407
+ */
408
+ getConnection: DRY_MACHINES.getConnection,
409
+
410
+ /**
411
+ * ╦═╗╔═╗╦ ╔═╗╔═╗╔═╗╔═╗ ╔═╗╔═╗╔╗╔╔╗╔╔═╗╔═╗╔╦╗╦╔═╗╔╗╔
412
+ * ╠╦╝║╣ ║ ║╣ ╠═╣╚═╗║╣ ║ ║ ║║║║║║║║╣ ║ ║ ║║ ║║║║
413
+ * ╩╚═╚═╝╩═╝╚═╝╩ ╩╚═╝╚═╝ ╚═╝╚═╝╝╚╝╝╚╝╚═╝╚═╝ ╩ ╩╚═╝╝╚╝
414
+ *
415
+ * > https://github.com/node-machine/driver-interface/blob/master/layers/connectable/release-connection.js
416
+ */
417
+ releaseConnection: DRY_MACHINES.releaseConnection,
418
+
419
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
420
+ // ██╗ ██╗███████╗██████╗ ██╗███████╗██╗ ██╗ ███╗ ███╗ ██████╗ ██████╗ ███████╗██╗ ██████╗ ███████╗███████╗ //
421
+ // ██║ ██║██╔════╝██╔══██╗██║██╔════╝╚██╗ ██╔╝ ████╗ ████║██╔═══██╗██╔══██╗██╔════╝██║ ██╔══██╗██╔════╝██╔════╝ //
422
+ // ██║ ██║█████╗ ██████╔╝██║█████╗ ╚████╔╝ ██╔████╔██║██║ ██║██║ ██║█████╗ ██║ ██║ ██║█████╗ █████╗ //
423
+ // ╚██╗ ██╔╝██╔══╝ ██╔══██╗██║██╔══╝ ╚██╔╝ ██║╚██╔╝██║██║ ██║██║ ██║██╔══╝ ██║ ██║ ██║██╔══╝ ██╔══╝ //
424
+ // ╚████╔╝ ███████╗██║ ██║██║██║ ██║ ██║ ╚═╝ ██║╚██████╔╝██████╔╝███████╗███████╗ ██████╔╝███████╗██║ //
425
+ // ╚═══╝ ╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚══════╝╚═╝ //
426
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
427
+ verifyModelDef: DRY_MACHINES.verifyModelDef,
428
+
429
+ //////////////////////////////////////////////////////////////////////////////////////////////////
430
+ // ██████╗ ███╗ ███╗██╗ //
431
+ // ██╔══██╗████╗ ████║██║ //
432
+ // ██║ ██║██╔████╔██║██║ //
433
+ // ██║ ██║██║╚██╔╝██║██║ //
434
+ // ██████╔╝██║ ╚═╝ ██║███████╗ //
435
+ // ╚═════╝ ╚═╝ ╚═╝╚══════╝ //
436
+ // (D)ata (M)anipulation (L)anguage //
437
+ // //
438
+ // DML adapter methods: //
439
+ // Methods related to manipulating records stored in the database. //
440
+ //////////////////////////////////////////////////////////////////////////////////////////////////
441
+
442
+ /**
443
+ * ╔═╗╦═╗╔═╗╔═╗╔╦╗╔═╗
444
+ * ║ ╠╦╝║╣ ╠═╣ ║ ║╣
445
+ * ╚═╝╩╚═╚═╝╩ ╩ ╩ ╚═╝
446
+ * Create a new record.
447
+ *
448
+ * (e.g. add a new row to a SQL table, or a new document to a MongoDB collection.)
449
+ *
450
+ * > Note that depending on the value of `s3q.meta.fetch`,
451
+ * > you may be expected to return the physical record that was
452
+ * > created (a dictionary) as the second argument to the callback.
453
+ * > (Otherwise, exclude the 2nd argument or send back `undefined`.)
454
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
455
+ * @param {String} datastoreName The name of the datastore to perform the query on.
456
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
457
+ * @param {Dictionary} s3q The stage-3 query to perform.
458
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
459
+ * @param {Function} done Callback
460
+ * @param {Error?}
461
+ * @param {Dictionary?}
462
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
463
+ */
464
+ create: buildStdAdapterMethod(
465
+ require('./private/machines/create-record'),
466
+ WET_MACHINES,
467
+ registeredDsEntries,
468
+ registeredDryModels
469
+ ),
470
+ /**
471
+ * ╔═╗╦═╗╔═╗╔═╗╔╦╗╔═╗ ╔═╗╔═╗╔═╗╦ ╦
472
+ * ║ ╠╦╝║╣ ╠═╣ ║ ║╣ ║╣ ╠═╣║ ╠═╣
473
+ * ╚═╝╩╚═╚═╝╩ ╩ ╩ ╚═╝ ╚═╝╩ ╩╚═╝╩ ╩
474
+ * Create multiple new records.
475
+ *
476
+ * > Note that depending on the value of `query.meta.fetch`,
477
+ * > you may be expected to return the array of physical records
478
+ * > that were created as the second argument to the callback.
479
+ * > (Otherwise, exclude the 2nd argument or send back `undefined`.)
480
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
481
+ * @param {String} datastoreName The name of the datastore to perform the query on.
482
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
483
+ * @param {Dictionary} query The stage-3 query to perform.
484
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
485
+ * @param {Function} done Callback
486
+ * @param {Error?}
487
+ * @param {Array?}
488
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
489
+ */
490
+ createEach: buildStdAdapterMethod(
491
+ require('./private/machines/create-each-record'),
492
+ WET_MACHINES,
493
+ registeredDsEntries,
494
+ registeredDryModels
495
+ ),
496
+ /**
497
+ * ╦ ╦╔═╗╔╦╗╔═╗╔╦╗╔═╗
498
+ * ║ ║╠═╝ ║║╠═╣ ║ ║╣
499
+ * ╚═╝╩ ═╩╝╩ ╩ ╩ ╚═╝
500
+ * Update matching records.
501
+ *
502
+ * > Note that depending on the value of `query.meta.fetch`,
503
+ * > you may be expected to return the array of physical records
504
+ * > that were updated as the second argument to the callback.
505
+ * > (Otherwise, exclude the 2nd argument or send back `undefined`.)
506
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
507
+ * @param {String} datastoreName The name of the datastore to perform the query on.
508
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
509
+ * @param {Dictionary} query The stage-3 query to perform.
510
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
511
+ * @param {Function} done Callback
512
+ * @param {Error?}
513
+ * @param {Array?}
514
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
515
+ */
516
+ update: buildStdAdapterMethod(
517
+ require('./private/machines/update-records'),
518
+ WET_MACHINES,
519
+ registeredDsEntries,
520
+ registeredDryModels
521
+ ),
522
+ /**
523
+ * ╔╦╗╔═╗╔═╗╔╦╗╦═╗╔═╗╦ ╦
524
+ * ║║║╣ ╚═╗ ║ ╠╦╝║ ║╚╦╝
525
+ * ═╩╝╚═╝╚═╝ ╩ ╩╚═╚═╝ ╩
526
+ * Destroy one or more records.
527
+ *
528
+ * > Note that depending on the value of `query.meta.fetch`,
529
+ * > you may be expected to return the array of physical records
530
+ * > that were destroyed as the second argument to the callback.
531
+ * > (Otherwise, exclude the 2nd argument or send back `undefined`.)
532
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
533
+ * @param {String} datastoreName The name of the datastore to perform the query on.
534
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
535
+ * @param {Dictionary} query The stage-3 query to perform.
536
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
537
+ * @param {Function} done Callback
538
+ * @param {Error?}
539
+ * @param {Array?}
540
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
541
+ */
542
+ destroy: buildStdAdapterMethod(
543
+ require('./private/machines/destroy-records'),
544
+ WET_MACHINES,
545
+ registeredDsEntries,
546
+ registeredDryModels
547
+ ),
548
+
549
+ // ╔╗╔╔═╗╔╦╗╦╦ ╦╔═╗ ┬┌─┐┬┌┐┌ ┌─┐┬ ┬┌─┐┌─┐┌─┐┬─┐┌┬┐
550
+ // ║║║╠═╣ ║ ║╚╗╔╝║╣ ││ │││││ └─┐│ │├─┘├─┘│ │├┬┘ │
551
+ // ╝╚╝╩ ╩ ╩ ╩ ╚╝ ╚═╝ └┘└─┘┴┘└┘ └─┘└─┘┴ ┴ └─┘┴└─ ┴
552
+ // Build up native joins to run on the adapter.
553
+ join: buildStdAdapterMethod(
554
+ require('./private/machines/join'),
555
+ WET_MACHINES,
556
+ registeredDsEntries,
557
+ registeredDryModels
558
+ ),
559
+ //////////////////////////////////////////////////////////////////////////////////////////////////
560
+ // ██████╗ ██████╗ ██╗ //
561
+ // ██╔══██╗██╔═══██╗██║ //
562
+ // ██║ ██║██║ ██║██║ //
563
+ // ██║ ██║██║▄▄ ██║██║ //
564
+ // ██████╔╝╚██████╔╝███████╗ //
565
+ // ╚═════╝ ╚══▀▀═╝ ╚══════╝ //
566
+ // (D)ata (Q)uery (L)anguage //
567
+ // //
568
+ // DQL adapter methods: //
569
+ // Methods related to fetching information from the database (e.g. finding stored records). //
570
+ //////////////////////////////////////////////////////////////////////////////////////////////////
571
+
572
+ /**
573
+ * ╔═╗╦╔╗╔╔╦╗
574
+ * ╠╣ ║║║║ ║║
575
+ * ╚ ╩╝╚╝═╩╝
576
+ * Find matching records.
577
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
578
+ * @param {String} datastoreName The name of the datastore to perform the query on.
579
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
580
+ * @param {Dictionary} query The stage-3 query to perform.
581
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
582
+ * @param {Function} done Callback
583
+ * @param {Error?}
584
+ * @param {Array} [matching physical records]
585
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
586
+ */
587
+ find: buildStdAdapterMethod(
588
+ require('./private/machines/find-records'),
589
+ WET_MACHINES,
590
+ registeredDsEntries,
591
+ registeredDryModels
592
+ ),
593
+
594
+ /**
595
+ * ╔═╗╔═╗╦ ╦╔╗╔╔╦╗
596
+ * ║ ║ ║║ ║║║║ ║
597
+ * ╚═╝╚═╝╚═╝╝╚╝ ╩
598
+ * Get the number of matching records.
599
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
600
+ * @param {String} datastoreName The name of the datastore to perform the query on.
601
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
602
+ * @param {Dictionary} query The stage-3 query to perform.
603
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
604
+ * @param {Function} done Callback
605
+ * @param {Error?}
606
+ * @param {Number} [the number of matching records]
607
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
608
+ */
609
+ count: buildStdAdapterMethod(
610
+ require('./private/machines/count-records'),
611
+ WET_MACHINES,
612
+ registeredDsEntries,
613
+ registeredDryModels
614
+ ),
615
+
616
+ /**
617
+ * ╔═╗╦ ╦╔╦╗
618
+ * ╚═╗║ ║║║║
619
+ * ╚═╝╚═╝╩ ╩
620
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
621
+ * @param {String} datastoreName The name of the datastore to perform the query on.
622
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
623
+ * @param {Dictionary} query The stage-3 query to perform.
624
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
625
+ * @param {Function} done Callback
626
+ * @param {Error?}
627
+ * @param {Number} [the sum]
628
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
629
+ */
630
+ sum: buildStdAdapterMethod(
631
+ require('./private/machines/sum-records'),
632
+ WET_MACHINES,
633
+ registeredDsEntries,
634
+ registeredDryModels
635
+ ),
636
+
637
+ /**
638
+ * ╔═╗╦ ╦╔═╗
639
+ * ╠═╣╚╗╔╝║ ╦
640
+ * ╩ ╩ ╚╝ ╚═╝
641
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
642
+ * @param {String} datastoreName The name of the datastore to perform the query on.
643
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
644
+ * @param {Dictionary} query The stage-3 query to perform.
645
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
646
+ * @param {Function} done Callback
647
+ * @param {Error?}
648
+ * @param {Number} [the average ("mean")]
649
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
650
+ */
651
+ avg: buildStdAdapterMethod(
652
+ require('./private/machines/avg-records'),
653
+ WET_MACHINES,
654
+ registeredDsEntries,
655
+ registeredDryModels
656
+ ),
657
+
658
+ //////////////////////////////////////////////////////////////////////////////////////////////////
659
+ // ██████╗ ██████╗ ██╗ //
660
+ // ██╔══██╗██╔══██╗██║ //
661
+ // ██║ ██║██║ ██║██║ //
662
+ // ██║ ██║██║ ██║██║ //
663
+ // ██████╔╝██████╔╝███████╗ //
664
+ // ╚═════╝ ╚═════╝ ╚══════╝ //
665
+ // (D)ata (D)efinition (L)anguage //
666
+ // //
667
+ // DDL adapter methods: //
668
+ // Methods related to modifying the underlying structure of physical models in the database. //
669
+ //////////////////////////////////////////////////////////////////////////////////////////////////
670
+
671
+ /**
672
+ * ╔╦╗╔═╗╔═╗╦╔╗╔╔═╗
673
+ * ║║║╣ ╠╣ ║║║║║╣
674
+ * ═╩╝╚═╝╚ ╩╝╚╝╚═╝
675
+ * Build a new physical model (e.g. table/etc) to use for storing records in the database.
676
+ *
677
+ * (This is used for schema migrations.)
678
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
679
+ * @param {String} datastoreName The name of the datastore containing the table to define.
680
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
681
+ * @param {String} tableName The name of the table to define.
682
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
683
+ * @param {Dictionary} phmDef The physical model definition (not a normal Sails/Waterline model-- log this for details.)
684
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
685
+ * @param {Function} done Callback
686
+ * @param {Error?}
687
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
688
+ */
689
+
690
+ define: function (datastoreName, tableName, phmDef, done) {
691
+ // Look up the datastore entry (manager/driver/config).
692
+ const dsEntry = registeredDsEntries[datastoreName]
693
+
694
+ // Sanity check:
695
+ if (dsEntry === undefined) {
696
+ return done(
697
+ new Error(
698
+ 'Consistency violation: Cannot do that with datastore (`' +
699
+ datastoreName +
700
+ '`) 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.)'
701
+ )
702
+ )
703
+ }
704
+
705
+ // Helper function to convert Waterline types to SQLite column types
706
+ function mapWaterlineTypeToColumnType(waterlineType, phmAttrDef) {
707
+ // If columnType is explicitly set, use that first
708
+ if (phmAttrDef.columnType) {
709
+ return phmAttrDef.columnType
710
+ }
711
+
712
+ // In real Sails apps, the phmDef often comes pre-processed with column types.
713
+ // If we get a type that starts with _, it's already processed, so pass it through.
714
+ if (typeof waterlineType === 'string' && waterlineType.startsWith('_')) {
715
+ return waterlineType
716
+ }
717
+
718
+ // Map basic Waterline types to appropriate column types for getSqliteType()
719
+ switch (waterlineType) {
720
+ case 'string':
721
+ return '_string'
722
+ case 'number':
723
+ return '_number'
724
+ case 'boolean':
725
+ return 'boolean'
726
+ case 'json':
727
+ return '_json'
728
+ case 'ref':
729
+ return '_text'
730
+ default:
731
+ return '_string' // Default to string type
732
+ }
733
+ }
734
+
735
+ // Convert phmDef to the format expected by definePhysicalModel
736
+ const columns = Object.entries(phmDef).map(([columnName, phmAttrDef]) => {
737
+ const isAutoIncrement =
738
+ columnName === 'id' || phmAttrDef.autoIncrement || false
739
+ return {
740
+ columnName,
741
+ unique: phmAttrDef.unique || false,
742
+ required: phmAttrDef.required || false,
743
+ autoIncrement: isAutoIncrement,
744
+ primaryKey: isAutoIncrement || phmAttrDef.primaryKey || false,
745
+ columnType: mapWaterlineTypeToColumnType(phmAttrDef.type, phmAttrDef)
746
+ }
747
+ })
748
+
749
+ // Call the definePhysicalModel machine
750
+ WET_MACHINES.definePhysicalModel({
751
+ connection: dsEntry.manager,
752
+ tableName: tableName,
753
+ columns: columns,
754
+ meta: dsEntry.config
755
+ }).switch({
756
+ error: function (err) {
757
+ return done(err)
758
+ },
759
+ success: function () {
760
+ return done()
761
+ }
762
+ })
763
+ },
764
+
765
+ /**
766
+ * ╔╦╗╦═╗╔═╗╔═╗
767
+ * ║║╠╦╝║ ║╠═╝
768
+ * ═╩╝╩╚═╚═╝╩
769
+ * Drop a physical model (table/etc.) from the database, including all of its records.
770
+ *
771
+ * > This is idempotent.
772
+ *
773
+ * (This is used for schema migrations.)
774
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
775
+ * @param {String} datastoreName The name of the datastore containing the table to drop.
776
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
777
+ * @param {String} tableName The name of the table to drop.
778
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
779
+ * @param {Ref} unused Currently unused (do not use this argument.)
780
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
781
+ * @param {Function} done Callback
782
+ * @param {Error?}
783
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
784
+ */
785
+ drop: function (datastoreName, tableName, unused, done) {
786
+ // Look up the datastore entry (manager/driver/config).
787
+ const dsEntry = registeredDsEntries[datastoreName]
788
+
789
+ // Sanity check:
790
+ if (dsEntry === undefined) {
791
+ return done(
792
+ new Error(
793
+ `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.)`
794
+ )
795
+ )
796
+ }
797
+
798
+ // Call the dropPhysicalModel machine
799
+ WET_MACHINES.dropPhysicalModel({
800
+ connection: dsEntry.manager,
801
+ tableName: tableName,
802
+ meta: dsEntry.config
803
+ }).switch({
804
+ error: function (err) {
805
+ // Check if the error is an instance of Error
806
+ if (err instanceof Error) {
807
+ return done(err)
808
+ } else {
809
+ return done(
810
+ new Error(
811
+ `Consistency violation: Expecting Error instance, but instead got: ${util.inspect(err)}`
812
+ )
813
+ )
814
+ }
815
+ },
816
+ success: function () {
817
+ // If we get here, the table was successfully dropped or didn't exist
818
+ return done()
819
+ }
820
+ })
821
+ },
822
+ /**
823
+ * ╔═╗╔═╗╔╦╗ ┌─┐┌─┐┌─┐ ┬ ┬┌─┐┌┐┌┌─┐┌─┐
824
+ * ╚═╗║╣ ║ └─┐├┤ │─┼┐│ │├┤ ││││ ├┤
825
+ * ╚═╝╚═╝ ╩ └─┘└─┘└─┘└└─┘└─┘┘└┘└─┘└─┘
826
+ * Set a sequence in a physical model (specifically, the auto-incrementing
827
+ * counter for the primary key) to the specified value.
828
+ *
829
+ * (This is used for schema migrations.)
830
+ *
831
+ * > NOTE - If your adapter doesn't support sequence entities (like PostgreSQL),
832
+ * > you should remove this method.
833
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
834
+ * @param {String} datastoreName The name of the datastore containing the table/etc.
835
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
836
+ * @param {String} sequenceName The name of the sequence to update.
837
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
838
+ * @param {Number} sequenceValue The new value for the sequence (e.g. 1)
839
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
840
+ * @param {Function} done Callback
841
+ * @param {Error?}
842
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
843
+ */
844
+
845
+ /**
846
+ * ╔═╗╔═╗╔╦╗ ╔═╗╔═╗╔═╗ ┬ ┬┌─┐┌┐┌┌─┐┌─┐
847
+ * ╚═╗║╣ ║ └─┐├┤ │─┼┐│ │├┤ ││││ ├┤
848
+ * ╚═╝╚═╝ ╩ └─┘└─┘└─┘└└─┘└─┘┘└┘└─┘└─┘
849
+ * Set a sequence in a physical model (specifically, the auto-incrementing
850
+ * counter for the primary key) to the specified value.
851
+ *
852
+ * (This is used for schema migrations.)
853
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
854
+ * @param {String} datastoreName The name of the datastore containing the table.
855
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
856
+ * @param {String} sequenceName The name of the sequence to update (usually the table name).
857
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
858
+ * @param {Number} sequenceValue The new value for the sequence (e.g. 1).
859
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
860
+ * @param {Function} done Callback
861
+ * @param {Error?}
862
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
863
+ */
864
+ setSequence: function (datastoreName, sequenceName, sequenceValue, done) {
865
+ // Look up the datastore entry (manager/driver/config).
866
+ const dsEntry = registeredDsEntries[datastoreName]
867
+
868
+ // Sanity check:
869
+ if (dsEntry === undefined) {
870
+ return done(
871
+ new Error(
872
+ `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 https://sailsjs.com/support.)`
873
+ )
874
+ )
875
+ }
876
+
877
+ // Call the setPhysicalSequence machine
878
+ WET_MACHINES.setPhysicalSequence({
879
+ connection: dsEntry.manager,
880
+ sequenceName: sequenceName,
881
+ sequenceValue: sequenceValue,
882
+ meta: dsEntry.config
883
+ }).switch({
884
+ error: function (err) {
885
+ return done(err)
886
+ },
887
+ notFound: function (err) {
888
+ // In SQLite, if a table doesn't exist or doesn't have autoincrement,
889
+ // that's not necessarily an error during migrations. We can safely ignore this.
890
+ console.warn(
891
+ `Warning: Could not reset sequence for '${sequenceName}'. This is normal if the table doesn't exist or doesn't have an auto-increment column.`
892
+ )
893
+ return done()
894
+ },
895
+ success: function () {
896
+ return done()
897
+ }
898
+ })
899
+ },
900
+
901
+ /**
902
+ * ╔╦╗╔═╗╔═╗╦╔╗╔╔═╗ ╔═╗╦ ╦╦ ╦╔═╗╦╔═╗╔═╗╦ ╔╦╗╔═╗╔╦╗╔═╗╦
903
+ * ║║║╣ ╠╣ ║║║║║╣ ╠═╝╠═╣╚╦╝╚═╗║║ ╠═╣║ ║║║║ ║ ║║║╣ ║
904
+ * ═╩╝╚═╝╚ ╩╝╚╝╚═╝ ╩ ╩ ╩ ╩ ╚═╝╩╚═╝╩ ╩╩═╝ ╩ ╩╚═╝═╩╝╚═╝╩═╝
905
+ *
906
+ * > https://github.com/node-machine/driver-interface/blob/master/layers/migratable/define-physical-model.js
907
+ */
908
+ definePhysicalModel: DRY_MACHINES.definePhysicalModel,
909
+
910
+ /**
911
+ * ╔╦╗╦═╗╔═╗╔═╗ ╔═╗╦ ╦╦ ╦╔═╗╦╔═╗╔═╗╦ ╔╦╗╔═╗╔╦╗╔═╗╦
912
+ * ║║╠╦╝║ ║╠═╝ ╠═╝╠═╣╚╦╝╚═╗║║ ╠═╣║ ║║║║ ║ ║║║╣ ║
913
+ * ═╩╝╩╚═╚═╝╩ ╩ ╩ ╩ ╩ ╚═╝╩╚═╝╩ ╩╩═╝ ╩ ╩╚═╝═╩╝╚═╝╩═╝
914
+ *
915
+ * > https://github.com/node-machine/driver-interface/blob/master/layers/migratable/drop-physical-model.js
916
+ */
917
+ dropPhysicalModel: DRY_MACHINES.dropPhysicalModel,
918
+
919
+ /**
920
+ * ╔═╗╔═╗╔╦╗ ╔═╗╦ ╦╦ ╦╔═╗╦╔═╗╔═╗╦ ╔═╗╔═╗╔═╗ ╦ ╦╔═╗╔╗╔╔═╗╔═╗
921
+ * ╚═╗║╣ ║ ╠═╝╠═╣╚╦╝╚═╗║║ ╠═╣║ ╚═╗║╣ ║═╬╗║ ║║╣ ║║║║ ║╣
922
+ * ╚═╝╚═╝ ╩ ╩ ╩ ╩ ╩ ╚═╝╩╚═╝╩ ╩╩═╝ ╚═╝╚═╝╚═╝╚╚═╝╚═╝╝╚╝╚═╝╚═╝
923
+ *
924
+ * > https://github.com/node-machine/driver-interface/blob/master/layers/migratable/set-physical-sequence.js
925
+ */
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
+ }
1104
+ }