meadow 2.0.17 → 2.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -112
- package/docs/README.md +276 -0
- package/docs/_sidebar.md +38 -0
- package/docs/providers/README.md +253 -0
- package/docs/providers/alasql.md +271 -0
- package/docs/providers/mssql.md +296 -0
- package/docs/providers/mysql.md +260 -0
- package/docs/providers/sqlite.md +173 -0
- package/docs/query/README.md +175 -0
- package/docs/query/count.md +228 -0
- package/docs/query/create.md +226 -0
- package/docs/query/delete.md +264 -0
- package/docs/query/read.md +350 -0
- package/docs/query/update.md +250 -0
- package/docs/schema/README.md +408 -0
- package/package.json +16 -3
- package/scripts/mssql-test-db.sh +111 -0
- package/scripts/mysql-test-db.sh +108 -0
- package/source/Meadow.js +1 -0
- package/source/providers/Meadow-Provider-SQLite.js +235 -155
- package/test/Meadow-Provider-SQLite-AnimalReadQuery.sql +5 -0
- package/test/Meadow-Provider-SQLite_tests.js +931 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Meadow Provider - SQLite (via better-sqlite3)
|
|
3
|
+
*
|
|
2
4
|
* @license MIT
|
|
3
5
|
* @author <steven@velozo.com>
|
|
4
6
|
*/
|
|
@@ -14,21 +16,16 @@ var MeadowProvider = function ()
|
|
|
14
16
|
var _Fable = pFable;
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
+
* Get the better-sqlite3 database instance from the connection provider.
|
|
20
|
+
*
|
|
21
|
+
* The connection provider (meadow-connection-sqlite) stores the database
|
|
22
|
+
* instance on .db after connectAsync() completes.
|
|
19
23
|
*/
|
|
20
24
|
var getDB = function ()
|
|
21
25
|
{
|
|
22
|
-
if (typeof (_Fable.
|
|
26
|
+
if (typeof (_Fable.MeadowSQLiteProvider) == 'object' && _Fable.MeadowSQLiteProvider.connected)
|
|
23
27
|
{
|
|
24
|
-
|
|
25
|
-
return _Fable.MeadowMySQLConnectionPool;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// New-style default connection pool provider
|
|
29
|
-
if (typeof (_Fable.MeadowMySQLProvider) == 'object' && _Fable.MeadowMySQLProvider.connected)
|
|
30
|
-
{
|
|
31
|
-
return _Fable.MeadowMySQLProvider.pool;
|
|
28
|
+
return _Fable.MeadowSQLiteProvider.db;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
return false;
|
|
@@ -36,26 +33,43 @@ var MeadowProvider = function ()
|
|
|
36
33
|
|
|
37
34
|
var getProvider = function ()
|
|
38
35
|
{
|
|
39
|
-
if (typeof (_Fable.
|
|
36
|
+
if (typeof (_Fable.MeadowSQLiteProvider) == 'object')
|
|
40
37
|
{
|
|
41
|
-
|
|
42
|
-
return _Fable.MeadowMySQLConnectionPool;
|
|
38
|
+
return _Fable.MeadowSQLiteProvider;
|
|
43
39
|
}
|
|
44
40
|
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
return false;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Replace NOW() with SQLite-compatible datetime('now') in query bodies.
|
|
46
|
+
*
|
|
47
|
+
* The FoxHound SQLite dialect generates NOW() for date stamps, but SQLite
|
|
48
|
+
* does not support NOW(). We replace it at the provider level so the
|
|
49
|
+
* dialect can stay consistent with the other providers.
|
|
50
|
+
*/
|
|
51
|
+
var fixDateFunctions = function (pQueryBody)
|
|
52
|
+
{
|
|
53
|
+
if (typeof (pQueryBody) !== 'string')
|
|
47
54
|
{
|
|
48
|
-
return
|
|
55
|
+
return pQueryBody;
|
|
49
56
|
}
|
|
57
|
+
// Replace NOW() and NOW(3) with SQLite's datetime function
|
|
58
|
+
return pQueryBody.replace(/NOW\(\d*\)/g, "datetime('now')");
|
|
59
|
+
};
|
|
50
60
|
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Convert FoxHound named parameters (:name) to better-sqlite3 format.
|
|
63
|
+
*
|
|
64
|
+
* better-sqlite3 uses @name, $name, or :name for named parameters,
|
|
65
|
+
* but expects them passed as an object. FoxHound generates :name syntax
|
|
66
|
+
* which better-sqlite3 supports natively.
|
|
67
|
+
*/
|
|
53
68
|
|
|
54
69
|
// The Meadow marshaller also passes in the Schema as the third parameter, but this is a blunt function ATM.
|
|
55
70
|
var marshalRecordFromSourceToObject = function (pObject, pRecord)
|
|
56
71
|
{
|
|
57
72
|
// For now, crudely assign everything in pRecord to pObject
|
|
58
|
-
// This is safe in this context, and we don't want to slow down marshalling with millions of hasOwnProperty checks
|
|
59
73
|
for (var tmpColumn in pRecord)
|
|
60
74
|
{
|
|
61
75
|
pObject[tmpColumn] = pRecord[tmpColumn];
|
|
@@ -68,205 +82,271 @@ var MeadowProvider = function ()
|
|
|
68
82
|
|
|
69
83
|
pQuery.setDialect('SQLite').buildCreateQuery();
|
|
70
84
|
|
|
71
|
-
|
|
85
|
+
var tmpQueryBody = fixDateFunctions(pQuery.query.body);
|
|
86
|
+
|
|
72
87
|
if (pQuery.logLevel > 0)
|
|
73
88
|
{
|
|
74
|
-
_Fable.log.trace(
|
|
89
|
+
_Fable.log.trace(tmpQueryBody, pQuery.query.parameters);
|
|
75
90
|
}
|
|
76
91
|
|
|
77
|
-
|
|
92
|
+
try
|
|
78
93
|
{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
var tmpDB = getDB();
|
|
95
|
+
if (!tmpDB)
|
|
96
|
+
{
|
|
97
|
+
tmpResult.error = new Error('No SQLite database connection available.');
|
|
98
|
+
tmpResult.executed = true;
|
|
99
|
+
return fCallback();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
var tmpStatement = tmpDB.prepare(tmpQueryBody);
|
|
103
|
+
var tmpInfo = tmpStatement.run(pQuery.query.parameters);
|
|
104
|
+
|
|
105
|
+
tmpResult.error = null;
|
|
106
|
+
tmpResult.value = false;
|
|
107
|
+
try
|
|
108
|
+
{
|
|
109
|
+
tmpResult.value = Number(tmpInfo.lastInsertRowid);
|
|
110
|
+
}
|
|
111
|
+
catch (pErrorGettingRowcount)
|
|
112
|
+
{
|
|
113
|
+
_Fable.log.warn('Error getting insert ID during create query', { Body: tmpQueryBody, Parameters: pQuery.query.parameters });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
tmpResult.executed = true;
|
|
117
|
+
return fCallback();
|
|
118
|
+
}
|
|
119
|
+
catch (pError)
|
|
120
|
+
{
|
|
121
|
+
tmpResult.error = pError;
|
|
122
|
+
tmpResult.value = false;
|
|
123
|
+
tmpResult.executed = true;
|
|
124
|
+
return fCallback();
|
|
125
|
+
}
|
|
101
126
|
};
|
|
102
127
|
|
|
103
|
-
// This is a synchronous read, good for a few records.
|
|
104
|
-
// TODO: Add a pipe-able read for huge sets
|
|
105
128
|
var Read = function (pQuery, fCallback)
|
|
106
129
|
{
|
|
107
130
|
var tmpResult = pQuery.parameters.result;
|
|
108
131
|
|
|
109
|
-
pQuery.setDialect('
|
|
132
|
+
pQuery.setDialect('SQLite').buildReadQuery();
|
|
133
|
+
|
|
134
|
+
var tmpQueryBody = fixDateFunctions(pQuery.query.body);
|
|
110
135
|
|
|
111
136
|
if (pQuery.logLevel > 0)
|
|
112
137
|
{
|
|
113
|
-
_Fable.log.trace(
|
|
138
|
+
_Fable.log.trace(tmpQueryBody, pQuery.query.parameters);
|
|
114
139
|
}
|
|
115
140
|
|
|
116
|
-
|
|
141
|
+
try
|
|
117
142
|
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
143
|
+
var tmpDB = getDB();
|
|
144
|
+
if (!tmpDB)
|
|
145
|
+
{
|
|
146
|
+
tmpResult.error = new Error('No SQLite database connection available.');
|
|
147
|
+
tmpResult.executed = true;
|
|
148
|
+
return fCallback();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
var tmpStatement = tmpDB.prepare(tmpQueryBody);
|
|
152
|
+
var tmpRows = tmpStatement.all(pQuery.query.parameters);
|
|
153
|
+
|
|
154
|
+
tmpResult.error = null;
|
|
155
|
+
tmpResult.value = tmpRows;
|
|
156
|
+
tmpResult.executed = true;
|
|
157
|
+
return fCallback();
|
|
158
|
+
}
|
|
159
|
+
catch (pError)
|
|
160
|
+
{
|
|
161
|
+
tmpResult.error = pError;
|
|
162
|
+
tmpResult.value = false;
|
|
163
|
+
tmpResult.executed = true;
|
|
164
|
+
return fCallback();
|
|
165
|
+
}
|
|
131
166
|
};
|
|
132
167
|
|
|
133
168
|
var Update = function (pQuery, fCallback)
|
|
134
169
|
{
|
|
135
170
|
var tmpResult = pQuery.parameters.result;
|
|
136
171
|
|
|
137
|
-
pQuery.setDialect('
|
|
172
|
+
pQuery.setDialect('SQLite').buildUpdateQuery();
|
|
173
|
+
|
|
174
|
+
var tmpQueryBody = fixDateFunctions(pQuery.query.body);
|
|
138
175
|
|
|
139
176
|
if (pQuery.logLevel > 0)
|
|
140
177
|
{
|
|
141
|
-
_Fable.log.trace(
|
|
178
|
+
_Fable.log.trace(tmpQueryBody, pQuery.query.parameters);
|
|
142
179
|
}
|
|
143
180
|
|
|
144
|
-
|
|
181
|
+
try
|
|
145
182
|
{
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
183
|
+
var tmpDB = getDB();
|
|
184
|
+
if (!tmpDB)
|
|
185
|
+
{
|
|
186
|
+
tmpResult.error = new Error('No SQLite database connection available.');
|
|
187
|
+
tmpResult.executed = true;
|
|
188
|
+
return fCallback();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
var tmpStatement = tmpDB.prepare(tmpQueryBody);
|
|
192
|
+
var tmpInfo = tmpStatement.run(pQuery.query.parameters);
|
|
193
|
+
|
|
194
|
+
tmpResult.error = null;
|
|
195
|
+
tmpResult.value = tmpInfo;
|
|
196
|
+
tmpResult.executed = true;
|
|
197
|
+
return fCallback();
|
|
198
|
+
}
|
|
199
|
+
catch (pError)
|
|
200
|
+
{
|
|
201
|
+
tmpResult.error = pError;
|
|
202
|
+
tmpResult.value = false;
|
|
203
|
+
tmpResult.executed = true;
|
|
204
|
+
return fCallback();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
160
207
|
|
|
161
208
|
var Delete = function (pQuery, fCallback)
|
|
162
209
|
{
|
|
163
210
|
var tmpResult = pQuery.parameters.result;
|
|
164
211
|
|
|
165
|
-
pQuery.setDialect('
|
|
212
|
+
pQuery.setDialect('SQLite').buildDeleteQuery();
|
|
213
|
+
|
|
214
|
+
var tmpQueryBody = fixDateFunctions(pQuery.query.body);
|
|
166
215
|
|
|
167
216
|
if (pQuery.logLevel > 0)
|
|
168
217
|
{
|
|
169
|
-
_Fable.log.trace(
|
|
218
|
+
_Fable.log.trace(tmpQueryBody, pQuery.query.parameters);
|
|
170
219
|
}
|
|
171
220
|
|
|
172
|
-
|
|
221
|
+
try
|
|
173
222
|
{
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
223
|
+
var tmpDB = getDB();
|
|
224
|
+
if (!tmpDB)
|
|
225
|
+
{
|
|
226
|
+
tmpResult.error = new Error('No SQLite database connection available.');
|
|
227
|
+
tmpResult.executed = true;
|
|
228
|
+
return fCallback();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
var tmpStatement = tmpDB.prepare(tmpQueryBody);
|
|
232
|
+
var tmpInfo = tmpStatement.run(pQuery.query.parameters);
|
|
233
|
+
|
|
234
|
+
tmpResult.error = null;
|
|
235
|
+
tmpResult.value = false;
|
|
236
|
+
try
|
|
237
|
+
{
|
|
238
|
+
tmpResult.value = tmpInfo.changes;
|
|
239
|
+
}
|
|
240
|
+
catch (pErrorGettingRowcount)
|
|
241
|
+
{
|
|
242
|
+
_Fable.log.warn('Error getting affected rowcount during delete query', { Body: tmpQueryBody, Parameters: pQuery.query.parameters });
|
|
243
|
+
}
|
|
244
|
+
tmpResult.executed = true;
|
|
245
|
+
return fCallback();
|
|
246
|
+
}
|
|
247
|
+
catch (pError)
|
|
248
|
+
{
|
|
249
|
+
tmpResult.error = pError;
|
|
250
|
+
tmpResult.value = false;
|
|
251
|
+
tmpResult.executed = true;
|
|
252
|
+
return fCallback();
|
|
253
|
+
}
|
|
196
254
|
};
|
|
197
255
|
|
|
198
256
|
var Undelete = function (pQuery, fCallback)
|
|
199
257
|
{
|
|
200
258
|
var tmpResult = pQuery.parameters.result;
|
|
201
259
|
|
|
202
|
-
pQuery.setDialect('
|
|
260
|
+
pQuery.setDialect('SQLite').buildUndeleteQuery();
|
|
261
|
+
|
|
262
|
+
var tmpQueryBody = fixDateFunctions(pQuery.query.body);
|
|
203
263
|
|
|
204
264
|
if (pQuery.logLevel > 0)
|
|
205
265
|
{
|
|
206
|
-
_Fable.log.trace(
|
|
266
|
+
_Fable.log.trace(tmpQueryBody, pQuery.query.parameters);
|
|
207
267
|
}
|
|
208
268
|
|
|
209
|
-
|
|
269
|
+
try
|
|
210
270
|
{
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
271
|
+
var tmpDB = getDB();
|
|
272
|
+
if (!tmpDB)
|
|
273
|
+
{
|
|
274
|
+
tmpResult.error = new Error('No SQLite database connection available.');
|
|
275
|
+
tmpResult.executed = true;
|
|
276
|
+
return fCallback();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
var tmpStatement = tmpDB.prepare(tmpQueryBody);
|
|
280
|
+
var tmpInfo = tmpStatement.run(pQuery.query.parameters);
|
|
281
|
+
|
|
282
|
+
tmpResult.error = null;
|
|
283
|
+
tmpResult.value = false;
|
|
284
|
+
try
|
|
285
|
+
{
|
|
286
|
+
tmpResult.value = tmpInfo.changes;
|
|
287
|
+
}
|
|
288
|
+
catch (pErrorGettingRowcount)
|
|
289
|
+
{
|
|
290
|
+
_Fable.log.warn('Error getting affected rowcount during undelete query', { Body: tmpQueryBody, Parameters: pQuery.query.parameters });
|
|
291
|
+
}
|
|
292
|
+
tmpResult.executed = true;
|
|
293
|
+
return fCallback();
|
|
294
|
+
}
|
|
295
|
+
catch (pError)
|
|
296
|
+
{
|
|
297
|
+
tmpResult.error = pError;
|
|
298
|
+
tmpResult.value = false;
|
|
299
|
+
tmpResult.executed = true;
|
|
300
|
+
return fCallback();
|
|
301
|
+
}
|
|
233
302
|
};
|
|
234
303
|
|
|
235
304
|
var Count = function (pQuery, fCallback)
|
|
236
305
|
{
|
|
237
306
|
var tmpResult = pQuery.parameters.result;
|
|
238
307
|
|
|
239
|
-
pQuery.setDialect('
|
|
308
|
+
pQuery.setDialect('SQLite').buildCountQuery();
|
|
309
|
+
|
|
310
|
+
var tmpQueryBody = fixDateFunctions(pQuery.query.body);
|
|
240
311
|
|
|
241
312
|
if (pQuery.logLevel > 0)
|
|
242
313
|
{
|
|
243
|
-
_Fable.log.trace(
|
|
314
|
+
_Fable.log.trace(tmpQueryBody, pQuery.query.parameters);
|
|
244
315
|
}
|
|
245
316
|
|
|
246
|
-
|
|
317
|
+
try
|
|
247
318
|
{
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
319
|
+
var tmpDB = getDB();
|
|
320
|
+
if (!tmpDB)
|
|
321
|
+
{
|
|
322
|
+
tmpResult.error = new Error('No SQLite database connection available.');
|
|
323
|
+
tmpResult.executed = true;
|
|
324
|
+
return fCallback();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
var tmpStatement = tmpDB.prepare(tmpQueryBody);
|
|
328
|
+
var tmpRows = tmpStatement.all(pQuery.query.parameters);
|
|
329
|
+
|
|
330
|
+
tmpResult.executed = true;
|
|
331
|
+
tmpResult.error = null;
|
|
332
|
+
tmpResult.value = false;
|
|
333
|
+
try
|
|
334
|
+
{
|
|
335
|
+
tmpResult.value = tmpRows[0].RowCount;
|
|
336
|
+
}
|
|
337
|
+
catch (pErrorGettingRowcount)
|
|
338
|
+
{
|
|
339
|
+
_Fable.log.warn('Error getting rowcount during count query', { Body: tmpQueryBody, Parameters: pQuery.query.parameters });
|
|
340
|
+
}
|
|
341
|
+
return fCallback();
|
|
342
|
+
}
|
|
343
|
+
catch (pError)
|
|
344
|
+
{
|
|
345
|
+
tmpResult.error = pError;
|
|
346
|
+
tmpResult.value = false;
|
|
347
|
+
tmpResult.executed = true;
|
|
348
|
+
return fCallback();
|
|
349
|
+
}
|
|
270
350
|
};
|
|
271
351
|
|
|
272
352
|
var tmpNewProvider = (
|