meadow 2.0.23 → 2.0.27

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 (62) hide show
  1. package/README.md +110 -141
  2. package/docs/README.md +34 -230
  3. package/docs/_cover.md +14 -0
  4. package/docs/_sidebar.md +44 -12
  5. package/docs/_topbar.md +5 -0
  6. package/docs/api/doCount.md +109 -0
  7. package/docs/api/doCreate.md +132 -0
  8. package/docs/api/doDelete.md +101 -0
  9. package/docs/api/doRead.md +122 -0
  10. package/docs/api/doReads.md +136 -0
  11. package/docs/api/doUndelete.md +98 -0
  12. package/docs/api/doUpdate.md +129 -0
  13. package/docs/api/getRoleName.md +84 -0
  14. package/docs/api/loadFromPackage.md +153 -0
  15. package/docs/api/marshalRecordFromSourceToObject.md +92 -0
  16. package/docs/api/query.md +133 -0
  17. package/docs/api/rawQueries.md +197 -0
  18. package/docs/api/reference.md +117 -0
  19. package/docs/api/setAuthorizer.md +103 -0
  20. package/docs/api/setDefault.md +90 -0
  21. package/docs/api/setDefaultIdentifier.md +84 -0
  22. package/docs/api/setDomain.md +56 -0
  23. package/docs/api/setIDUser.md +91 -0
  24. package/docs/api/setJsonSchema.md +92 -0
  25. package/docs/api/setProvider.md +87 -0
  26. package/docs/api/setSchema.md +107 -0
  27. package/docs/api/setScope.md +68 -0
  28. package/docs/api/validateObject.md +119 -0
  29. package/docs/architecture.md +316 -0
  30. package/docs/audit-tracking.md +226 -0
  31. package/docs/configuration.md +317 -0
  32. package/docs/providers/meadow-endpoints.md +306 -0
  33. package/docs/providers/mongodb.md +319 -0
  34. package/docs/providers/postgresql.md +312 -0
  35. package/docs/providers/rocksdb.md +297 -0
  36. package/docs/query-dsl.md +269 -0
  37. package/docs/quick-start.md +384 -0
  38. package/docs/raw-queries.md +193 -0
  39. package/docs/retold-catalog.json +61 -1
  40. package/docs/retold-keyword-index.json +15860 -4839
  41. package/docs/soft-deletes.md +224 -0
  42. package/package.json +44 -13
  43. package/scripts/bookstore-seed-postgresql.sql +135 -0
  44. package/scripts/dgraph-test-db.sh +144 -0
  45. package/scripts/meadow-test-cleanup.sh +5 -1
  46. package/scripts/mongodb-test-db.sh +98 -0
  47. package/scripts/postgresql-test-db.sh +124 -0
  48. package/scripts/solr-test-db.sh +135 -0
  49. package/source/Meadow.js +5 -0
  50. package/source/providers/Meadow-Provider-DGraph.js +679 -0
  51. package/source/providers/Meadow-Provider-MeadowEndpoints.js +1 -1
  52. package/source/providers/Meadow-Provider-MongoDB.js +527 -0
  53. package/source/providers/Meadow-Provider-PostgreSQL.js +361 -0
  54. package/source/providers/Meadow-Provider-RocksDB.js +1300 -0
  55. package/source/providers/Meadow-Provider-Solr.js +726 -0
  56. package/test/Meadow-Provider-DGraph_tests.js +741 -0
  57. package/test/Meadow-Provider-MongoDB_tests.js +661 -0
  58. package/test/Meadow-Provider-PostgreSQL_tests.js +787 -0
  59. package/test/Meadow-Provider-RocksDB_tests.js +887 -0
  60. package/test/Meadow-Provider-SQLiteBrowser-Headless_tests.js +657 -0
  61. package/test/Meadow-Provider-SQLiteBrowser_tests.js +895 -0
  62. package/test/Meadow-Provider-Solr_tests.js +679 -0
@@ -0,0 +1,527 @@
1
+ // ##### Part of the **[retold](https://stevenvelozo.github.io/retold/)** system
2
+ /**
3
+ * @license MIT
4
+ * @author <steven@velozo.com>
5
+ */
6
+ var MeadowProvider = function ()
7
+ {
8
+ function createNew(pFable)
9
+ {
10
+ // If a valid Fable object isn't passed in, return a constructor
11
+ if (typeof (pFable) !== 'object')
12
+ {
13
+ return { new: createNew };
14
+ }
15
+ var _Fable = pFable;
16
+ var _GlobalLogLevel = 0;
17
+ if (_Fable.settings.MongoDB)
18
+ {
19
+ _GlobalLogLevel = _Fable.settings.MongoDB.GlobalLogLevel || 0;
20
+ }
21
+
22
+ /**
23
+ * Get the MongoDB Db instance from the connection service.
24
+ */
25
+ var getDB = function ()
26
+ {
27
+ if (typeof (_Fable.MeadowMongoDBProvider) == 'object' && _Fable.MeadowMongoDBProvider.connected)
28
+ {
29
+ return _Fable.MeadowMongoDBProvider.pool;
30
+ }
31
+ return false;
32
+ };
33
+
34
+ var getProvider = function ()
35
+ {
36
+ if (typeof (_Fable.MeadowMongoDBProvider) == 'object')
37
+ {
38
+ return _Fable.MeadowMongoDBProvider;
39
+ }
40
+ return false;
41
+ };
42
+
43
+ /**
44
+ * Deep-walk an object and replace $$NOW sentinels with new Date().
45
+ *
46
+ * @param {Object} pObj Object to process (mutated in place)
47
+ * @return {Object} The same object with sentinels replaced
48
+ */
49
+ var replaceSentinels = function (pObj)
50
+ {
51
+ if (typeof pObj !== 'object' || pObj === null)
52
+ {
53
+ return pObj;
54
+ }
55
+
56
+ for (var tmpKey in pObj)
57
+ {
58
+ if (!pObj.hasOwnProperty(tmpKey))
59
+ {
60
+ continue;
61
+ }
62
+
63
+ if (pObj[tmpKey] === '$$NOW')
64
+ {
65
+ pObj[tmpKey] = new Date();
66
+ }
67
+ else if (typeof pObj[tmpKey] === 'object' && pObj[tmpKey] !== null)
68
+ {
69
+ replaceSentinels(pObj[tmpKey]);
70
+ }
71
+ }
72
+ return pObj;
73
+ };
74
+
75
+ /**
76
+ * Get the next auto-increment sequence value for a collection/column pair.
77
+ * Uses the _meadow_counters collection with atomic findOneAndUpdate.
78
+ *
79
+ * @param {Object} pDB MongoDB Db instance
80
+ * @param {String} pScope Collection name
81
+ * @param {String} pIDColumn Identity column name
82
+ * @param {Function} fCallback (error, nextSequenceValue)
83
+ */
84
+ var getNextSequence = function (pDB, pScope, pIDColumn, fCallback)
85
+ {
86
+ var tmpCounterKey = pScope + '.' + pIDColumn;
87
+ pDB.collection('_meadow_counters').findOneAndUpdate(
88
+ { _id: tmpCounterKey },
89
+ { $inc: { seq: 1 } },
90
+ { upsert: true, returnDocument: 'after' }
91
+ )
92
+ .then(function (pResult)
93
+ {
94
+ return fCallback(null, pResult.seq);
95
+ })
96
+ .catch(function (pError)
97
+ {
98
+ return fCallback(pError);
99
+ });
100
+ };
101
+
102
+ // The Meadow marshaller also passes in the Schema as the third parameter
103
+ var marshalRecordFromSourceToObject = function (pObject, pRecord)
104
+ {
105
+ for (var tmpColumn in pRecord)
106
+ {
107
+ // Skip MongoDB's internal _id field
108
+ if (tmpColumn === '_id')
109
+ {
110
+ continue;
111
+ }
112
+ pObject[tmpColumn] = pRecord[tmpColumn];
113
+ }
114
+ };
115
+
116
+ var Create = function (pQuery, fCallback)
117
+ {
118
+ var tmpResult = pQuery.parameters.result;
119
+
120
+ pQuery.setDialect('MongoDB').buildCreateQuery();
121
+
122
+ if (pQuery.logLevel > 0 ||
123
+ _GlobalLogLevel > 0)
124
+ {
125
+ _Fable.log.trace(pQuery.query.body, pQuery.query.parameters);
126
+ }
127
+
128
+ var tmpDB = getDB();
129
+ if (!tmpDB)
130
+ {
131
+ tmpResult.error = new Error('No MongoDB connection available.');
132
+ tmpResult.executed = true;
133
+ return fCallback();
134
+ }
135
+
136
+ var tmpOp = pQuery.query.parameters.mongoOperation;
137
+ if (!tmpOp)
138
+ {
139
+ tmpResult.error = new Error('No MongoDB operation generated.');
140
+ tmpResult.executed = true;
141
+ return fCallback();
142
+ }
143
+
144
+ var tmpCollection = tmpDB.collection(tmpOp.collection);
145
+ var tmpDocument = replaceSentinels(JSON.parse(JSON.stringify(tmpOp.document)));
146
+
147
+ // Check for $$AUTOINCREMENT sentinel
148
+ var tmpAutoIncrementColumn = false;
149
+ for (var tmpKey in tmpDocument)
150
+ {
151
+ if (tmpDocument[tmpKey] === '$$AUTOINCREMENT')
152
+ {
153
+ tmpAutoIncrementColumn = tmpKey;
154
+ break;
155
+ }
156
+ }
157
+
158
+ if (tmpAutoIncrementColumn)
159
+ {
160
+ // Get next sequence, then insert
161
+ getNextSequence(tmpDB, tmpOp.collection, tmpAutoIncrementColumn, function (pSeqError, pSeqValue)
162
+ {
163
+ if (pSeqError)
164
+ {
165
+ tmpResult.error = pSeqError;
166
+ tmpResult.value = false;
167
+ tmpResult.executed = true;
168
+ return fCallback();
169
+ }
170
+
171
+ tmpDocument[tmpAutoIncrementColumn] = pSeqValue;
172
+
173
+ tmpCollection.insertOne(tmpDocument)
174
+ .then(function (pInsertResult)
175
+ {
176
+ tmpResult.error = null;
177
+ tmpResult.value = pSeqValue;
178
+ tmpResult.executed = true;
179
+ return fCallback();
180
+ })
181
+ .catch(function (pError)
182
+ {
183
+ tmpResult.error = pError;
184
+ tmpResult.value = false;
185
+ tmpResult.executed = true;
186
+ return fCallback();
187
+ });
188
+ });
189
+ }
190
+ else
191
+ {
192
+ tmpCollection.insertOne(tmpDocument)
193
+ .then(function (pInsertResult)
194
+ {
195
+ tmpResult.error = null;
196
+ tmpResult.value = pInsertResult.insertedId;
197
+ tmpResult.executed = true;
198
+ return fCallback();
199
+ })
200
+ .catch(function (pError)
201
+ {
202
+ tmpResult.error = pError;
203
+ tmpResult.value = false;
204
+ tmpResult.executed = true;
205
+ return fCallback();
206
+ });
207
+ }
208
+ };
209
+
210
+ var Read = function (pQuery, fCallback)
211
+ {
212
+ var tmpResult = pQuery.parameters.result;
213
+
214
+ pQuery.setDialect('MongoDB').buildReadQuery();
215
+
216
+ if (pQuery.logLevel > 0 ||
217
+ _GlobalLogLevel > 0)
218
+ {
219
+ _Fable.log.trace(pQuery.query.body, pQuery.query.parameters);
220
+ }
221
+
222
+ var tmpDB = getDB();
223
+ if (!tmpDB)
224
+ {
225
+ tmpResult.error = new Error('No MongoDB connection available.');
226
+ tmpResult.executed = true;
227
+ return fCallback();
228
+ }
229
+
230
+ var tmpOp = pQuery.query.parameters.mongoOperation;
231
+ var tmpCollection = tmpDB.collection(tmpOp.collection);
232
+
233
+ var tmpOptions = {};
234
+ if (tmpOp.projection && Object.keys(tmpOp.projection).length > 0)
235
+ {
236
+ tmpOptions.projection = tmpOp.projection;
237
+ }
238
+ if (tmpOp.sort && Object.keys(tmpOp.sort).length > 0)
239
+ {
240
+ tmpOptions.sort = tmpOp.sort;
241
+ }
242
+ if (tmpOp.skip)
243
+ {
244
+ tmpOptions.skip = tmpOp.skip;
245
+ }
246
+ if (tmpOp.limit)
247
+ {
248
+ tmpOptions.limit = tmpOp.limit;
249
+ }
250
+
251
+ tmpCollection.find(tmpOp.filter, tmpOptions).toArray()
252
+ .then(function (pDocs)
253
+ {
254
+ tmpResult.error = null;
255
+ tmpResult.value = pDocs;
256
+ tmpResult.executed = true;
257
+ return fCallback();
258
+ })
259
+ .catch(function (pError)
260
+ {
261
+ tmpResult.error = pError;
262
+ tmpResult.value = false;
263
+ tmpResult.executed = true;
264
+ return fCallback();
265
+ });
266
+ };
267
+
268
+ var Update = function (pQuery, fCallback)
269
+ {
270
+ var tmpResult = pQuery.parameters.result;
271
+
272
+ pQuery.setDialect('MongoDB').buildUpdateQuery();
273
+
274
+ if (pQuery.logLevel > 0 ||
275
+ _GlobalLogLevel > 0)
276
+ {
277
+ _Fable.log.trace(pQuery.query.body, pQuery.query.parameters);
278
+ }
279
+
280
+ var tmpDB = getDB();
281
+ if (!tmpDB)
282
+ {
283
+ tmpResult.error = new Error('No MongoDB connection available.');
284
+ tmpResult.executed = true;
285
+ return fCallback();
286
+ }
287
+
288
+ var tmpOp = pQuery.query.parameters.mongoOperation;
289
+ if (!tmpOp)
290
+ {
291
+ tmpResult.error = new Error('No MongoDB operation generated.');
292
+ tmpResult.executed = true;
293
+ return fCallback();
294
+ }
295
+
296
+ var tmpCollection = tmpDB.collection(tmpOp.collection);
297
+ var tmpUpdate = replaceSentinels(JSON.parse(JSON.stringify(tmpOp.update)));
298
+
299
+ tmpCollection.updateMany(tmpOp.filter, tmpUpdate)
300
+ .then(function (pUpdateResult)
301
+ {
302
+ tmpResult.error = null;
303
+ tmpResult.value = pUpdateResult;
304
+ tmpResult.executed = true;
305
+ return fCallback();
306
+ })
307
+ .catch(function (pError)
308
+ {
309
+ tmpResult.error = pError;
310
+ tmpResult.value = false;
311
+ tmpResult.executed = true;
312
+ return fCallback();
313
+ });
314
+ };
315
+
316
+ var Delete = function (pQuery, fCallback)
317
+ {
318
+ var tmpResult = pQuery.parameters.result;
319
+
320
+ pQuery.setDialect('MongoDB').buildDeleteQuery();
321
+
322
+ if (pQuery.logLevel > 0 ||
323
+ _GlobalLogLevel > 0)
324
+ {
325
+ _Fable.log.trace(pQuery.query.body, pQuery.query.parameters);
326
+ }
327
+
328
+ var tmpDB = getDB();
329
+ if (!tmpDB)
330
+ {
331
+ tmpResult.error = new Error('No MongoDB connection available.');
332
+ tmpResult.executed = true;
333
+ return fCallback();
334
+ }
335
+
336
+ var tmpOp = pQuery.query.parameters.mongoOperation;
337
+ var tmpCollection = tmpDB.collection(tmpOp.collection);
338
+
339
+ if (tmpOp.operation === 'updateMany')
340
+ {
341
+ // Soft delete
342
+ var tmpUpdate = replaceSentinels(JSON.parse(JSON.stringify(tmpOp.update)));
343
+ tmpCollection.updateMany(tmpOp.filter, tmpUpdate)
344
+ .then(function (pUpdateResult)
345
+ {
346
+ tmpResult.error = null;
347
+ tmpResult.value = pUpdateResult.modifiedCount;
348
+ tmpResult.executed = true;
349
+ return fCallback();
350
+ })
351
+ .catch(function (pError)
352
+ {
353
+ tmpResult.error = pError;
354
+ tmpResult.value = false;
355
+ tmpResult.executed = true;
356
+ return fCallback();
357
+ });
358
+ }
359
+ else
360
+ {
361
+ // Hard delete
362
+ tmpCollection.deleteMany(tmpOp.filter)
363
+ .then(function (pDeleteResult)
364
+ {
365
+ tmpResult.error = null;
366
+ tmpResult.value = pDeleteResult.deletedCount;
367
+ tmpResult.executed = true;
368
+ return fCallback();
369
+ })
370
+ .catch(function (pError)
371
+ {
372
+ tmpResult.error = pError;
373
+ tmpResult.value = false;
374
+ tmpResult.executed = true;
375
+ return fCallback();
376
+ });
377
+ }
378
+ };
379
+
380
+ var Undelete = function (pQuery, fCallback)
381
+ {
382
+ var tmpResult = pQuery.parameters.result;
383
+
384
+ pQuery.setDialect('MongoDB').buildUndeleteQuery();
385
+
386
+ if (pQuery.logLevel > 0 ||
387
+ _GlobalLogLevel > 0)
388
+ {
389
+ _Fable.log.trace(pQuery.query.body, pQuery.query.parameters);
390
+ }
391
+
392
+ var tmpDB = getDB();
393
+ if (!tmpDB)
394
+ {
395
+ tmpResult.error = new Error('No MongoDB connection available.');
396
+ tmpResult.executed = true;
397
+ return fCallback();
398
+ }
399
+
400
+ var tmpOp = pQuery.query.parameters.mongoOperation;
401
+ if (!tmpOp || tmpOp.operation === 'noop')
402
+ {
403
+ tmpResult.error = null;
404
+ tmpResult.value = 0;
405
+ tmpResult.executed = true;
406
+ return fCallback();
407
+ }
408
+
409
+ var tmpCollection = tmpDB.collection(tmpOp.collection);
410
+ var tmpUpdate = replaceSentinels(JSON.parse(JSON.stringify(tmpOp.update)));
411
+
412
+ tmpCollection.updateMany(tmpOp.filter, tmpUpdate)
413
+ .then(function (pUpdateResult)
414
+ {
415
+ tmpResult.error = null;
416
+ tmpResult.value = pUpdateResult.modifiedCount;
417
+ tmpResult.executed = true;
418
+ return fCallback();
419
+ })
420
+ .catch(function (pError)
421
+ {
422
+ tmpResult.error = pError;
423
+ tmpResult.value = false;
424
+ tmpResult.executed = true;
425
+ return fCallback();
426
+ });
427
+ };
428
+
429
+ var Count = function (pQuery, fCallback)
430
+ {
431
+ var tmpResult = pQuery.parameters.result;
432
+
433
+ pQuery.setDialect('MongoDB').buildCountQuery();
434
+
435
+ if (pQuery.logLevel > 0 ||
436
+ _GlobalLogLevel > 0)
437
+ {
438
+ _Fable.log.trace(pQuery.query.body, pQuery.query.parameters);
439
+ }
440
+
441
+ var tmpDB = getDB();
442
+ if (!tmpDB)
443
+ {
444
+ tmpResult.error = new Error('No MongoDB connection available.');
445
+ tmpResult.executed = true;
446
+ return fCallback();
447
+ }
448
+
449
+ var tmpOp = pQuery.query.parameters.mongoOperation;
450
+ var tmpCollection = tmpDB.collection(tmpOp.collection);
451
+
452
+ if (tmpOp.distinct && tmpOp.distinctFields && tmpOp.distinctFields.length > 0)
453
+ {
454
+ // Use aggregation pipeline for distinct count
455
+ var tmpGroupId = {};
456
+ for (var i = 0; i < tmpOp.distinctFields.length; i++)
457
+ {
458
+ tmpGroupId[tmpOp.distinctFields[i]] = '$' + tmpOp.distinctFields[i];
459
+ }
460
+
461
+ var tmpPipeline = [
462
+ { $match: tmpOp.filter },
463
+ { $group: { _id: tmpGroupId } },
464
+ { $count: 'RowCount' }
465
+ ];
466
+
467
+ tmpCollection.aggregate(tmpPipeline).toArray()
468
+ .then(function (pResults)
469
+ {
470
+ tmpResult.error = null;
471
+ tmpResult.value = (pResults.length > 0) ? pResults[0].RowCount : 0;
472
+ tmpResult.executed = true;
473
+ return fCallback();
474
+ })
475
+ .catch(function (pError)
476
+ {
477
+ tmpResult.error = pError;
478
+ tmpResult.value = false;
479
+ tmpResult.executed = true;
480
+ return fCallback();
481
+ });
482
+ }
483
+ else
484
+ {
485
+ tmpCollection.countDocuments(tmpOp.filter)
486
+ .then(function (pCount)
487
+ {
488
+ tmpResult.error = null;
489
+ tmpResult.value = pCount;
490
+ tmpResult.executed = true;
491
+ return fCallback();
492
+ })
493
+ .catch(function (pError)
494
+ {
495
+ tmpResult.error = pError;
496
+ tmpResult.value = false;
497
+ tmpResult.executed = true;
498
+ return fCallback();
499
+ });
500
+ }
501
+ };
502
+
503
+ var tmpNewProvider = (
504
+ {
505
+ marshalRecordFromSourceToObject: marshalRecordFromSourceToObject,
506
+
507
+ Create: Create,
508
+ Read: Read,
509
+ Update: Update,
510
+ Delete: Delete,
511
+ Undelete: Undelete,
512
+ Count: Count,
513
+
514
+ getProvider: getProvider,
515
+ providerCreatesSupported: true,
516
+
517
+ new: createNew
518
+ });
519
+
520
+
521
+ return tmpNewProvider;
522
+ }
523
+
524
+ return createNew();
525
+ };
526
+
527
+ module.exports = new MeadowProvider();