foxhound 2.0.18 → 2.0.20

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 (36) hide show
  1. package/README.md +3 -2
  2. package/docs/README.md +32 -11
  3. package/docs/_cover.md +3 -2
  4. package/docs/_sidebar.md +21 -1
  5. package/docs/_topbar.md +7 -0
  6. package/docs/api/README.md +73 -0
  7. package/docs/api/addFilter.md +170 -0
  8. package/docs/api/addJoin.md +128 -0
  9. package/docs/api/addRecord.md +108 -0
  10. package/docs/api/addSort.md +109 -0
  11. package/docs/api/behaviorFlags.md +123 -0
  12. package/docs/api/buildQuery.md +146 -0
  13. package/docs/api/clone.md +115 -0
  14. package/docs/api/queryOverrides.md +82 -0
  15. package/docs/api/setCap.md +115 -0
  16. package/docs/api/setDataElements.md +95 -0
  17. package/docs/api/setDialect.md +78 -0
  18. package/docs/api/setDistinct.md +76 -0
  19. package/docs/api/setIDUser.md +80 -0
  20. package/docs/api/setScope.md +70 -0
  21. package/docs/architecture.md +134 -42
  22. package/docs/dialects/README.md +2 -0
  23. package/docs/dialects/postgresql.md +126 -0
  24. package/docs/quickstart.md +196 -0
  25. package/docs/retold-catalog.json +40 -1
  26. package/docs/retold-keyword-index.json +7996 -2630
  27. package/package.json +2 -2
  28. package/source/Foxhound-Dialects.js +4 -0
  29. package/source/dialects/DGraph/FoxHound-Dialect-DGraph.js +954 -0
  30. package/source/dialects/MongoDB/FoxHound-Dialect-MongoDB.js +902 -0
  31. package/source/dialects/PostgreSQL/FoxHound-Dialect-PostgreSQL.js +865 -0
  32. package/source/dialects/Solr/FoxHound-Dialect-Solr.js +895 -0
  33. package/test/FoxHound-Dialect-DGraph_tests.js +547 -0
  34. package/test/FoxHound-Dialect-MongoDB_tests.js +485 -0
  35. package/test/FoxHound-Dialect-PostgreSQL_tests.js +342 -0
  36. package/test/FoxHound-Dialect-Solr_tests.js +551 -0
@@ -0,0 +1,547 @@
1
+ /**
2
+ * Unit tests for FoxHound DGraph Dialect
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ */
8
+
9
+ var Chai = require('chai');
10
+ var Expect = Chai.expect;
11
+ var Assert = Chai.assert;
12
+
13
+ var libFable = require('fable');
14
+ const _Fable = new libFable({Product:'FoxhoundTestsDGraph'});
15
+ var libFoxHound = require('../source/FoxHound.js');
16
+
17
+ var _AnimalSchema = (
18
+ [
19
+ { Column: "IDAnimal", Type:"AutoIdentity" },
20
+ { Column: "GUIDAnimal", Type:"AutoGUID" },
21
+ { Column: "CreateDate", Type:"CreateDate" },
22
+ { Column: "CreatingIDUser", Type:"CreateIDUser" },
23
+ { Column: "UpdateDate", Type:"UpdateDate" },
24
+ { Column: "UpdatingIDUser", Type:"UpdateIDUser" },
25
+ { Column: "Deleted", Type:"Deleted" },
26
+ { Column: "DeletingIDUser", Type:"DeleteIDUser" },
27
+ { Column: "DeleteDate", Type:"DeleteDate" }
28
+ ]);
29
+
30
+ var _AnimalSchemaWithoutDeleted = (
31
+ [
32
+ { Column: "IDAnimal", Type:"AutoIdentity" },
33
+ { Column: "GUIDAnimal", Type:"AutoGUID" },
34
+ { Column: "CreateDate", Type:"CreateDate" },
35
+ { Column: "CreatingIDUser", Type:"CreateIDUser" },
36
+ { Column: "UpdateDate", Type:"UpdateDate" },
37
+ { Column: "UpdatingIDUser", Type:"UpdateIDUser" }
38
+ ]);
39
+
40
+ suite
41
+ (
42
+ 'FoxHound-Dialect-DGraph',
43
+ function()
44
+ {
45
+ setup
46
+ (
47
+ function()
48
+ {
49
+ }
50
+ );
51
+
52
+ suite
53
+ (
54
+ 'Object Sanity',
55
+ function()
56
+ {
57
+ test
58
+ (
59
+ 'initialize should build a happy little object',
60
+ function()
61
+ {
62
+ var testFoxHound = libFoxHound.new(_Fable).setDialect('DGraph');
63
+ Expect(testFoxHound.dialect.name)
64
+ .to.equal('DGraph');
65
+ Expect(testFoxHound)
66
+ .to.be.an('object', 'FoxHound with DGraph should initialize as an object directly from the require statement.');
67
+ }
68
+ );
69
+ }
70
+ );
71
+
72
+ suite
73
+ (
74
+ 'Basic Query Generation',
75
+ function()
76
+ {
77
+ test
78
+ (
79
+ 'Create Query',
80
+ function()
81
+ {
82
+ var tmpQuery = libFoxHound.new(_Fable)
83
+ .setDialect('DGraph')
84
+ .setScope('Animal')
85
+ .addRecord({IDAnimal:null, Name:'Foo Foo', Age:15});
86
+ tmpQuery.buildCreateQuery();
87
+ _Fable.log.trace('Create Query', tmpQuery.query);
88
+ var tmpOp = JSON.parse(tmpQuery.query.body);
89
+ Expect(tmpOp.type).to.equal('Animal');
90
+ Expect(tmpOp.operation).to.equal('mutate');
91
+ Expect(tmpOp.mutationType).to.equal('set');
92
+ Expect(tmpOp.document.Name).to.equal('Foo Foo');
93
+ Expect(tmpOp.document.Age).to.equal(15);
94
+ Expect(tmpOp.document['dgraph.type']).to.equal('Animal');
95
+ }
96
+ );
97
+ test
98
+ (
99
+ 'Create Query with Schema uses $$AUTOINCREMENT for AutoIdentity',
100
+ function()
101
+ {
102
+ var tmpQuery = libFoxHound.new(_Fable)
103
+ .setDialect('DGraph')
104
+ .setScope('Animal')
105
+ .addRecord({IDAnimal:null, GUIDAnimal:false, CreateDate:null, CreatingIDUser:null, UpdateDate:null, UpdatingIDUser:null, Deleted:0, Name:'Foo Foo', Age:15});
106
+ tmpQuery.query.schema = _AnimalSchema;
107
+ tmpQuery.query.IDUser = 37;
108
+ tmpQuery.query.UUID = 'test-guid-value';
109
+ tmpQuery.buildCreateQuery();
110
+ _Fable.log.trace('Create Query with Schema', tmpQuery.query);
111
+ var tmpOp = JSON.parse(tmpQuery.query.body);
112
+ Expect(tmpOp.document.IDAnimal).to.equal('$$AUTOINCREMENT');
113
+ Expect(tmpOp.document.GUIDAnimal).to.equal('test-guid-value');
114
+ Expect(tmpOp.document.CreateDate).to.equal('$$NOW');
115
+ Expect(tmpOp.document.CreatingIDUser).to.equal(37);
116
+ Expect(tmpOp.document.UpdateDate).to.equal('$$NOW');
117
+ Expect(tmpOp.document.UpdatingIDUser).to.equal(37);
118
+ Expect(tmpOp.document.Deleted).to.equal(0);
119
+ // DeleteDate and DeletingIDUser should be skipped
120
+ Expect(tmpOp.document).to.not.have.property('DeleteDate');
121
+ Expect(tmpOp.document).to.not.have.property('DeletingIDUser');
122
+ Expect(tmpOp.document.Name).to.equal('Foo Foo');
123
+ // dgraph.type should be set
124
+ Expect(tmpOp.document['dgraph.type']).to.equal('Animal');
125
+ // counterScope should be present
126
+ Expect(tmpOp.counterScope).to.equal('Animal.IDAnimal');
127
+ }
128
+ );
129
+ test
130
+ (
131
+ 'Create Query with existing GUID passes it through',
132
+ function()
133
+ {
134
+ var tmpQuery = libFoxHound.new(_Fable)
135
+ .setDialect('DGraph')
136
+ .setScope('Animal')
137
+ .addRecord({IDAnimal:null, GUIDAnimal:'my-custom-guid-value'});
138
+ tmpQuery.query.schema = _AnimalSchema;
139
+ tmpQuery.query.UUID = 'should-not-use-this';
140
+ tmpQuery.buildCreateQuery();
141
+ var tmpOp = JSON.parse(tmpQuery.query.body);
142
+ Expect(tmpOp.document.GUIDAnimal).to.equal('my-custom-guid-value');
143
+ }
144
+ );
145
+ test
146
+ (
147
+ 'Bad Create Query',
148
+ function()
149
+ {
150
+ var tmpQuery = libFoxHound.new(_Fable).setDialect('DGraph');
151
+ tmpQuery.buildCreateQuery();
152
+ tmpQuery.addRecord({});
153
+ tmpQuery.buildCreateQuery();
154
+ _Fable.log.trace('Create Query', tmpQuery.query);
155
+ Expect(tmpQuery.query.body)
156
+ .to.equal(false);
157
+ }
158
+ );
159
+ test
160
+ (
161
+ 'Read Query',
162
+ function()
163
+ {
164
+ var tmpQuery = libFoxHound.new(_Fable).setDialect('DGraph').setScope('Animal');
165
+ tmpQuery.buildReadQuery();
166
+ _Fable.log.trace('Simple Select Query', tmpQuery.query);
167
+ var tmpOp = JSON.parse(tmpQuery.query.body);
168
+ Expect(tmpOp.type).to.equal('Animal');
169
+ Expect(tmpOp.operation).to.equal('query');
170
+ Expect(tmpOp.queryName).to.equal('results');
171
+ Expect(tmpOp.query).to.contain('func: type(Animal)');
172
+ Expect(tmpOp.query).to.contain('uid');
173
+ }
174
+ );
175
+ test
176
+ (
177
+ 'Read Query with Sort',
178
+ function()
179
+ {
180
+ var tmpQuery = libFoxHound.new(_Fable).setDialect('DGraph').setScope('Animal');
181
+ tmpQuery.addSort({Column:'Cost',Direction:'Descending'});
182
+ tmpQuery.buildReadQuery();
183
+ var tmpOp = JSON.parse(tmpQuery.query.body);
184
+ Expect(tmpOp.query).to.contain('orderdesc: Cost');
185
+ }
186
+ );
187
+ test
188
+ (
189
+ 'Read Query with Distinct',
190
+ function()
191
+ {
192
+ var tmpQuery = libFoxHound.new(_Fable).setDialect('DGraph').setScope('Animal');
193
+ tmpQuery.addSort({Column:'Cost',Direction:'Descending'})
194
+ .setDistinct(true);
195
+ tmpQuery.buildReadQuery();
196
+ var tmpOp = JSON.parse(tmpQuery.query.body);
197
+ Expect(tmpOp.distinct).to.equal(true);
198
+ }
199
+ );
200
+ test
201
+ (
202
+ 'Complex Read Query with cap, begin, dataElements, sort, filter',
203
+ function()
204
+ {
205
+ var tmpQuery = libFoxHound.new(_Fable)
206
+ .setDialect('DGraph')
207
+ .setScope('Animal')
208
+ .setCap(10)
209
+ .setBegin(5)
210
+ .setDataElements(['Name', 'Age', 'Cost'])
211
+ .setSort([{Column:'Age',Direction:'Ascending'}])
212
+ .setFilter({Column:'Age',Operator:'=',Value:'15',Connector:'AND',Parameter:'Age'});
213
+ tmpQuery.addSort('Cost');
214
+ tmpQuery.buildReadQuery();
215
+ _Fable.log.trace('Select Query', tmpQuery.query);
216
+ var tmpOp = JSON.parse(tmpQuery.query.body);
217
+ Expect(tmpOp.query).to.contain('first: 10');
218
+ Expect(tmpOp.query).to.contain('offset: 5');
219
+ Expect(tmpOp.query).to.contain('orderasc: Age');
220
+ Expect(tmpOp.query).to.contain('orderasc: Cost');
221
+ Expect(tmpOp.query).to.contain('@filter(eq(Age, "15"))');
222
+ Expect(tmpOp.query).to.contain('Name');
223
+ Expect(tmpOp.query).to.contain('Age');
224
+ Expect(tmpOp.query).to.contain('Cost');
225
+ }
226
+ );
227
+ test
228
+ (
229
+ 'Complex Read Query with Filters including OR, IN, IS NOT NULL',
230
+ function()
231
+ {
232
+ var tmpQuery = libFoxHound.new(_Fable)
233
+ .setDialect('DGraph')
234
+ .setScope('Animal')
235
+ .setDataElements(['Name', 'Age', 'Cost'])
236
+ .setCap(100)
237
+ .addFilter('Age', '25')
238
+ .addFilter('', '', '(')
239
+ .addFilter('Color', 'Red')
240
+ .addFilter('Color', 'Green', '=', 'OR')
241
+ .addFilter('', '', ')')
242
+ .addFilter('Description', '', 'IS NOT NULL')
243
+ .addFilter('IDOffice', [10, 11, 15, 18, 22], 'IN');
244
+ tmpQuery.buildReadQuery();
245
+ _Fable.log.trace('Select Query', tmpQuery.query);
246
+ var tmpOp = JSON.parse(tmpQuery.query.body);
247
+ // Should have the filter clause
248
+ Expect(tmpOp.query).to.contain('@filter(');
249
+ Expect(tmpOp.query).to.contain('eq(Age, "25")');
250
+ // OR group
251
+ Expect(tmpOp.query).to.contain('(eq(Color, "Red") OR eq(Color, "Green"))');
252
+ // IS NOT NULL
253
+ Expect(tmpOp.query).to.contain('has(Description)');
254
+ // IN
255
+ Expect(tmpOp.query).to.contain('eq(IDOffice, [10, 11, 15, 18, 22])');
256
+ }
257
+ );
258
+ test
259
+ (
260
+ 'Read Query with Deleted schema auto-adds Deleted filter',
261
+ function()
262
+ {
263
+ var tmpQuery = libFoxHound.new(_Fable)
264
+ .setDialect('DGraph')
265
+ .setScope('Animal')
266
+ .addFilter('Age', '3');
267
+ tmpQuery.query.schema = _AnimalSchema;
268
+ tmpQuery.buildReadQuery();
269
+ var tmpOp = JSON.parse(tmpQuery.query.body);
270
+ Expect(tmpOp.query).to.contain('eq(Deleted, 0)');
271
+ }
272
+ );
273
+ test
274
+ (
275
+ 'Read Query with Deleted tracking disabled does NOT add Deleted filter',
276
+ function()
277
+ {
278
+ var tmpQuery = libFoxHound.new(_Fable)
279
+ .setDialect('DGraph')
280
+ .setScope('Animal')
281
+ .addFilter('Age', '3');
282
+ tmpQuery.query.schema = _AnimalSchema;
283
+ tmpQuery.query.disableDeleteTracking = true;
284
+ tmpQuery.buildReadQuery();
285
+ var tmpOp = JSON.parse(tmpQuery.query.body);
286
+ // Deleted may appear as a field name but should NOT appear in the filter
287
+ Expect(tmpOp.query).to.not.contain('eq(Deleted');
288
+ }
289
+ );
290
+ test
291
+ (
292
+ 'Read Query without limit has no pagination',
293
+ function()
294
+ {
295
+ var tmpQuery = libFoxHound.new(_Fable)
296
+ .setDialect('DGraph')
297
+ .setScope('Animal');
298
+ tmpQuery.buildReadQuery();
299
+ var tmpOp = JSON.parse(tmpQuery.query.body);
300
+ Expect(tmpOp.query).to.not.contain('first:');
301
+ Expect(tmpOp.query).to.not.contain('offset:');
302
+ }
303
+ );
304
+ test
305
+ (
306
+ 'Update Query',
307
+ function()
308
+ {
309
+ var tmpQuery = libFoxHound.new(_Fable)
310
+ .setDialect('DGraph')
311
+ .setScope('Animal')
312
+ .addFilter('IDAnimal', 9)
313
+ .addRecord({Name:'Froggy', Age:12});
314
+ tmpQuery.buildUpdateQuery();
315
+ _Fable.log.trace('Update Query', tmpQuery.query);
316
+ var tmpOp = JSON.parse(tmpQuery.query.body);
317
+ Expect(tmpOp.type).to.equal('Animal');
318
+ Expect(tmpOp.operation).to.equal('upsert');
319
+ Expect(tmpOp.queryName).to.equal('updateTargets');
320
+ Expect(tmpOp.queryForUIDs).to.contain('func: type(Animal)');
321
+ Expect(tmpOp.queryForUIDs).to.contain('@filter(eq(IDAnimal, 9))');
322
+ Expect(tmpOp.update.Name).to.equal('Froggy');
323
+ Expect(tmpOp.update.Age).to.equal(12);
324
+ }
325
+ );
326
+ test
327
+ (
328
+ 'Update Query with Schema skips identity and create columns',
329
+ function()
330
+ {
331
+ var tmpQuery = libFoxHound.new(_Fable)
332
+ .setDialect('DGraph')
333
+ .setScope('Animal')
334
+ .addFilter('IDAnimal', 9)
335
+ .addRecord({IDAnimal:9, CreateDate:'2020-01-01', CreatingIDUser:1, UpdateDate:null, UpdatingIDUser:null, Name:'Froggy', Age:12});
336
+ tmpQuery.query.schema = _AnimalSchema;
337
+ tmpQuery.query.IDUser = 37;
338
+ tmpQuery.buildUpdateQuery();
339
+ var tmpOp = JSON.parse(tmpQuery.query.body);
340
+ Expect(tmpOp.update).to.not.have.property('IDAnimal');
341
+ Expect(tmpOp.update).to.not.have.property('CreateDate');
342
+ Expect(tmpOp.update).to.not.have.property('CreatingIDUser');
343
+ Expect(tmpOp.update.UpdateDate).to.equal('$$NOW');
344
+ Expect(tmpOp.update.UpdatingIDUser).to.equal(37);
345
+ Expect(tmpOp.update.Name).to.equal('Froggy');
346
+ }
347
+ );
348
+ test
349
+ (
350
+ 'Count Query',
351
+ function()
352
+ {
353
+ var tmpQuery = libFoxHound.new(_Fable)
354
+ .setDialect('DGraph')
355
+ .setScope('Animal')
356
+ .addFilter('Age', '3');
357
+ tmpQuery.buildCountQuery();
358
+ _Fable.log.trace('Count Query', tmpQuery.query);
359
+ var tmpOp = JSON.parse(tmpQuery.query.body);
360
+ Expect(tmpOp.type).to.equal('Animal');
361
+ Expect(tmpOp.operation).to.equal('query');
362
+ Expect(tmpOp.isCount).to.equal(true);
363
+ Expect(tmpOp.query).to.contain('count(uid)');
364
+ Expect(tmpOp.query).to.contain('eq(Age, "3")');
365
+ }
366
+ );
367
+ test
368
+ (
369
+ 'Delete Query with soft delete schema',
370
+ function()
371
+ {
372
+ var tmpQuery = libFoxHound.new(_Fable)
373
+ .setDialect('DGraph')
374
+ .setScope('Animal')
375
+ .addFilter('IDAnimal', 9);
376
+ tmpQuery.query.schema = _AnimalSchema;
377
+ tmpQuery.query.IDUser = 37;
378
+ tmpQuery.buildDeleteQuery();
379
+ _Fable.log.trace('Delete Query', tmpQuery.query);
380
+ var tmpOp = JSON.parse(tmpQuery.query.body);
381
+ Expect(tmpOp.operation).to.equal('upsert');
382
+ Expect(tmpOp.queryName).to.equal('deleteTargets');
383
+ Expect(tmpOp.queryForUIDs).to.contain('eq(IDAnimal, 9)');
384
+ Expect(tmpOp.queryForUIDs).to.contain('eq(Deleted, 0)');
385
+ Expect(tmpOp.update.Deleted).to.equal(1);
386
+ Expect(tmpOp.update.DeleteDate).to.equal('$$NOW');
387
+ Expect(tmpOp.update.DeletingIDUser).to.equal(37);
388
+ }
389
+ );
390
+ test
391
+ (
392
+ 'Delete Query without schema does hard delete',
393
+ function()
394
+ {
395
+ var tmpQuery = libFoxHound.new(_Fable)
396
+ .setDialect('DGraph')
397
+ .setScope('Animal')
398
+ .addFilter('IDAnimal', 9);
399
+ tmpQuery.buildDeleteQuery();
400
+ _Fable.log.trace('Delete Query', tmpQuery.query);
401
+ var tmpOp = JSON.parse(tmpQuery.query.body);
402
+ Expect(tmpOp.operation).to.equal('delete');
403
+ Expect(tmpOp.queryForUIDs).to.contain('eq(IDAnimal, 9)');
404
+ }
405
+ );
406
+ test
407
+ (
408
+ 'Undelete Query',
409
+ function()
410
+ {
411
+ var tmpQuery = libFoxHound.new(_Fable)
412
+ .setDialect('DGraph')
413
+ .setScope('Animal')
414
+ .addFilter('IDAnimal', 9);
415
+ tmpQuery.query.schema = _AnimalSchema;
416
+ tmpQuery.query.IDUser = 37;
417
+ tmpQuery.buildUndeleteQuery();
418
+ _Fable.log.trace('Undelete Query', tmpQuery.query);
419
+ var tmpOp = JSON.parse(tmpQuery.query.body);
420
+ Expect(tmpOp.operation).to.equal('upsert');
421
+ Expect(tmpOp.queryName).to.equal('undeleteTargets');
422
+ Expect(tmpOp.update.Deleted).to.equal(0);
423
+ Expect(tmpOp.update.UpdateDate).to.equal('$$NOW');
424
+ Expect(tmpOp.update.UpdatingIDUser).to.equal(37);
425
+ }
426
+ );
427
+ test
428
+ (
429
+ 'Undelete Query without Deleted column returns noop',
430
+ function()
431
+ {
432
+ var tmpQuery = libFoxHound.new(_Fable)
433
+ .setDialect('DGraph')
434
+ .setScope('Animal')
435
+ .addFilter('IDAnimal', 9);
436
+ tmpQuery.query.schema = _AnimalSchemaWithoutDeleted;
437
+ tmpQuery.buildUndeleteQuery();
438
+ var tmpOp = JSON.parse(tmpQuery.query.body);
439
+ Expect(tmpOp.operation).to.equal('noop');
440
+ }
441
+ );
442
+ test
443
+ (
444
+ 'dgraphOperation is stored in query.parameters',
445
+ function()
446
+ {
447
+ var tmpQuery = libFoxHound.new(_Fable)
448
+ .setDialect('DGraph')
449
+ .setScope('Animal');
450
+ tmpQuery.buildReadQuery();
451
+ Expect(tmpQuery.query.parameters.dgraphOperation).to.be.an('object');
452
+ Expect(tmpQuery.query.parameters.dgraphOperation.type).to.equal('Animal');
453
+ Expect(tmpQuery.query.parameters.dgraphOperation.operation).to.equal('query');
454
+ }
455
+ );
456
+ test
457
+ (
458
+ 'Filter with comparison operators',
459
+ function()
460
+ {
461
+ var tmpQuery = libFoxHound.new(_Fable)
462
+ .setDialect('DGraph')
463
+ .setScope('Animal')
464
+ .addFilter('Age', 10, '>')
465
+ .addFilter('Cost', 100, '<=');
466
+ tmpQuery.buildReadQuery();
467
+ var tmpOp = JSON.parse(tmpQuery.query.body);
468
+ Expect(tmpOp.query).to.contain('gt(Age, 10)');
469
+ Expect(tmpOp.query).to.contain('le(Cost, 100)');
470
+ }
471
+ );
472
+ test
473
+ (
474
+ 'Filter with LIKE operator converts to regexp',
475
+ function()
476
+ {
477
+ var tmpQuery = libFoxHound.new(_Fable)
478
+ .setDialect('DGraph')
479
+ .setScope('Animal')
480
+ .addFilter('Name', '%Foo%', 'LIKE');
481
+ tmpQuery.buildReadQuery();
482
+ var tmpOp = JSON.parse(tmpQuery.query.body);
483
+ Expect(tmpOp.query).to.contain('regexp(Name, /.*Foo.*/i)');
484
+ }
485
+ );
486
+ test
487
+ (
488
+ 'Filter with IS NULL',
489
+ function()
490
+ {
491
+ var tmpQuery = libFoxHound.new(_Fable)
492
+ .setDialect('DGraph')
493
+ .setScope('Animal')
494
+ .addFilter('Description', '', 'IS NULL');
495
+ tmpQuery.buildReadQuery();
496
+ var tmpOp = JSON.parse(tmpQuery.query.body);
497
+ Expect(tmpOp.query).to.contain('NOT has(Description)');
498
+ }
499
+ );
500
+ test
501
+ (
502
+ 'Filter with != operator',
503
+ function()
504
+ {
505
+ var tmpQuery = libFoxHound.new(_Fable)
506
+ .setDialect('DGraph')
507
+ .setScope('Animal')
508
+ .addFilter('Name', 'Cat', '!=');
509
+ tmpQuery.buildReadQuery();
510
+ var tmpOp = JSON.parse(tmpQuery.query.body);
511
+ Expect(tmpOp.query).to.contain('NOT eq(Name, "Cat")');
512
+ }
513
+ );
514
+ test
515
+ (
516
+ 'Filter with NOT IN operator',
517
+ function()
518
+ {
519
+ var tmpQuery = libFoxHound.new(_Fable)
520
+ .setDialect('DGraph')
521
+ .setScope('Animal')
522
+ .addFilter('IDOffice', [1, 2, 3], 'NOT IN');
523
+ tmpQuery.buildReadQuery();
524
+ var tmpOp = JSON.parse(tmpQuery.query.body);
525
+ Expect(tmpOp.query).to.contain('NOT eq(IDOffice, [1, 2, 3])');
526
+ }
527
+ );
528
+ test
529
+ (
530
+ 'Multiple sorts ascending and descending',
531
+ function()
532
+ {
533
+ var tmpQuery = libFoxHound.new(_Fable)
534
+ .setDialect('DGraph')
535
+ .setScope('Animal')
536
+ .addSort({Column:'Name', Direction:'Ascending'})
537
+ .addSort({Column:'Age', Direction:'Descending'});
538
+ tmpQuery.buildReadQuery();
539
+ var tmpOp = JSON.parse(tmpQuery.query.body);
540
+ Expect(tmpOp.query).to.contain('orderasc: Name');
541
+ Expect(tmpOp.query).to.contain('orderdesc: Age');
542
+ }
543
+ );
544
+ }
545
+ );
546
+ }
547
+ );