meadow 2.0.22 → 2.0.26

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 (59) 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 -27
  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-MongoDB.js +527 -0
  52. package/source/providers/Meadow-Provider-PostgreSQL.js +361 -0
  53. package/source/providers/Meadow-Provider-RocksDB.js +1300 -0
  54. package/source/providers/Meadow-Provider-Solr.js +726 -0
  55. package/test/Meadow-Provider-DGraph_tests.js +741 -0
  56. package/test/Meadow-Provider-MongoDB_tests.js +661 -0
  57. package/test/Meadow-Provider-PostgreSQL_tests.js +787 -0
  58. package/test/Meadow-Provider-RocksDB_tests.js +887 -0
  59. package/test/Meadow-Provider-Solr_tests.js +679 -0
@@ -0,0 +1,887 @@
1
+ /**
2
+ * Unit tests for the Meadow "RocksDB" Provider
3
+ *
4
+ * These tests use a local RocksDB database on disk.
5
+ *
6
+ * @license MIT
7
+ *
8
+ * @author Steven Velozo <steven@velozo.com>
9
+ */
10
+
11
+ var Chai = require("chai");
12
+ var Expect = Chai.expect;
13
+
14
+ var libFS = require('fs');
15
+ var libPath = require('path');
16
+
17
+ var libMeadowConnectionRocksDB = require('meadow-connection-rocksdb');
18
+
19
+ var _RocksDBFolder = libPath.join(__dirname, '..', 'dist', 'FableTest-RocksDB');
20
+
21
+ var tmpFableSettings = (
22
+ {
23
+ RocksDB:
24
+ {
25
+ RocksDBFolder: _RocksDBFolder
26
+ },
27
+ LogStreams:
28
+ [
29
+ {
30
+ level: 'fatal',
31
+ streamtype:'process.stdout',
32
+ },
33
+ {
34
+ level: 'trace',
35
+ path: __dirname+'/../tests.log'
36
+ }
37
+ ]
38
+ });
39
+
40
+ var libFable = new (require('fable'))(tmpFableSettings);
41
+
42
+ // Register the RocksDB connection service
43
+ libFable.serviceManager.addServiceType('MeadowRocksDBProvider', libMeadowConnectionRocksDB);
44
+ libFable.serviceManager.instantiateServiceProvider('MeadowRocksDBProvider');
45
+
46
+
47
+ var _AnimalJsonSchema = (
48
+ {
49
+ title: "Animal",
50
+ description: "A creature that lives in a meadow.",
51
+ type: "object",
52
+ properties: {
53
+ IDAnimal: {
54
+ description: "The unique identifier for an animal",
55
+ type: "integer"
56
+ },
57
+ Name: {
58
+ description: "The animal's name",
59
+ type: "string"
60
+ },
61
+ Type: {
62
+ description: "The type of the animal",
63
+ type: "string"
64
+ }
65
+ },
66
+ required: ["IDAnimal", "Name", "CreatingIDUser"]
67
+ });
68
+ var _AnimalSchema = (
69
+ [
70
+ { Column: "IDAnimal", Type:"AutoIdentity" },
71
+ { Column: "GUIDAnimal", Type:"AutoGUID" },
72
+ { Column: "CreateDate", Type:"CreateDate" },
73
+ { Column: "CreatingIDUser", Type:"CreateIDUser" },
74
+ { Column: "UpdateDate", Type:"UpdateDate" },
75
+ { Column: "UpdatingIDUser", Type:"UpdateIDUser" },
76
+ { Column: "Deleted", Type:"Deleted" },
77
+ { Column: "DeletingIDUser", Type:"DeleteIDUser" },
78
+ { Column: "DeleteDate", Type:"DeleteDate" }
79
+ ]);
80
+ var _AnimalDefault = (
81
+ {
82
+ IDAnimal: null,
83
+ GUIDAnimal: '',
84
+
85
+ CreateDate: false,
86
+ CreatingIDUser: 0,
87
+ UpdateDate: false,
88
+ UpdatingIDUser: 0,
89
+ Deleted: 0,
90
+ DeleteDate: false,
91
+ DeletingIDUser: 0,
92
+
93
+ Name: 'Unknown',
94
+ Type: 'Unclassified'
95
+ });
96
+
97
+ suite
98
+ (
99
+ 'Meadow-Provider-RocksDB',
100
+ function()
101
+ {
102
+ var _SpooledUp = false;
103
+
104
+ var newMeadow = function()
105
+ {
106
+ return require('../source/Meadow.js')
107
+ .new(libFable, 'FableTest')
108
+ .setProvider('RocksDB')
109
+ .setSchema(_AnimalSchema)
110
+ .setJsonSchema(_AnimalJsonSchema)
111
+ .setDefaultIdentifier('IDAnimal')
112
+ .setDefault(_AnimalDefault);
113
+ };
114
+
115
+ suiteSetup
116
+ (
117
+ function(fDone)
118
+ {
119
+ if (!_SpooledUp)
120
+ {
121
+ // Remove any previous test database
122
+ if (libFS.existsSync(_RocksDBFolder))
123
+ {
124
+ libFS.rmSync(_RocksDBFolder, { recursive: true, force: true });
125
+ }
126
+
127
+ // Ensure the dist directory exists
128
+ var tmpDistDir = libPath.join(__dirname, '..', 'dist');
129
+ if (!libFS.existsSync(tmpDistDir))
130
+ {
131
+ libFS.mkdirSync(tmpDistDir, { recursive: true });
132
+ }
133
+
134
+ // Connect to RocksDB
135
+ libFable.MeadowRocksDBProvider.connectAsync(
136
+ function(pError)
137
+ {
138
+ if (pError)
139
+ {
140
+ return fDone(pError);
141
+ }
142
+
143
+ _SpooledUp = true;
144
+ fDone();
145
+ }
146
+ );
147
+ }
148
+ else
149
+ {
150
+ fDone();
151
+ }
152
+ }
153
+ );
154
+
155
+ suiteTeardown(function(fDone)
156
+ {
157
+ libFable.MeadowRocksDBProvider.closeAsync(function()
158
+ {
159
+ fDone();
160
+ });
161
+ });
162
+
163
+ suite
164
+ (
165
+ 'Object Sanity',
166
+ function()
167
+ {
168
+ test
169
+ (
170
+ 'The RocksDB class should initialize itself into a happy little object.',
171
+ function()
172
+ {
173
+ var testMeadow = require('../source/Meadow.js').new(libFable).setProvider('RocksDB');
174
+ Expect(testMeadow).to.be.an('object', 'Meadow should initialize as an object directly from the require statement.');
175
+ Expect(testMeadow.providerName).to.equal('RocksDB');
176
+ }
177
+ );
178
+ }
179
+ );
180
+
181
+ suite
182
+ (
183
+ 'Create Operations',
184
+ function()
185
+ {
186
+ test
187
+ (
188
+ 'Create a record in the database',
189
+ function(fDone)
190
+ {
191
+ var testMeadow = newMeadow().setIDUser(90210);
192
+
193
+ var tmpQuery = testMeadow.query.clone().setLogLevel(5)
194
+ .addRecord({Name:'Foo Foo', Type:'Bunny'});
195
+
196
+ testMeadow.doCreate(tmpQuery,
197
+ function(pError, pQuery, pQueryRead, pRecord)
198
+ {
199
+ Expect(pRecord.Name)
200
+ .to.equal('Foo Foo');
201
+ Expect(pRecord.Type)
202
+ .to.equal('Bunny');
203
+ Expect(pRecord.IDAnimal)
204
+ .to.equal(1);
205
+ Expect(pRecord.CreatingIDUser)
206
+ .to.equal(90210);
207
+ Expect(pRecord.GUIDAnimal)
208
+ .to.be.a('string');
209
+ Expect(pRecord.GUIDAnimal.length)
210
+ .to.be.greaterThan(5);
211
+ fDone();
212
+ }
213
+ );
214
+ }
215
+ );
216
+
217
+ test
218
+ (
219
+ 'Create more records for later tests',
220
+ function(fDone)
221
+ {
222
+ var testMeadow = newMeadow().setIDUser(1);
223
+
224
+ var tmpQuery1 = testMeadow.query.clone()
225
+ .addRecord({Name:'Red Riding Hood', Type:'Human'});
226
+ testMeadow.doCreate(tmpQuery1,
227
+ function(pError1, pQuery1, pQueryRead1, pRecord1)
228
+ {
229
+ Expect(pRecord1.IDAnimal).to.equal(2);
230
+ Expect(pRecord1.Name).to.equal('Red Riding Hood');
231
+
232
+ var tmpQuery2 = testMeadow.query.clone()
233
+ .addRecord({Name:'Red', Type:'Dog'});
234
+ testMeadow.doCreate(tmpQuery2,
235
+ function(pError2, pQuery2, pQueryRead2, pRecord2)
236
+ {
237
+ Expect(pRecord2.IDAnimal).to.equal(3);
238
+
239
+ var tmpQuery3 = testMeadow.query.clone()
240
+ .addRecord({Name:'Spot', Type:'Dog'});
241
+ testMeadow.doCreate(tmpQuery3,
242
+ function(pError3, pQuery3, pQueryRead3, pRecord3)
243
+ {
244
+ Expect(pRecord3.IDAnimal).to.equal(4);
245
+
246
+ var tmpQuery4 = testMeadow.query.clone()
247
+ .addRecord({Name:'Gertrude', Type:'Frog'});
248
+ testMeadow.doCreate(tmpQuery4,
249
+ function(pError4, pQuery4, pQueryRead4, pRecord4)
250
+ {
251
+ Expect(pRecord4.IDAnimal).to.equal(5);
252
+ fDone();
253
+ }
254
+ );
255
+ }
256
+ );
257
+ }
258
+ );
259
+ }
260
+ );
261
+ }
262
+ );
263
+
264
+ test
265
+ (
266
+ 'Create a record with pre-set Deleted flag',
267
+ function(fDone)
268
+ {
269
+ var testMeadow = newMeadow().setIDUser(1);
270
+
271
+ var tmpQuery = testMeadow.query.clone()
272
+ .setDisableDeleteTracking(true)
273
+ .addRecord({Name:'Charmander', Type:'Pokemon', Deleted: 1});
274
+
275
+ testMeadow.doCreate(tmpQuery,
276
+ function(pError, pQuery, pQueryRead, pRecord)
277
+ {
278
+ Expect(pRecord.Name).to.equal('Charmander');
279
+ Expect(pRecord.Deleted).to.equal(1);
280
+ Expect(pRecord.IDAnimal).to.equal(6);
281
+ fDone();
282
+ }
283
+ );
284
+ }
285
+ );
286
+ }
287
+ );
288
+
289
+ suite
290
+ (
291
+ 'Read Operations',
292
+ function()
293
+ {
294
+ test
295
+ (
296
+ 'Read a single record by ID',
297
+ function(fDone)
298
+ {
299
+ var testMeadow = newMeadow();
300
+
301
+ var tmpQuery = testMeadow.query
302
+ .addFilter('IDAnimal', 1);
303
+
304
+ testMeadow.doRead(tmpQuery,
305
+ function(pError, pQuery, pRecord)
306
+ {
307
+ Expect(pRecord.IDAnimal)
308
+ .to.equal(1);
309
+ Expect(pRecord.Name)
310
+ .to.equal('Foo Foo');
311
+ Expect(pRecord.Type)
312
+ .to.equal('Bunny');
313
+ fDone();
314
+ }
315
+ );
316
+ }
317
+ );
318
+
319
+ test
320
+ (
321
+ 'Read all records (doReads)',
322
+ function(fDone)
323
+ {
324
+ var testMeadow = newMeadow();
325
+
326
+ testMeadow.doReads(testMeadow.query,
327
+ function(pError, pQuery, pRecords)
328
+ {
329
+ // Should return 5 records (excluding Charmander which is Deleted=1)
330
+ Expect(pRecords.length)
331
+ .to.equal(5);
332
+ // Records come back in GUID key order, so use set-based assertions
333
+ var tmpNames = pRecords.map(function(r) { return r.Name; });
334
+ Expect(tmpNames).to.include('Foo Foo');
335
+ Expect(tmpNames).to.include('Red Riding Hood');
336
+ Expect(tmpNames).to.include('Red');
337
+ Expect(tmpNames).to.include('Spot');
338
+ Expect(tmpNames).to.include('Gertrude');
339
+ fDone();
340
+ }
341
+ );
342
+ }
343
+ );
344
+
345
+ test
346
+ (
347
+ 'Read records with equality filter',
348
+ function(fDone)
349
+ {
350
+ var testMeadow = newMeadow();
351
+
352
+ var tmpQuery = testMeadow.query
353
+ .addFilter('Type', 'Dog');
354
+
355
+ testMeadow.doReads(tmpQuery,
356
+ function(pError, pQuery, pRecords)
357
+ {
358
+ Expect(pRecords.length)
359
+ .to.equal(2);
360
+ // Records come back in GUID key order, so use set-based assertions
361
+ var tmpNames = pRecords.map(function(r) { return r.Name; });
362
+ Expect(tmpNames).to.include('Red');
363
+ Expect(tmpNames).to.include('Spot');
364
+ fDone();
365
+ }
366
+ );
367
+ }
368
+ );
369
+
370
+ test
371
+ (
372
+ 'Read records with LIKE filter',
373
+ function(fDone)
374
+ {
375
+ var testMeadow = newMeadow();
376
+
377
+ var tmpQuery = testMeadow.query
378
+ .addFilter('Name', '%Red%', 'LIKE');
379
+
380
+ testMeadow.doReads(tmpQuery,
381
+ function(pError, pQuery, pRecords)
382
+ {
383
+ Expect(pRecords.length)
384
+ .to.equal(2);
385
+ // Should match "Red Riding Hood" and "Red"
386
+ var tmpNames = pRecords.map(function(r) { return r.Name; });
387
+ Expect(tmpNames).to.include('Red Riding Hood');
388
+ Expect(tmpNames).to.include('Red');
389
+ fDone();
390
+ }
391
+ );
392
+ }
393
+ );
394
+
395
+ test
396
+ (
397
+ 'Read records with IN filter',
398
+ function(fDone)
399
+ {
400
+ var testMeadow = newMeadow();
401
+
402
+ var tmpQuery = testMeadow.query
403
+ .addFilter('Type', ['Bunny', 'Frog'], 'IN');
404
+
405
+ testMeadow.doReads(tmpQuery,
406
+ function(pError, pQuery, pRecords)
407
+ {
408
+ Expect(pRecords.length)
409
+ .to.equal(2);
410
+ var tmpTypes = pRecords.map(function(r) { return r.Type; });
411
+ Expect(tmpTypes).to.include('Bunny');
412
+ Expect(tmpTypes).to.include('Frog');
413
+ fDone();
414
+ }
415
+ );
416
+ }
417
+ );
418
+
419
+ test
420
+ (
421
+ 'Read records with comparison filter (>)',
422
+ function(fDone)
423
+ {
424
+ var testMeadow = newMeadow();
425
+
426
+ var tmpQuery = testMeadow.query
427
+ .addFilter('IDAnimal', 3, '>');
428
+
429
+ testMeadow.doReads(tmpQuery,
430
+ function(pError, pQuery, pRecords)
431
+ {
432
+ Expect(pRecords.length)
433
+ .to.equal(2);
434
+ // IDs 4 and 5 (not 6 since it's Deleted); order depends on GUID keys
435
+ var tmpIDs = pRecords.map(function(r) { return r.IDAnimal; });
436
+ Expect(tmpIDs).to.include(4);
437
+ Expect(tmpIDs).to.include(5);
438
+ fDone();
439
+ }
440
+ );
441
+ }
442
+ );
443
+
444
+ test
445
+ (
446
+ 'Read records with NOT IN filter',
447
+ function(fDone)
448
+ {
449
+ var testMeadow = newMeadow();
450
+
451
+ var tmpQuery = testMeadow.query
452
+ .addFilter('Type', ['Dog', 'Human', 'Frog'], 'NOT IN');
453
+
454
+ testMeadow.doReads(tmpQuery,
455
+ function(pError, pQuery, pRecords)
456
+ {
457
+ // Should only be the Bunny
458
+ Expect(pRecords.length)
459
+ .to.equal(1);
460
+ Expect(pRecords[0].Type)
461
+ .to.equal('Bunny');
462
+ fDone();
463
+ }
464
+ );
465
+ }
466
+ );
467
+
468
+ test
469
+ (
470
+ 'Read records with sorting',
471
+ function(fDone)
472
+ {
473
+ var testMeadow = newMeadow();
474
+
475
+ var tmpQuery = testMeadow.query
476
+ .addSort({Column:'Name', Direction:'Descending'});
477
+
478
+ testMeadow.doReads(tmpQuery,
479
+ function(pError, pQuery, pRecords)
480
+ {
481
+ Expect(pRecords.length)
482
+ .to.equal(5);
483
+ // Alphabetically descending
484
+ Expect(pRecords[0].Name)
485
+ .to.equal('Spot');
486
+ Expect(pRecords[pRecords.length - 1].Name)
487
+ .to.equal('Foo Foo');
488
+ fDone();
489
+ }
490
+ );
491
+ }
492
+ );
493
+
494
+ test
495
+ (
496
+ 'Read records with pagination (skip and limit)',
497
+ function(fDone)
498
+ {
499
+ var testMeadow = newMeadow();
500
+
501
+ var tmpQuery = testMeadow.query
502
+ .addSort({Column:'IDAnimal', Direction:'Ascending'})
503
+ .setCap(2)
504
+ .setBegin(1);
505
+
506
+ testMeadow.doReads(tmpQuery,
507
+ function(pError, pQuery, pRecords)
508
+ {
509
+ // Should skip 1 and return 2 (sorted by IDAnimal ascending)
510
+ Expect(pRecords.length)
511
+ .to.equal(2);
512
+ Expect(pRecords[0].IDAnimal)
513
+ .to.equal(2);
514
+ Expect(pRecords[1].IDAnimal)
515
+ .to.equal(3);
516
+ fDone();
517
+ }
518
+ );
519
+ }
520
+ );
521
+ }
522
+ );
523
+
524
+ suite
525
+ (
526
+ 'Update Operations',
527
+ function()
528
+ {
529
+ test
530
+ (
531
+ 'Update a record in the database',
532
+ function(fDone)
533
+ {
534
+ var testMeadow = newMeadow().setIDUser(42);
535
+
536
+ var tmpQuery = testMeadow.query
537
+ .addRecord({IDAnimal:2, Type:'Girl'});
538
+
539
+ testMeadow.doUpdate(tmpQuery,
540
+ function(pError, pQuery, pQueryRead, pRecord)
541
+ {
542
+ Expect(pRecord.Type)
543
+ .to.equal('Girl');
544
+ Expect(pRecord.Name)
545
+ .to.equal('Red Riding Hood');
546
+ Expect(pRecord.UpdatingIDUser)
547
+ .to.equal(42);
548
+ fDone();
549
+ }
550
+ );
551
+ }
552
+ );
553
+
554
+ test
555
+ (
556
+ 'Verify update persisted',
557
+ function(fDone)
558
+ {
559
+ var testMeadow = newMeadow();
560
+
561
+ var tmpQuery = testMeadow.query
562
+ .addFilter('IDAnimal', 2);
563
+
564
+ testMeadow.doRead(tmpQuery,
565
+ function(pError, pQuery, pRecord)
566
+ {
567
+ Expect(pRecord.Type)
568
+ .to.equal('Girl');
569
+ fDone();
570
+ }
571
+ );
572
+ }
573
+ );
574
+ }
575
+ );
576
+
577
+ suite
578
+ (
579
+ 'Count Operations',
580
+ function()
581
+ {
582
+ test
583
+ (
584
+ 'Count all non-deleted records',
585
+ function(fDone)
586
+ {
587
+ var testMeadow = newMeadow();
588
+
589
+ testMeadow.doCount(testMeadow.query,
590
+ function(pError, pQuery, pCount)
591
+ {
592
+ Expect(pCount)
593
+ .to.equal(5);
594
+ fDone();
595
+ }
596
+ );
597
+ }
598
+ );
599
+
600
+ test
601
+ (
602
+ 'Count records with filter',
603
+ function(fDone)
604
+ {
605
+ var testMeadow = newMeadow();
606
+
607
+ var tmpQuery = testMeadow.query
608
+ .addFilter('Type', 'Dog');
609
+
610
+ testMeadow.doCount(tmpQuery,
611
+ function(pError, pQuery, pCount)
612
+ {
613
+ Expect(pCount)
614
+ .to.equal(2);
615
+ fDone();
616
+ }
617
+ );
618
+ }
619
+ );
620
+ }
621
+ );
622
+
623
+ suite
624
+ (
625
+ 'Delete Operations',
626
+ function()
627
+ {
628
+ test
629
+ (
630
+ 'Soft-delete a record',
631
+ function(fDone)
632
+ {
633
+ var testMeadow = newMeadow().setIDUser(999);
634
+
635
+ var tmpQuery = testMeadow.query
636
+ .addFilter('IDAnimal', 5);
637
+
638
+ testMeadow.doDelete(tmpQuery,
639
+ function(pError, pQuery, pCount)
640
+ {
641
+ Expect(pCount)
642
+ .to.equal(1);
643
+ fDone();
644
+ }
645
+ );
646
+ }
647
+ );
648
+
649
+ test
650
+ (
651
+ 'Verify soft-deleted record is excluded from reads',
652
+ function(fDone)
653
+ {
654
+ var testMeadow = newMeadow();
655
+
656
+ testMeadow.doReads(testMeadow.query,
657
+ function(pError, pQuery, pRecords)
658
+ {
659
+ // Should now be 4 (Foo Foo, Red Riding Hood, Red, Spot)
660
+ Expect(pRecords.length)
661
+ .to.equal(4);
662
+ var tmpIDs = pRecords.map(function(r) { return r.IDAnimal; });
663
+ Expect(tmpIDs).to.not.include(5);
664
+ fDone();
665
+ }
666
+ );
667
+ }
668
+ );
669
+
670
+ test
671
+ (
672
+ 'Verify soft-deleted record still exists with disableDeleteTracking',
673
+ function(fDone)
674
+ {
675
+ var testMeadow = newMeadow();
676
+
677
+ var tmpQuery = testMeadow.query
678
+ .setDisableDeleteTracking(true)
679
+ .addFilter('IDAnimal', 5);
680
+
681
+ testMeadow.doRead(tmpQuery,
682
+ function(pError, pQuery, pRecord)
683
+ {
684
+ Expect(pRecord.IDAnimal)
685
+ .to.equal(5);
686
+ Expect(pRecord.Deleted)
687
+ .to.equal(1);
688
+ // Note: Meadow's Delete behavior does not propagate IDUser
689
+ // from meadow.setIDUser() (unlike Create and Update behaviors),
690
+ // so DeletingIDUser will be the default (0).
691
+ Expect(pRecord.DeletingIDUser)
692
+ .to.equal(0);
693
+ fDone();
694
+ }
695
+ );
696
+ }
697
+ );
698
+
699
+ test
700
+ (
701
+ 'Count excludes deleted records',
702
+ function(fDone)
703
+ {
704
+ var testMeadow = newMeadow();
705
+
706
+ testMeadow.doCount(testMeadow.query,
707
+ function(pError, pQuery, pCount)
708
+ {
709
+ Expect(pCount)
710
+ .to.equal(4);
711
+ fDone();
712
+ }
713
+ );
714
+ }
715
+ );
716
+ }
717
+ );
718
+
719
+ suite
720
+ (
721
+ 'Undelete Operations',
722
+ function()
723
+ {
724
+ test
725
+ (
726
+ 'Undelete a soft-deleted record',
727
+ function(fDone)
728
+ {
729
+ var testMeadow = newMeadow().setIDUser(777);
730
+
731
+ var tmpQuery = testMeadow.query
732
+ .addFilter('IDAnimal', 5);
733
+
734
+ testMeadow.doUndelete(tmpQuery,
735
+ function(pError, pQuery, pCount)
736
+ {
737
+ Expect(pCount)
738
+ .to.equal(1);
739
+ fDone();
740
+ }
741
+ );
742
+ }
743
+ );
744
+
745
+ test
746
+ (
747
+ 'Verify undeleted record is now visible',
748
+ function(fDone)
749
+ {
750
+ var testMeadow = newMeadow();
751
+
752
+ var tmpQuery = testMeadow.query
753
+ .addFilter('IDAnimal', 5);
754
+
755
+ testMeadow.doRead(tmpQuery,
756
+ function(pError, pQuery, pRecord)
757
+ {
758
+ Expect(pRecord.IDAnimal)
759
+ .to.equal(5);
760
+ Expect(pRecord.Deleted)
761
+ .to.equal(0);
762
+ Expect(pRecord.Name)
763
+ .to.equal('Gertrude');
764
+ fDone();
765
+ }
766
+ );
767
+ }
768
+ );
769
+
770
+ test
771
+ (
772
+ 'Count now includes undeleted record',
773
+ function(fDone)
774
+ {
775
+ var testMeadow = newMeadow();
776
+
777
+ testMeadow.doCount(testMeadow.query,
778
+ function(pError, pQuery, pCount)
779
+ {
780
+ Expect(pCount)
781
+ .to.equal(5);
782
+ fDone();
783
+ }
784
+ );
785
+ }
786
+ );
787
+ }
788
+ );
789
+
790
+ suite
791
+ (
792
+ 'Multiple Scopes',
793
+ function()
794
+ {
795
+ test
796
+ (
797
+ 'Create records in a different scope and verify isolation',
798
+ function(fDone)
799
+ {
800
+ var testMeadow = require('../source/Meadow.js')
801
+ .new(libFable, 'Vehicle')
802
+ .setProvider('RocksDB')
803
+ .setSchema([
804
+ { Column: "IDVehicle", Type:"AutoIdentity" },
805
+ { Column: "GUIDVehicle", Type:"AutoGUID" },
806
+ { Column: "CreateDate", Type:"CreateDate" },
807
+ { Column: "CreatingIDUser", Type:"CreateIDUser" },
808
+ { Column: "UpdateDate", Type:"UpdateDate" },
809
+ { Column: "UpdatingIDUser", Type:"UpdateIDUser" },
810
+ { Column: "Deleted", Type:"Deleted" },
811
+ { Column: "DeletingIDUser", Type:"DeleteIDUser" },
812
+ { Column: "DeleteDate", Type:"DeleteDate" }
813
+ ])
814
+ .setDefaultIdentifier('IDVehicle')
815
+ .setDefault({
816
+ IDVehicle: null,
817
+ GUIDVehicle: '',
818
+ CreateDate: false,
819
+ CreatingIDUser: 0,
820
+ UpdateDate: false,
821
+ UpdatingIDUser: 0,
822
+ Deleted: 0,
823
+ DeleteDate: false,
824
+ DeletingIDUser: 0,
825
+ Make: 'Unknown',
826
+ Model: 'Unknown'
827
+ });
828
+
829
+ var tmpQuery = testMeadow.query.clone()
830
+ .addRecord({Make:'Toyota', Model:'Camry'});
831
+
832
+ testMeadow.doCreate(tmpQuery,
833
+ function(pError, pQuery, pQueryRead, pRecord)
834
+ {
835
+ Expect(pRecord.Make).to.equal('Toyota');
836
+ Expect(pRecord.IDVehicle).to.equal(1);
837
+
838
+ // Now verify FableTest scope still has its 5 records
839
+ var animalMeadow = newMeadow();
840
+ animalMeadow.doCount(animalMeadow.query,
841
+ function(pError2, pQuery2, pCount)
842
+ {
843
+ Expect(pCount).to.equal(5);
844
+ fDone();
845
+ }
846
+ );
847
+ }
848
+ );
849
+ }
850
+ );
851
+ }
852
+ );
853
+
854
+ suite
855
+ (
856
+ 'Error Handling',
857
+ function()
858
+ {
859
+ test
860
+ (
861
+ 'Read with no connection should return error',
862
+ function(fDone)
863
+ {
864
+ var tmpFable2 = new (require('fable'))({
865
+ LogStreams: [{ level: 'fatal', streamtype: 'process.stdout' }]
866
+ });
867
+
868
+ var testMeadow = require('../source/Meadow.js')
869
+ .new(tmpFable2, 'FableTest')
870
+ .setProvider('RocksDB')
871
+ .setSchema(_AnimalSchema)
872
+ .setDefaultIdentifier('IDAnimal')
873
+ .setDefault(_AnimalDefault);
874
+
875
+ testMeadow.doReads(testMeadow.query,
876
+ function(pError, pQuery, pRecords)
877
+ {
878
+ Expect(pError).to.exist;
879
+ fDone();
880
+ }
881
+ );
882
+ }
883
+ );
884
+ }
885
+ );
886
+ }
887
+ );