@nymphjs/nymph 1.0.0-beta.9 → 1.0.0-beta.91

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 (96) hide show
  1. package/CHANGELOG.md +436 -0
  2. package/README.md +10 -20
  3. package/dist/Entity.d.ts +277 -10
  4. package/dist/Entity.js +543 -148
  5. package/dist/Entity.js.map +1 -1
  6. package/dist/Entity.test.js +53 -13
  7. package/dist/Entity.test.js.map +1 -1
  8. package/dist/Entity.types.d.ts +249 -23
  9. package/dist/Entity.types.js +1 -2
  10. package/dist/Nymph.d.ts +431 -12
  11. package/dist/Nymph.js +692 -180
  12. package/dist/Nymph.js.map +1 -1
  13. package/dist/Nymph.types.d.ts +65 -7
  14. package/dist/Nymph.types.js +3 -5
  15. package/dist/Nymph.types.js.map +1 -1
  16. package/dist/conf/d.d.ts +43 -0
  17. package/dist/conf/d.js +1 -2
  18. package/dist/conf/defaults.d.ts +1 -1
  19. package/dist/conf/defaults.js +26 -3
  20. package/dist/conf/defaults.js.map +1 -1
  21. package/dist/conf/index.d.ts +2 -2
  22. package/dist/conf/index.js +2 -8
  23. package/dist/conf/index.js.map +1 -1
  24. package/dist/driver/NymphDriver.d.ts +137 -39
  25. package/dist/driver/NymphDriver.js +344 -194
  26. package/dist/driver/NymphDriver.js.map +1 -1
  27. package/dist/driver/index.d.ts +2 -2
  28. package/dist/driver/index.js +3 -23
  29. package/dist/driver/index.js.map +1 -1
  30. package/dist/driver/testArtifacts.d.ts +2 -2
  31. package/dist/driver/testArtifacts.js +557 -92
  32. package/dist/driver/testArtifacts.js.map +1 -1
  33. package/dist/errors/ClassNotAvailableError.js +1 -5
  34. package/dist/errors/ClassNotAvailableError.js.map +1 -1
  35. package/dist/errors/EntityConflictError.js +1 -5
  36. package/dist/errors/EntityConflictError.js.map +1 -1
  37. package/dist/errors/EntityInvalidDataError.d.ts +6 -0
  38. package/dist/errors/EntityInvalidDataError.js +8 -6
  39. package/dist/errors/EntityInvalidDataError.js.map +1 -1
  40. package/dist/errors/EntityIsSleepingReferenceError.js +1 -5
  41. package/dist/errors/EntityIsSleepingReferenceError.js.map +1 -1
  42. package/dist/errors/EntityUniqueConstraintError.d.ts +3 -0
  43. package/dist/errors/EntityUniqueConstraintError.js +7 -0
  44. package/dist/errors/EntityUniqueConstraintError.js.map +1 -0
  45. package/dist/errors/InvalidParametersError.js +1 -5
  46. package/dist/errors/InvalidParametersError.js.map +1 -1
  47. package/dist/errors/InvalidStateError.d.ts +3 -0
  48. package/dist/errors/InvalidStateError.js +7 -0
  49. package/dist/errors/InvalidStateError.js.map +1 -0
  50. package/dist/errors/NotConfiguredError.js +1 -5
  51. package/dist/errors/NotConfiguredError.js.map +1 -1
  52. package/dist/errors/QueryFailedError.js +2 -5
  53. package/dist/errors/QueryFailedError.js.map +1 -1
  54. package/dist/errors/UnableToConnectError.js +1 -5
  55. package/dist/errors/UnableToConnectError.js.map +1 -1
  56. package/dist/errors/index.d.ts +10 -8
  57. package/dist/errors/index.js +10 -24
  58. package/dist/errors/index.js.map +1 -1
  59. package/dist/index.d.ts +11 -11
  60. package/dist/index.js +14 -34
  61. package/dist/index.js.map +1 -1
  62. package/dist/nymphJoiProps.js +10 -15
  63. package/dist/nymphJoiProps.js.map +1 -1
  64. package/dist/testArtifacts.d.ts +18 -6
  65. package/dist/testArtifacts.js +32 -37
  66. package/dist/testArtifacts.js.map +1 -1
  67. package/dist/testMocks.d.ts +15 -12
  68. package/dist/testMocks.js +40 -29
  69. package/dist/testMocks.js.map +1 -1
  70. package/dist/utils.d.ts +4 -4
  71. package/dist/utils.js +40 -29
  72. package/dist/utils.js.map +1 -1
  73. package/jest.config.js +11 -2
  74. package/package.json +22 -19
  75. package/src/Entity.test.ts +52 -7
  76. package/src/Entity.ts +458 -147
  77. package/src/Entity.types.ts +64 -74
  78. package/src/Nymph.ts +754 -321
  79. package/src/Nymph.types.ts +131 -26
  80. package/src/conf/d.ts +25 -0
  81. package/src/conf/defaults.ts +34 -1
  82. package/src/conf/index.ts +2 -2
  83. package/src/driver/NymphDriver.ts +362 -359
  84. package/src/driver/index.ts +2 -2
  85. package/src/driver/testArtifacts.ts +609 -185
  86. package/src/errors/EntityUniqueConstraintError.ts +6 -0
  87. package/src/errors/InvalidStateError.ts +6 -0
  88. package/src/errors/index.ts +12 -8
  89. package/src/index.ts +11 -11
  90. package/src/nymphJoiProps.ts +2 -2
  91. package/src/testArtifacts.ts +19 -20
  92. package/src/testMocks.ts +60 -35
  93. package/src/type/locutus.d.ts +3 -0
  94. package/src/utils.ts +39 -18
  95. package/tsconfig.json +5 -3
  96. package/typedoc.json +4 -0
@@ -1,20 +1,27 @@
1
- import fs from 'fs';
2
- import strtotime from 'locutus/php/datetime/strtotime';
1
+ import { dirname } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import fs from 'node:fs';
4
+ import strtotime from 'locutus/php/datetime/strtotime.js';
3
5
  import { guid } from '@nymphjs/guid';
4
6
 
5
- import type Nymph from '../Nymph';
7
+ import type Nymph from '../Nymph.js';
8
+ import { EntityUniqueConstraintError } from '../errors/index.js';
6
9
  import {
7
10
  TestBModel as TestBModelClass,
8
11
  TestModel as TestModelClass,
9
12
  TestModelData,
10
- } from '../testArtifacts';
13
+ TestEmptyModel as TestEmptyModelClass,
14
+ } from '../testArtifacts.js';
11
15
 
12
- export function QueriesTest(
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+
18
+ export function EntitiesTest(
13
19
  nymph: Nymph,
14
- it: (name: string, fn: () => void) => void
20
+ it: (name: string, fn: () => void) => void,
15
21
  ) {
16
22
  const TestModel = nymph.addEntityClass(TestModelClass);
17
23
  const TestBModel = nymph.addEntityClass(TestBModelClass);
24
+ const TestEmptyModel = nymph.addEntityClass(TestEmptyModelClass);
18
25
 
19
26
  let testEntity: TestModelClass & TestModelData;
20
27
  let testGuid: string;
@@ -34,12 +41,15 @@ export function QueriesTest(
34
41
  testEntity.name = 'Entity Test ' + new Date().toLocaleString();
35
42
  testEntity.null = null;
36
43
  testEntity.string = 'test';
37
- testEntity.array = ['full', 'of', 'values', 500];
38
- testEntity.match = `Hello, my name is Edward McCheese. It is a pleasure to meet you. As you can see, I have several hats of the most pleasant nature.
39
-
40
- This one's email address is nice_hat-wednesday+newyork@im-a-hat.hat.
41
- This one's phone number is (555) 555-1818.
42
- This one's zip code is 92064.`;
44
+ testEntity.array = [
45
+ 'full',
46
+ 'of',
47
+ 'values',
48
+ 500,
49
+ { test: true },
50
+ { nullbyte: '\\\x00\u0000 \x00' },
51
+ ];
52
+ testEntity.match = matchValue;
43
53
  testEntity.number = 30;
44
54
  testEntity.numberString = '30';
45
55
  testEntity.timestamp = Date.now();
@@ -59,18 +69,10 @@ This one's zip code is 92064.`;
59
69
  entityReferenceTest.test = 'good';
60
70
  expect(await entityReferenceTest.$save()).toEqual(true);
61
71
 
62
- // Test synchronous getEntity.
63
- testEntity = nymph.driver.getEntitySync(
64
- { class: TestModel },
65
- testGuid
66
- ) as TestModelClass & TestModelData;
67
- expect(testEntity).toBeInstanceOf(TestModel);
68
- expect(testEntity.guid).toEqual(testGuid);
69
-
70
72
  // Test asynchronous getEntity.
71
73
  testEntity = (await nymph.getEntity(
72
74
  { class: TestModel },
73
- testGuid
75
+ testGuid,
74
76
  )) as TestModelClass & TestModelData;
75
77
  expect(testEntity).toBeInstanceOf(TestModel);
76
78
  expect(testEntity.guid).toEqual(testGuid);
@@ -84,6 +86,8 @@ This one's zip code is 92064.`;
84
86
  for (let i = 0; i < 100; i++) {
85
87
  const testEntity = await TestModel.factory();
86
88
  testEntity.name = `Multi Test ${i}`;
89
+ // Reverse the number for sort testing.
90
+ testEntity.number = 100 - i;
87
91
  testEntity.$removeTag('test');
88
92
  testEntity.$addTag('multiTest');
89
93
  expect(await testEntity.$save()).toEqual(true);
@@ -94,20 +98,36 @@ This one's zip code is 92064.`;
94
98
  }
95
99
 
96
100
  it('delete old test data', async () => {
97
- let all = await nymph.getEntities({ class: TestModel });
98
- expect(Array.isArray(all)).toEqual(true);
99
- for (const cur of all) {
101
+ let amodels = await nymph.getEntities({ class: TestModel });
102
+ expect(Array.isArray(amodels)).toEqual(true);
103
+ for (const cur of amodels) {
100
104
  expect(await cur.$delete()).toEqual(true);
101
105
  }
102
106
 
103
- all = await nymph.getEntities({ class: TestModel });
104
- expect(all.length).toEqual(0);
107
+ amodels = await nymph.getEntities({ class: TestModel });
108
+ expect(amodels.length).toEqual(0);
109
+
110
+ let bmodels = await nymph.getEntities({ class: TestBModel });
111
+ expect(Array.isArray(bmodels)).toEqual(true);
112
+ for (const cur of bmodels) {
113
+ expect(await cur.$delete()).toEqual(true);
114
+ }
115
+
116
+ bmodels = await nymph.getEntities({ class: TestBModel });
117
+ expect(bmodels.length).toEqual(0);
105
118
  });
106
119
 
107
120
  it('create entity', async () => {
108
121
  await createTestEntities();
109
122
  });
110
123
 
124
+ it("doesn't create empty entity", async () => {
125
+ const testEntity = await TestEmptyModel.factory();
126
+
127
+ expect(await testEntity.$save()).toBeFalsy();
128
+ expect(testEntity.guid).toBeNull();
129
+ });
130
+
111
131
  it('update mdate on save', async () => {
112
132
  await createTestEntities();
113
133
 
@@ -139,6 +159,35 @@ This one's zip code is 92064.`;
139
159
  expect(testEntity.$is(resultEntity)).toEqual(false);
140
160
  });
141
161
 
162
+ it('guaranteed guid', async () => {
163
+ // Creating entity...
164
+ const testEntity = await TestModel.factory();
165
+
166
+ // Saving entity...
167
+ testEntity.name = 'Entity Test ' + new Date().toLocaleString();
168
+ testEntity.null = null;
169
+ testEntity.string = 'test';
170
+ testEntity.array = [];
171
+ testEntity.match = matchValue;
172
+ testEntity.number = 30;
173
+ testEntity.numberString = '30';
174
+ testEntity.timestamp = Date.now();
175
+
176
+ // Get the guaranteed GUID.
177
+ const testGuid = testEntity.$getGuaranteedGUID();
178
+
179
+ expect(await testEntity.$save()).toEqual(true);
180
+ expect(testEntity.guid).not.toBeNull();
181
+ expect(testEntity.guid).toEqual(testGuid);
182
+
183
+ // Retrieving entity by GUID...
184
+ let resultEntity = await nymph.getEntity({ class: TestModel }, testGuid);
185
+ expect(testEntity.$is(resultEntity)).toEqual(true);
186
+
187
+ // Delete the entity.
188
+ expect(await testEntity.$delete()).toEqual(true);
189
+ });
190
+
142
191
  it('transactions', async () => {
143
192
  await createTestEntities();
144
193
 
@@ -150,7 +199,7 @@ This one's zip code is 92064.`;
150
199
 
151
200
  if (!(await transaction.inTransaction())) {
152
201
  console.log(
153
- 'This Nymph driver or database seems to not support transactions. Skipping transaction tests.'
202
+ 'This Nymph driver or database seems to not support transactions. Skipping transaction tests.',
154
203
  );
155
204
  await transaction.rollback('test');
156
205
  return;
@@ -181,7 +230,7 @@ This one's zip code is 92064.`;
181
230
  expect(await testEntity.$delete()).toEqual(true);
182
231
  const resultEntity = await transaction.getEntity(
183
232
  { class: TestModel },
184
- testGuid
233
+ testGuid,
185
234
  );
186
235
  expect(resultEntity).toBeNull();
187
236
 
@@ -194,13 +243,13 @@ This one's zip code is 92064.`;
194
243
  // Verify it's back.
195
244
  testEntity = (await transaction.getEntity(
196
245
  { class: TestModel },
197
- testGuid
246
+ testGuid,
198
247
  )) as TestModelClass & TestModelData;
199
248
 
200
249
  expect(testEntity.guid).toEqual(testGuid);
201
250
 
202
- // Start a new transaction.
203
- transaction = await nymph.startTransaction('test');
251
+ // Start a new transaction with a dot in the name.
252
+ transaction = await nymph.startTransaction('test.1');
204
253
  testEntity.$nymph = transaction;
205
254
 
206
255
  // Verify in a transaction.
@@ -211,7 +260,7 @@ This one's zip code is 92064.`;
211
260
  expect(await testEntity.$save()).toEqual(true);
212
261
 
213
262
  // Commit the transaction.
214
- await transaction.commit('test');
263
+ await transaction.commit('test.1');
215
264
  testEntity.$nymph = nymph;
216
265
 
217
266
  // Verify not in a transaction.
@@ -240,7 +289,7 @@ This one's zip code is 92064.`;
240
289
  limit: 1,
241
290
  sort: 'cdate',
242
291
  },
243
- { type: '&', tag: 'test' }
292
+ { type: '&', tag: 'test' },
244
293
  );
245
294
  expect(resultEntities.length).toEqual(1);
246
295
  expect(testEntity.$is(resultEntities[0])).toEqual(true);
@@ -252,7 +301,7 @@ This one's zip code is 92064.`;
252
301
  // Retrieving entity by GUID and tags...
253
302
  const resultEntity = await nymph.getEntity(
254
303
  { class: TestModel },
255
- { type: '&', guid: testGuid, tag: 'test' }
304
+ { type: '&', guid: testGuid, tag: 'test' },
256
305
  );
257
306
  expect(testEntity.$is(resultEntity)).toEqual(true);
258
307
  });
@@ -263,7 +312,7 @@ This one's zip code is 92064.`;
263
312
  // Retrieving entity by GUID and tags...
264
313
  const resultEntity = await nymph.getEntity(
265
314
  { class: TestModel },
266
- { type: '|', guid: [testGuid, guid()] }
315
+ { type: '|', guid: [testGuid, guid()] },
267
316
  );
268
317
  expect(testEntity.$is(resultEntity)).toEqual(true);
269
318
  });
@@ -274,7 +323,7 @@ This one's zip code is 92064.`;
274
323
  // Retrieving entity by GUID and tags...
275
324
  const resultEntity = await nymph.getEntity(
276
325
  { class: TestModel },
277
- { type: '|', guid: [guid(), guid()] }
326
+ { type: '|', guid: [guid(), guid()] },
278
327
  );
279
328
  expect(testEntity.$is(resultEntity)).toEqual(false);
280
329
  });
@@ -285,7 +334,7 @@ This one's zip code is 92064.`;
285
334
  // Retrieving entity by !GUID...
286
335
  const resultEntity = await nymph.getEntities(
287
336
  { class: TestModel },
288
- { type: '&', '!guid': guid(), tag: 'test' }
337
+ { type: '&', '!guid': guid(), tag: 'test' },
289
338
  );
290
339
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
291
340
  });
@@ -296,7 +345,7 @@ This one's zip code is 92064.`;
296
345
  // Retrieving entity by !tags...
297
346
  const resultEntity = await nymph.getEntities(
298
347
  { class: TestModel },
299
- { type: '&', guid: testGuid, '!tag': ['barbecue', 'pickles'] }
348
+ { type: '&', guid: testGuid, '!tag': ['barbecue', 'pickles'] },
300
349
  );
301
350
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
302
351
  });
@@ -307,7 +356,7 @@ This one's zip code is 92064.`;
307
356
  // Testing GUID and wrong tags...
308
357
  const resultEntity = await nymph.getEntity(
309
358
  { class: TestModel },
310
- { type: '&', guid: testGuid, tag: ['pickles'] }
359
+ { type: '&', guid: testGuid, tag: ['pickles'] },
311
360
  );
312
361
  expect(resultEntity).toBeNull();
313
362
  });
@@ -318,7 +367,7 @@ This one's zip code is 92064.`;
318
367
  // Retrieving entity by tags...
319
368
  const resultEntity = await nymph.getEntities(
320
369
  { class: TestModel },
321
- { type: '&', tag: 'test' }
370
+ { type: '&', tag: 'test' },
322
371
  );
323
372
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
324
373
  });
@@ -329,7 +378,7 @@ This one's zip code is 92064.`;
329
378
  // Testing wrong tags...
330
379
  const resultEntity = await nymph.getEntities(
331
380
  { class: TestModel },
332
- { type: '&', tag: 'pickles' }
381
+ { type: '&', tag: 'pickles' },
333
382
  );
334
383
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
335
384
  });
@@ -340,7 +389,7 @@ This one's zip code is 92064.`;
340
389
  // Retrieving entity by tags inclusively...
341
390
  const resultEntity = await nymph.getEntities(
342
391
  { class: TestModel },
343
- { type: '|', tag: ['pickles', 'test', 'barbecue'] }
392
+ { type: '|', tag: ['pickles', 'test', 'barbecue'] },
344
393
  );
345
394
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
346
395
  });
@@ -351,7 +400,7 @@ This one's zip code is 92064.`;
351
400
  // Testing wrong inclusive tags...
352
401
  const resultEntity = await nymph.getEntities(
353
402
  { class: TestModel },
354
- { type: '|', tag: ['pickles', 'barbecue'] }
403
+ { type: '|', tag: ['pickles', 'barbecue'] },
355
404
  );
356
405
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
357
406
  });
@@ -363,7 +412,7 @@ This one's zip code is 92064.`;
363
412
  const resultEntity = await nymph.getEntities(
364
413
  { class: TestModel },
365
414
  { type: '&', tag: 'test' },
366
- { type: '|', tag: ['pickles', 'test', 'barbecue'] }
415
+ { type: '|', tag: ['pickles', 'test', 'barbecue'] },
367
416
  );
368
417
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
369
418
  });
@@ -375,7 +424,7 @@ This one's zip code is 92064.`;
375
424
  const resultEntity = await nymph.getEntities(
376
425
  { class: TestModel },
377
426
  { type: '&', tag: 'test' },
378
- { type: '|', tag: ['pickles', 'barbecue'] }
427
+ { type: '|', tag: ['pickles', 'barbecue'] },
379
428
  );
380
429
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
381
430
  });
@@ -387,7 +436,7 @@ This one's zip code is 92064.`;
387
436
  const resultEntity = await nymph.getEntities(
388
437
  { class: TestModel },
389
438
  { type: '&', tag: 'pickles' },
390
- { type: '|', tag: ['test', 'barbecue'] }
439
+ { type: '|', tag: ['test', 'barbecue'] },
391
440
  );
392
441
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
393
442
  });
@@ -398,7 +447,7 @@ This one's zip code is 92064.`;
398
447
  // Retrieving entity by defined...
399
448
  const resultEntity = await nymph.getEntities(
400
449
  { class: TestModel },
401
- { type: '&', defined: 'string' }
450
+ { type: '&', defined: 'string' },
402
451
  );
403
452
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
404
453
  });
@@ -409,7 +458,7 @@ This one's zip code is 92064.`;
409
458
  // Retrieving entity by !defined...
410
459
  const resultEntity = await nymph.getEntities(
411
460
  { class: TestModel },
412
- { type: '&', tag: 'test', '!defined': 'pickles' }
461
+ { type: '&', tag: 'test', '!defined': 'pickles' },
413
462
  );
414
463
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
415
464
  });
@@ -421,7 +470,7 @@ This one's zip code is 92064.`;
421
470
  const resultEntity = await nymph.getEntities(
422
471
  { class: TestModel },
423
472
  { type: '!&', defined: 'pickles' },
424
- { type: '&', tag: 'test' }
473
+ { type: '&', tag: 'test' },
425
474
  );
426
475
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
427
476
  });
@@ -430,9 +479,60 @@ This one's zip code is 92064.`;
430
479
  await createTestEntities();
431
480
 
432
481
  // Retrieving entity by equal...
433
- const resultEntity = await nymph.getEntities(
482
+ let resultEntity = await nymph.getEntities(
483
+ { class: TestModel },
484
+ { type: '&', equal: ['string', 'test'] },
485
+ );
486
+ expect(testEntity.$inArray(resultEntity)).toEqual(true);
487
+
488
+ // Retrieving entity by equal...
489
+ resultEntity = await nymph.getEntities(
434
490
  { class: TestModel },
435
- { type: '&', equal: ['string', 'test'] }
491
+ { type: '&', equal: ['null', null] },
492
+ );
493
+ expect(testEntity.$inArray(resultEntity)).toEqual(true);
494
+
495
+ // Retrieving entity by equal...
496
+ resultEntity = await nymph.getEntities(
497
+ { class: TestModel },
498
+ { type: '&', equal: ['boolean', true] },
499
+ );
500
+ expect(testEntity.$inArray(resultEntity)).toEqual(true);
501
+
502
+ // Retrieving entity by equal...
503
+ resultEntity = await nymph.getEntities(
504
+ { class: TestModel },
505
+ { type: '&', equal: ['number', 30] },
506
+ );
507
+ expect(testEntity.$inArray(resultEntity)).toEqual(true);
508
+
509
+ // Retrieving entity by equal...
510
+ resultEntity = await nymph.getEntities(
511
+ { class: TestModel },
512
+ {
513
+ type: '&',
514
+ equal: [
515
+ 'array',
516
+ [
517
+ 'full',
518
+ 'of',
519
+ 'values',
520
+ 500,
521
+ { test: true },
522
+ { nullbyte: '\\\x00\u0000 \x00' },
523
+ ],
524
+ ],
525
+ },
526
+ );
527
+ expect(testEntity.$inArray(resultEntity)).toEqual(true);
528
+
529
+ // Retrieving entity by equal...
530
+ resultEntity = await nymph.getEntities(
531
+ { class: TestModel },
532
+ {
533
+ type: '&',
534
+ equal: ['match', matchValue],
535
+ },
436
536
  );
437
537
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
438
538
  });
@@ -446,7 +546,7 @@ This one's zip code is 92064.`;
446
546
  // Retrieving entity by !equal...
447
547
  const resultEntity = await nymph.getEntities(
448
548
  { class: TestModel },
449
- { type: '&', tag: 'test', '!equal': ['string', 'wrong'] }
549
+ { type: '&', tag: 'test', '!equal': ['string', 'wrong'] },
450
550
  );
451
551
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
452
552
  expect(referenceEntity.$inArray(resultEntity)).toEqual(false);
@@ -458,7 +558,7 @@ This one's zip code is 92064.`;
458
558
  // Retrieving entity by like...
459
559
  const resultEntity = await nymph.getEntities(
460
560
  { class: TestModel },
461
- { type: '&', like: ['string', 't_s%'] }
561
+ { type: '&', like: ['string', 't_s%'] },
462
562
  );
463
563
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
464
564
  });
@@ -472,7 +572,7 @@ This one's zip code is 92064.`;
472
572
  // Retrieving entity by !like...
473
573
  const resultEntity = await nymph.getEntities(
474
574
  { class: TestModel },
475
- { type: '&', tag: 'test', '!like': ['string', 'wr_n%'] }
575
+ { type: '&', tag: 'test', '!like': ['string', 'wr_n%'] },
476
576
  );
477
577
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
478
578
  expect(referenceEntity.$inArray(resultEntity)).toEqual(false);
@@ -484,7 +584,7 @@ This one's zip code is 92064.`;
484
584
  // Retrieving entity by ilike...
485
585
  const resultEntity = await nymph.getEntities(
486
586
  { class: TestModel },
487
- { type: '&', ilike: ['string', 'T_s%'] }
587
+ { type: '&', ilike: ['string', 'T_s%'] },
488
588
  );
489
589
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
490
590
  });
@@ -498,7 +598,7 @@ This one's zip code is 92064.`;
498
598
  // Retrieving entity by !ilike...
499
599
  const resultEntity = await nymph.getEntities(
500
600
  { class: TestModel },
501
- { type: '&', tag: 'test', '!ilike': ['string', 'wr_n%'] }
601
+ { type: '&', tag: 'test', '!ilike': ['string', 'wr_n%'] },
502
602
  );
503
603
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
504
604
  expect(referenceEntity.$inArray(resultEntity)).toEqual(false);
@@ -510,7 +610,7 @@ This one's zip code is 92064.`;
510
610
  // Retrieving entity by like...
511
611
  const resultEntity = await nymph.getEntities(
512
612
  { class: TestModel },
513
- { type: '&', like: ['string', 'T_s%'] }
613
+ { type: '&', like: ['string', 'T_s%'] },
514
614
  );
515
615
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
516
616
  });
@@ -521,7 +621,7 @@ This one's zip code is 92064.`;
521
621
  // Retrieving entity by tags and equal...
522
622
  const resultEntity = await nymph.getEntities(
523
623
  { class: TestModel },
524
- { type: '&', tag: 'test', equal: ['string', 'test'] }
624
+ { type: '&', tag: 'test', equal: ['string', 'test'] },
525
625
  );
526
626
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
527
627
  });
@@ -532,7 +632,7 @@ This one's zip code is 92064.`;
532
632
  // Testing wrong tags and right equal...
533
633
  const resultEntity = await nymph.getEntities(
534
634
  { class: TestModel },
535
- { type: '&', tag: 'pickles', equal: ['string', 'test'] }
635
+ { type: '&', tag: 'pickles', equal: ['string', 'test'] },
536
636
  );
537
637
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
538
638
  });
@@ -543,7 +643,7 @@ This one's zip code is 92064.`;
543
643
  // Testing right tags and wrong equal...
544
644
  const resultEntity = await nymph.getEntities(
545
645
  { class: TestModel },
546
- { type: '&', tag: 'test', equal: ['string', 'pickles'] }
646
+ { type: '&', tag: 'test', equal: ['string', 'pickles'] },
547
647
  );
548
648
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
549
649
  });
@@ -554,7 +654,7 @@ This one's zip code is 92064.`;
554
654
  // Testing wrong tags and wrong equal...
555
655
  const resultEntity = await nymph.getEntities(
556
656
  { class: TestModel },
557
- { type: '&', tag: 'pickles', equal: ['string', 'pickles'] }
657
+ { type: '&', tag: 'pickles', equal: ['string', 'pickles'] },
558
658
  );
559
659
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
560
660
  });
@@ -565,14 +665,21 @@ This one's zip code is 92064.`;
565
665
  // Retrieving entity by contain...
566
666
  let resultEntity = await nymph.getEntities(
567
667
  { class: TestModel },
568
- { type: '&', contain: ['array', 'values'] }
668
+ { type: '&', contain: ['array', 'values'] },
669
+ );
670
+ expect(testEntity.$inArray(resultEntity)).toEqual(true);
671
+
672
+ // Retrieving entity by contain...
673
+ resultEntity = await nymph.getEntities(
674
+ { class: TestModel },
675
+ { type: '&', contain: ['array', 500] },
569
676
  );
570
677
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
571
678
 
572
- // Retrieving entity by contain with full match...
679
+ // Retrieving entity by contain...
573
680
  resultEntity = await nymph.getEntities(
574
681
  { class: TestModel },
575
- { type: '&', contain: ['string', 'test'] }
682
+ { type: '&', contain: ['array', { test: true }] },
576
683
  );
577
684
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
578
685
  });
@@ -584,7 +691,7 @@ This one's zip code is 92064.`;
584
691
  const resultEntity = await nymph.getEntities(
585
692
  { class: TestModel },
586
693
  { type: '&', tag: 'test' },
587
- { type: '!&', contain: ['array', 'pickles'] }
694
+ { type: '!&', contain: ['array', 'pickles'] },
588
695
  );
589
696
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
590
697
  });
@@ -595,14 +702,14 @@ This one's zip code is 92064.`;
595
702
  // Testing wrong contain...
596
703
  let resultEntity = await nymph.getEntities(
597
704
  { class: TestModel },
598
- { type: '&', contain: ['array', 'pickles'] }
705
+ { type: '&', contain: ['array', 'pickles'] },
599
706
  );
600
707
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
601
708
 
602
709
  // Testing wrong contain...
603
710
  resultEntity = await nymph.getEntities(
604
711
  { class: TestModel },
605
- { type: '&', contain: ['string', 'pickles'] }
712
+ { type: '&', contain: ['string', 'pickles'] },
606
713
  );
607
714
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
608
715
  });
@@ -613,12 +720,12 @@ This one's zip code is 92064.`;
613
720
  // Retrieving entity by regex match...
614
721
  let resultEntity = await nymph.getEntities(
615
722
  { class: TestModel },
616
- { type: '&', match: ['match', '.*'] } // anything
723
+ { type: '&', match: ['match', '.*'] }, // anything
617
724
  );
618
725
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
619
726
  resultEntity = await nymph.getEntities(
620
727
  { class: TestModel },
621
- { type: '&', tag: 'test', match: ['match', 'Edward McCheese'] } // a substring
728
+ { type: '&', tag: 'test', match: ['match', 'Edward McCheese'] }, // a substring
622
729
  );
623
730
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
624
731
  resultEntity = await nymph.getEntities(
@@ -630,7 +737,7 @@ This one's zip code is 92064.`;
630
737
  ['string', '[0-9]'],
631
738
  ['match', 'Edward McCheese'],
632
739
  ],
633
- } // inclusive test
740
+ }, // inclusive test
634
741
  );
635
742
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
636
743
  resultEntity = await nymph.getEntities(
@@ -639,7 +746,7 @@ This one's zip code is 92064.`;
639
746
  type: '&',
640
747
  tag: 'test',
641
748
  match: ['match', '[-a-zA-Z0-9+_]+@[-a-zA-Z0-9_]+.[-a-zA-Z0-9_]{2,4}'],
642
- } // a simple email
749
+ }, // a simple email
643
750
  );
644
751
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
645
752
  resultEntity = await nymph.getEntities(
@@ -648,7 +755,7 @@ This one's zip code is 92064.`;
648
755
  type: '&',
649
756
  tag: 'test',
650
757
  match: ['match', '\\([0-9]{3}\\) [0-9]{3}-[0-9]{4}'],
651
- } // a phone number
758
+ }, // a phone number
652
759
  );
653
760
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
654
761
  });
@@ -659,7 +766,7 @@ This one's zip code is 92064.`;
659
766
  // Retrieving entity by regex match...
660
767
  const resultEntity = await nymph.getEntities(
661
768
  { class: TestModel },
662
- { type: '&', tag: 'test', imatch: ['match', 'edward mccheese'] } // a substring
769
+ { type: '&', tag: 'test', imatch: ['match', 'edward mccheese'] }, // a substring
663
770
  );
664
771
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
665
772
  });
@@ -670,12 +777,12 @@ This one's zip code is 92064.`;
670
777
  // Testing wrong regex match...
671
778
  let resultEntity = await nymph.getEntities(
672
779
  { class: TestModel },
673
- { type: '&', match: ['match', 'Q'] }
780
+ { type: '&', match: ['match', '='] },
674
781
  );
675
782
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
676
783
  resultEntity = await nymph.getEntities(
677
784
  { class: TestModel },
678
- { type: '&', tag: 'pickle', match: ['match', '.*'] }
785
+ { type: '&', tag: 'pickle', match: ['match', '.*'] },
679
786
  );
680
787
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
681
788
  resultEntity = await nymph.getEntities(
@@ -686,7 +793,7 @@ This one's zip code is 92064.`;
686
793
  ['string', '[0-9]'],
687
794
  ['match', ',,'],
688
795
  ],
689
- }
796
+ },
690
797
  );
691
798
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
692
799
  });
@@ -697,7 +804,7 @@ This one's zip code is 92064.`;
697
804
  // Retrieving entity by regex match...
698
805
  const resultEntity = await nymph.getEntities(
699
806
  { class: TestModel },
700
- { type: '&', tag: 'test', match: ['match', 'edward mccheese'] } // a substring
807
+ { type: '&', tag: 'test', match: ['match', 'edward mccheese'] }, // a substring
701
808
  );
702
809
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
703
810
  });
@@ -709,7 +816,7 @@ This one's zip code is 92064.`;
709
816
  const resultEntity = await nymph.getEntities(
710
817
  { class: TestModel },
711
818
  { type: '&', tag: 'test' },
712
- { type: '|', equal: ['string', 'pickles'], match: ['string', 'test'] }
819
+ { type: '|', equal: ['string', 'pickles'], match: ['string', 'test'] },
713
820
  );
714
821
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
715
822
  });
@@ -726,7 +833,7 @@ This one's zip code is 92064.`;
726
833
  ['number', 30],
727
834
  ['pickles', 100],
728
835
  ],
729
- }
836
+ },
730
837
  );
731
838
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
732
839
 
@@ -739,7 +846,7 @@ This one's zip code is 92064.`;
739
846
  ['number', 31],
740
847
  ['pickles', 100],
741
848
  ],
742
- }
849
+ },
743
850
  );
744
851
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
745
852
 
@@ -752,7 +859,7 @@ This one's zip code is 92064.`;
752
859
  ['number', 29],
753
860
  ['pickles', 100],
754
861
  ],
755
- }
862
+ },
756
863
  );
757
864
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
758
865
 
@@ -765,7 +872,7 @@ This one's zip code is 92064.`;
765
872
  ['numberString', 30],
766
873
  ['pickles', 100],
767
874
  ],
768
- }
875
+ },
769
876
  );
770
877
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
771
878
 
@@ -778,7 +885,7 @@ This one's zip code is 92064.`;
778
885
  ['numberString', 31],
779
886
  ['pickles', 100],
780
887
  ],
781
- }
888
+ },
782
889
  );
783
890
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
784
891
 
@@ -791,7 +898,7 @@ This one's zip code is 92064.`;
791
898
  ['numberString', 29],
792
899
  ['pickles', 100],
793
900
  ],
794
- }
901
+ },
795
902
  );
796
903
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
797
904
  });
@@ -808,7 +915,7 @@ This one's zip code is 92064.`;
808
915
  ['number', 30],
809
916
  ['pickles', 100],
810
917
  ],
811
- }
918
+ },
812
919
  );
813
920
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
814
921
 
@@ -821,7 +928,7 @@ This one's zip code is 92064.`;
821
928
  ['number', 31],
822
929
  ['pickles', 100],
823
930
  ],
824
- }
931
+ },
825
932
  );
826
933
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
827
934
 
@@ -834,7 +941,7 @@ This one's zip code is 92064.`;
834
941
  ['number', 29],
835
942
  ['pickles', 100],
836
943
  ],
837
- }
944
+ },
838
945
  );
839
946
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
840
947
 
@@ -847,7 +954,7 @@ This one's zip code is 92064.`;
847
954
  ['numberString', 30],
848
955
  ['pickles', 100],
849
956
  ],
850
- }
957
+ },
851
958
  );
852
959
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
853
960
 
@@ -860,7 +967,7 @@ This one's zip code is 92064.`;
860
967
  ['numberString', 31],
861
968
  ['pickles', 100],
862
969
  ],
863
- }
970
+ },
864
971
  );
865
972
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
866
973
 
@@ -873,7 +980,7 @@ This one's zip code is 92064.`;
873
980
  ['numberString', 29],
874
981
  ['pickles', 100],
875
982
  ],
876
- }
983
+ },
877
984
  );
878
985
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
879
986
  });
@@ -890,7 +997,7 @@ This one's zip code is 92064.`;
890
997
  ['number', 30],
891
998
  ['pickles', 100],
892
999
  ],
893
- }
1000
+ },
894
1001
  );
895
1002
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
896
1003
 
@@ -903,7 +1010,7 @@ This one's zip code is 92064.`;
903
1010
  ['number', 31],
904
1011
  ['pickles', 100],
905
1012
  ],
906
- }
1013
+ },
907
1014
  );
908
1015
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
909
1016
 
@@ -916,7 +1023,7 @@ This one's zip code is 92064.`;
916
1023
  ['number', 29],
917
1024
  ['pickles', 100],
918
1025
  ],
919
- }
1026
+ },
920
1027
  );
921
1028
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
922
1029
 
@@ -929,7 +1036,7 @@ This one's zip code is 92064.`;
929
1036
  ['numberString', 30],
930
1037
  ['pickles', 100],
931
1038
  ],
932
- }
1039
+ },
933
1040
  );
934
1041
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
935
1042
 
@@ -942,7 +1049,7 @@ This one's zip code is 92064.`;
942
1049
  ['numberString', 31],
943
1050
  ['pickles', 100],
944
1051
  ],
945
- }
1052
+ },
946
1053
  );
947
1054
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
948
1055
 
@@ -955,7 +1062,7 @@ This one's zip code is 92064.`;
955
1062
  ['numberString', 29],
956
1063
  ['pickles', 100],
957
1064
  ],
958
- }
1065
+ },
959
1066
  );
960
1067
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
961
1068
  });
@@ -972,7 +1079,7 @@ This one's zip code is 92064.`;
972
1079
  ['number', 30],
973
1080
  ['pickles', 100],
974
1081
  ],
975
- }
1082
+ },
976
1083
  );
977
1084
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
978
1085
 
@@ -985,7 +1092,7 @@ This one's zip code is 92064.`;
985
1092
  ['number', 31],
986
1093
  ['pickles', 100],
987
1094
  ],
988
- }
1095
+ },
989
1096
  );
990
1097
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
991
1098
 
@@ -998,7 +1105,7 @@ This one's zip code is 92064.`;
998
1105
  ['number', 29],
999
1106
  ['pickles', 100],
1000
1107
  ],
1001
- }
1108
+ },
1002
1109
  );
1003
1110
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1004
1111
 
@@ -1011,7 +1118,7 @@ This one's zip code is 92064.`;
1011
1118
  ['numberString', 30],
1012
1119
  ['pickles', 100],
1013
1120
  ],
1014
- }
1121
+ },
1015
1122
  );
1016
1123
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1017
1124
 
@@ -1024,7 +1131,7 @@ This one's zip code is 92064.`;
1024
1131
  ['numberString', 31],
1025
1132
  ['pickles', 100],
1026
1133
  ],
1027
- }
1134
+ },
1028
1135
  );
1029
1136
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1030
1137
 
@@ -1037,7 +1144,7 @@ This one's zip code is 92064.`;
1037
1144
  ['numberString', 29],
1038
1145
  ['pickles', 100],
1039
1146
  ],
1040
- }
1147
+ },
1041
1148
  );
1042
1149
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1043
1150
  });
@@ -1049,7 +1156,7 @@ This one's zip code is 92064.`;
1049
1156
  const resultEntity = await nymph.getEntities(
1050
1157
  { class: TestModel },
1051
1158
  { type: '&', tag: 'test' },
1052
- { type: '!&', gte: ['number', 60] }
1159
+ { type: '!&', gte: ['number', 60] },
1053
1160
  );
1054
1161
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1055
1162
  });
@@ -1060,7 +1167,7 @@ This one's zip code is 92064.`;
1060
1167
  // Testing wrong inequality...
1061
1168
  const resultEntity = await nymph.getEntities(
1062
1169
  { class: TestModel },
1063
- { type: '&', lte: ['number', 29.99] }
1170
+ { type: '&', lte: ['number', 29.99] },
1064
1171
  );
1065
1172
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1066
1173
  });
@@ -1071,7 +1178,7 @@ This one's zip code is 92064.`;
1071
1178
  // Retrieving entity by time...
1072
1179
  const resultEntity = await nymph.getEntities(
1073
1180
  { class: TestModel },
1074
- { type: '&', tag: 'test', gt: ['cdate', (testEntity.cdate ?? 0) - 120] }
1181
+ { type: '&', tag: 'test', gt: ['cdate', (testEntity.cdate ?? 0) - 120] },
1075
1182
  );
1076
1183
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1077
1184
  });
@@ -1082,7 +1189,7 @@ This one's zip code is 92064.`;
1082
1189
  // Testing wrong time...
1083
1190
  const resultEntity = await nymph.getEntities(
1084
1191
  { class: TestModel },
1085
- { type: '&', tag: 'test', gte: ['cdate', (testEntity.cdate ?? 0) + 1] }
1192
+ { type: '&', tag: 'test', gte: ['cdate', (testEntity.cdate ?? 0) + 1] },
1086
1193
  );
1087
1194
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1088
1195
  });
@@ -1095,7 +1202,7 @@ This one's zip code is 92064.`;
1095
1202
  // Retrieving entity by relative time...
1096
1203
  let resultEntity = await nymph.getEntities(
1097
1204
  { class: TestModel },
1098
- { type: '&', gt: ['timestamp', null, '-1 day'] }
1205
+ { type: '&', gt: ['timestamp', null, '-1 day'] },
1099
1206
  );
1100
1207
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1101
1208
  expect(referenceEntity.$inArray(resultEntity)).toEqual(false);
@@ -1109,7 +1216,7 @@ This one's zip code is 92064.`;
1109
1216
  ['timestamp', null, '-1 day'],
1110
1217
  ['timestamp', null, '+5 days'],
1111
1218
  ],
1112
- }
1219
+ },
1113
1220
  );
1114
1221
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1115
1222
  expect(referenceEntity.$inArray(resultEntity)).toEqual(false);
@@ -1117,7 +1224,7 @@ This one's zip code is 92064.`;
1117
1224
  // Retrieving entity by relative time...
1118
1225
  resultEntity = await nymph.getEntities(
1119
1226
  { class: TestModel },
1120
- { type: '&', gt: ['timestamp', null, '-3 days'] }
1227
+ { type: '&', gt: ['timestamp', null, '-3 days'] },
1121
1228
  );
1122
1229
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1123
1230
  expect(referenceEntity.$inArray(resultEntity)).toEqual(true);
@@ -1125,7 +1232,7 @@ This one's zip code is 92064.`;
1125
1232
  // Retrieving entity by relative time...
1126
1233
  resultEntity = await nymph.getEntities(
1127
1234
  { class: TestModel },
1128
- { type: '&', gt: ['cdate', null, '-1 day'] }
1235
+ { type: '&', gt: ['cdate', null, '-1 day'] },
1129
1236
  );
1130
1237
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1131
1238
  expect(referenceEntity.$inArray(resultEntity)).toEqual(true);
@@ -1139,7 +1246,7 @@ This one's zip code is 92064.`;
1139
1246
  // Retrieving entity by relative time...
1140
1247
  let resultEntity = await nymph.getEntities(
1141
1248
  { class: TestModel },
1142
- { type: '&', tag: 'test', gt: ['timestamp', null, '+1 day'] }
1249
+ { type: '&', tag: 'test', gt: ['timestamp', null, '+1 day'] },
1143
1250
  );
1144
1251
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1145
1252
  expect(referenceEntity.$inArray(resultEntity)).toEqual(false);
@@ -1147,7 +1254,7 @@ This one's zip code is 92064.`;
1147
1254
  // Retrieving entity by relative time...
1148
1255
  resultEntity = await nymph.getEntities(
1149
1256
  { class: TestModel },
1150
- { type: '&', tag: 'test', lt: ['timestamp', null, '-3 days'] }
1257
+ { type: '&', tag: 'test', lt: ['timestamp', null, '-3 days'] },
1151
1258
  );
1152
1259
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1153
1260
  expect(referenceEntity.$inArray(resultEntity)).toEqual(false);
@@ -1155,7 +1262,7 @@ This one's zip code is 92064.`;
1155
1262
  // Retrieving entity by relative time...
1156
1263
  resultEntity = await nymph.getEntities(
1157
1264
  { class: TestModel },
1158
- { type: '&', tag: 'test', gt: ['cdate', null, '+1 day'] }
1265
+ { type: '&', tag: 'test', gt: ['cdate', null, '+1 day'] },
1159
1266
  );
1160
1267
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1161
1268
  expect(referenceEntity.$inArray(resultEntity)).toEqual(false);
@@ -1165,9 +1272,11 @@ This one's zip code is 92064.`;
1165
1272
  await createTestEntities();
1166
1273
 
1167
1274
  // Testing referenced entities...
1275
+ await testEntity.reference?.$wake();
1168
1276
  expect(testEntity.reference?.test).toEqual('good');
1169
1277
 
1170
1278
  // Testing referenced entity arrays...
1279
+ await Promise.all(testEntity.refArray?.map((e) => e.$wake()) || []);
1171
1280
  expect(testEntity.refArray?.[0].test).toEqual('good');
1172
1281
  });
1173
1282
 
@@ -1177,7 +1286,7 @@ This one's zip code is 92064.`;
1177
1286
  // Retrieving entity by reference...
1178
1287
  const resultEntity = await nymph.getEntities(
1179
1288
  { class: TestModel },
1180
- { type: '&', ref: ['reference', refGuid] }
1289
+ { type: '&', ref: ['reference', refGuid] },
1181
1290
  );
1182
1291
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1183
1292
  });
@@ -1189,7 +1298,7 @@ This one's zip code is 92064.`;
1189
1298
  const resultEntity = await nymph.getEntities(
1190
1299
  { class: TestModel },
1191
1300
  { type: '&', tag: 'test' },
1192
- { type: '!&', ref: ['reference', guid()] }
1301
+ { type: '!&', ref: ['reference', guid()] },
1193
1302
  );
1194
1303
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1195
1304
  });
@@ -1200,7 +1309,7 @@ This one's zip code is 92064.`;
1200
1309
  // Testing wrong reference...
1201
1310
  const resultEntity = await nymph.getEntities(
1202
1311
  { class: TestModel },
1203
- { type: '&', ref: ['reference', guid()] }
1312
+ { type: '&', ref: ['reference', guid()] },
1204
1313
  );
1205
1314
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1206
1315
  });
@@ -1211,7 +1320,7 @@ This one's zip code is 92064.`;
1211
1320
  // Testing non-existent reference...
1212
1321
  const resultEntity = await nymph.getEntities(
1213
1322
  { class: TestModel },
1214
- { type: '&', ref: ['pickle', refGuid] }
1323
+ { type: '&', ref: ['pickle', refGuid] },
1215
1324
  );
1216
1325
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1217
1326
  });
@@ -1228,7 +1337,7 @@ This one's zip code is 92064.`;
1228
1337
  ['reference', refGuid],
1229
1338
  ['reference', guid()],
1230
1339
  ],
1231
- }
1340
+ },
1232
1341
  );
1233
1342
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1234
1343
  });
@@ -1245,7 +1354,7 @@ This one's zip code is 92064.`;
1245
1354
  ['reference', guid()],
1246
1355
  ['reference', guid()],
1247
1356
  ],
1248
- }
1357
+ },
1249
1358
  );
1250
1359
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1251
1360
  });
@@ -1256,7 +1365,7 @@ This one's zip code is 92064.`;
1256
1365
  // Retrieving entity by array reference...
1257
1366
  const resultEntity = await nymph.getEntities(
1258
1367
  { class: TestModel },
1259
- { type: '&', ref: ['refArray', refGuid] }
1368
+ { type: '&', ref: ['refArray', refGuid] },
1260
1369
  );
1261
1370
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1262
1371
  });
@@ -1273,7 +1382,7 @@ This one's zip code is 92064.`;
1273
1382
  ['refArray', refGuid],
1274
1383
  ['refArray', guid()],
1275
1384
  ],
1276
- }
1385
+ },
1277
1386
  );
1278
1387
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1279
1388
  });
@@ -1307,6 +1416,8 @@ This one's zip code is 92064.`;
1307
1416
  ['array', 'of'],
1308
1417
  ['array', 'values'],
1309
1418
  ['array', 500],
1419
+ ['array', { test: true }],
1420
+ ['array', { nullbyte: '\\\x00\u0000 \x00' }],
1310
1421
  ],
1311
1422
  },
1312
1423
  {
@@ -1318,7 +1429,7 @@ This one's zip code is 92064.`;
1318
1429
  ['array', 'values'],
1319
1430
  ['array', 500],
1320
1431
  ],
1321
- }
1432
+ },
1322
1433
  );
1323
1434
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1324
1435
  });
@@ -1338,13 +1449,13 @@ This one's zip code is 92064.`;
1338
1449
 
1339
1450
  const resultSelectors = await nymph.getEntities(
1340
1451
  { class: TestModel },
1341
- { type: '&', ref: ['reference', refGuid] }
1452
+ { type: '&', ref: ['reference', refGuid] },
1342
1453
  );
1343
1454
 
1344
1455
  // Testing count return with selectors...
1345
1456
  const resultSelectorsCount = await nymph.getEntities(
1346
1457
  { class: TestModel, return: 'count' },
1347
- { type: '&', ref: ['reference', refGuid] }
1458
+ { type: '&', ref: ['reference', refGuid] },
1348
1459
  );
1349
1460
  expect(resultSelectorsCount).toBeGreaterThanOrEqual(1);
1350
1461
  expect(resultSelectorsCount).toEqual(resultSelectors.length);
@@ -1367,7 +1478,7 @@ This one's zip code is 92064.`;
1367
1478
  // Testing empty count...
1368
1479
  const resultSelectorsEmpty = await nymph.getEntities(
1369
1480
  { class: TestModel, return: 'count' },
1370
- { type: '&', ref: ['reference', guid()] }
1481
+ { type: '&', ref: ['reference', guid()] },
1371
1482
  );
1372
1483
  expect(resultSelectorsEmpty).toEqual(0);
1373
1484
  });
@@ -1401,6 +1512,8 @@ This one's zip code is 92064.`;
1401
1512
  ['array', 'of'],
1402
1513
  ['array', 'values'],
1403
1514
  ['array', 500],
1515
+ ['array', { test: true }],
1516
+ ['array', { nullbyte: '\\\x00\u0000 \x00' }],
1404
1517
  ],
1405
1518
  },
1406
1519
  {
@@ -1412,7 +1525,7 @@ This one's zip code is 92064.`;
1412
1525
  ['array', 'values'],
1413
1526
  ['array', 500],
1414
1527
  ],
1415
- }
1528
+ },
1416
1529
  );
1417
1530
  expect(resultGuid.indexOf(testEntity.guid ?? '')).toBeGreaterThan(-1);
1418
1531
  });
@@ -1449,6 +1562,8 @@ This one's zip code is 92064.`;
1449
1562
  ['array', 'of'],
1450
1563
  ['array', 'values'],
1451
1564
  ['array', 500],
1565
+ ['array', { test: true }],
1566
+ ['array', { nullbyte: '\\\x00\u0000 \x00' }],
1452
1567
  ],
1453
1568
  },
1454
1569
  {
@@ -1462,7 +1577,7 @@ This one's zip code is 92064.`;
1462
1577
  ],
1463
1578
  },
1464
1579
  ],
1465
- }
1580
+ },
1466
1581
  );
1467
1582
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1468
1583
 
@@ -1494,6 +1609,8 @@ This one's zip code is 92064.`;
1494
1609
  ['array', 'of'],
1495
1610
  ['array', 'values'],
1496
1611
  ['array', 500],
1612
+ ['array', { test: true }],
1613
+ ['array', { nullbyte: '\\\x00\u0000 \x00' }],
1497
1614
  ],
1498
1615
  },
1499
1616
  {
@@ -1507,7 +1624,7 @@ This one's zip code is 92064.`;
1507
1624
  ],
1508
1625
  },
1509
1626
  ],
1510
- }
1627
+ },
1511
1628
  );
1512
1629
  expect(testEntity.$inArray(resultEntity2)).toEqual(true);
1513
1630
 
@@ -1523,7 +1640,7 @@ This one's zip code is 92064.`;
1523
1640
  },
1524
1641
  { type: '&', gte: ['number', 16000] },
1525
1642
  ],
1526
- }
1643
+ },
1527
1644
  );
1528
1645
  expect(testEntity.$inArray(resultEntity3)).toEqual(true);
1529
1646
 
@@ -1545,7 +1662,7 @@ This one's zip code is 92064.`;
1545
1662
  },
1546
1663
  },
1547
1664
  ],
1548
- }
1665
+ },
1549
1666
  );
1550
1667
  expect(testEntity.$inArray(resultEntity4)).toEqual(true);
1551
1668
  });
@@ -1564,7 +1681,7 @@ This one's zip code is 92064.`;
1564
1681
  },
1565
1682
  { type: '&', gte: ['number', 16000] },
1566
1683
  ],
1567
- }
1684
+ },
1568
1685
  );
1569
1686
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1570
1687
  });
@@ -1581,7 +1698,7 @@ This one's zip code is 92064.`;
1581
1698
  'reference',
1582
1699
  [{ class: TestModel }, { type: '&', equal: ['test', 'good'] }],
1583
1700
  ],
1584
- }
1701
+ },
1585
1702
  );
1586
1703
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1587
1704
  });
@@ -1598,7 +1715,7 @@ This one's zip code is 92064.`;
1598
1715
  'reference',
1599
1716
  [{ class: TestModel }, { type: '&', equal: ['test', 'pickles'] }],
1600
1717
  ],
1601
- }
1718
+ },
1602
1719
  );
1603
1720
  expect(testEntity.$inArray(resultEntity)).toEqual(true);
1604
1721
  });
@@ -1615,7 +1732,7 @@ This one's zip code is 92064.`;
1615
1732
  'reference',
1616
1733
  [{ class: TestBModel }, { type: '&', equal: ['test', 'good'] }],
1617
1734
  ],
1618
- }
1735
+ },
1619
1736
  );
1620
1737
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1621
1738
  });
@@ -1632,31 +1749,28 @@ This one's zip code is 92064.`;
1632
1749
  'reference',
1633
1750
  [{ class: TestModel }, { type: '&', equal: ['test', 'pickles'] }],
1634
1751
  ],
1635
- }
1752
+ },
1636
1753
  );
1637
1754
  expect(testEntity.$inArray(resultEntity)).toEqual(false);
1638
1755
  });
1639
1756
 
1640
- it('sort option', async () => {
1757
+ it('cdate and mdate sort option', async () => {
1641
1758
  await createMultipleTestEntities();
1642
1759
 
1643
- for (const sort of ['cdate', 'mdate']) {
1760
+ for (const sort of ['cdate', 'mdate'] as ('cdate' | 'mdate')[]) {
1644
1761
  // Retrieving entities sorted...
1645
- let resultEntities = await nymph.getEntities({
1646
- class: TestModel,
1647
- sort: sort as 'cdate' | 'mdate',
1648
- });
1762
+ let resultEntities = await nymph.getEntities({ class: TestModel, sort });
1649
1763
  expect(resultEntities.length).toBeGreaterThan(100);
1650
1764
  for (let i = 0; i < resultEntities.length - 1; i++) {
1651
- expect(
1652
- resultEntities[i + 1][sort as 'cdate' | 'mdate']
1653
- ).toBeGreaterThan(resultEntities[i][sort as 'cdate' | 'mdate'] ?? 0);
1765
+ expect(resultEntities[i + 1][sort]).toBeGreaterThan(
1766
+ resultEntities[i][sort] ?? 0,
1767
+ );
1654
1768
  }
1655
1769
 
1656
1770
  // And test the same with guid return...
1657
1771
  let resultGuids = await nymph.getEntities({
1658
1772
  class: TestModel,
1659
- sort: sort as 'cdate' | 'mdate',
1773
+ sort,
1660
1774
  return: 'guid',
1661
1775
  });
1662
1776
  expect(resultGuids.length).toBeGreaterThan(100);
@@ -1667,48 +1781,121 @@ This one's zip code is 92064.`;
1667
1781
  // Retrieving entities reverse sorted...
1668
1782
  resultEntities = await nymph.getEntities({
1669
1783
  class: TestModel,
1670
- sort: sort as 'cdate' | 'mdate',
1784
+ sort,
1671
1785
  reverse: true,
1672
1786
  });
1673
1787
  expect(resultEntities.length).toBeGreaterThan(100);
1674
1788
  for (let i = 0; i < resultEntities.length - 1; i++) {
1675
- expect(resultEntities[i + 1][sort as 'cdate' | 'mdate']).toBeLessThan(
1676
- resultEntities[i][sort as 'cdate' | 'mdate'] ?? 0
1789
+ expect(resultEntities[i + 1][sort]).toBeLessThan(
1790
+ resultEntities[i][sort] ?? 0,
1677
1791
  );
1678
1792
  }
1679
1793
 
1680
1794
  // And again with other selectors.
1681
1795
  // Retrieving entities sorted...
1682
1796
  resultEntities = await nymph.getEntities(
1683
- { class: TestModel, sort: sort as 'cdate' | 'mdate' },
1684
- { type: '&', match: ['name', '^Multi Test '] }
1797
+ { class: TestModel, sort },
1798
+ { type: '&', match: ['name', '^Multi Test '] },
1685
1799
  );
1686
1800
  expect(resultEntities.length).toEqual(100);
1687
1801
  for (let i = 0; i < resultEntities.length - 1; i++) {
1688
- expect(
1689
- resultEntities[i + 1][sort as 'cdate' | 'mdate']
1690
- ).toBeGreaterThan(resultEntities[i][sort as 'cdate' | 'mdate'] ?? 0);
1802
+ expect(resultEntities[i + 1][sort]).toBeGreaterThan(
1803
+ resultEntities[i][sort] ?? 0,
1804
+ );
1691
1805
  }
1692
1806
 
1693
1807
  // Retrieving entities reverse sorted...
1694
1808
  resultEntities = await nymph.getEntities(
1695
- { class: TestModel, sort: sort as 'cdate' | 'mdate', reverse: true },
1696
- { type: '&', match: ['name', '^Multi Test '] }
1809
+ { class: TestModel, sort, reverse: true },
1810
+ { type: '&', match: ['name', '^Multi Test '] },
1697
1811
  );
1698
1812
  expect(resultEntities.length).toEqual(100);
1699
1813
  for (let i = 0; i < resultEntities.length - 1; i++) {
1700
- expect(resultEntities[i + 1][sort as 'cdate' | 'mdate']).toBeLessThan(
1701
- resultEntities[i][sort as 'cdate' | 'mdate'] ?? 0
1814
+ expect(resultEntities[i + 1][sort]).toBeLessThan(
1815
+ resultEntities[i][sort] ?? 0,
1702
1816
  );
1703
1817
  }
1704
1818
  }
1705
1819
  });
1706
1820
 
1821
+ it('property sort option', async () => {
1822
+ await createMultipleTestEntities();
1823
+
1824
+ // Retrieving entities sorted...
1825
+ let resultEntities = await nymph.getEntities({
1826
+ class: TestModel,
1827
+ sort: 'number',
1828
+ });
1829
+ expect(resultEntities.length).toBeGreaterThan(100);
1830
+ for (let i = 0; i < resultEntities.length - 1; i++) {
1831
+ expect(resultEntities[i + 1].number ?? Infinity).toBeGreaterThanOrEqual(
1832
+ resultEntities[i].number ?? 0,
1833
+ );
1834
+ }
1835
+
1836
+ // And test the same with guid return...
1837
+ let resultGuids = await nymph.getEntities({
1838
+ class: TestModel,
1839
+ sort: 'number',
1840
+ return: 'guid',
1841
+ });
1842
+ expect(resultGuids.length).toBeGreaterThan(100);
1843
+ for (let i = 0; i < resultGuids.length - 1; i++) {
1844
+ expect(resultGuids[i]).toEqual(resultEntities[i].guid);
1845
+ }
1846
+
1847
+ // Retrieving entities reverse sorted...
1848
+ resultEntities = await nymph.getEntities({
1849
+ class: TestModel,
1850
+ sort: 'number',
1851
+ reverse: true,
1852
+ });
1853
+ expect(resultEntities.length).toBeGreaterThan(100);
1854
+ for (let i = 0; i < resultEntities.length - 1; i++) {
1855
+ expect(resultEntities[i + 1].number ?? 0).toBeLessThanOrEqual(
1856
+ resultEntities[i].number ?? Infinity,
1857
+ );
1858
+ }
1859
+
1860
+ // And again with other selectors.
1861
+ // Retrieving entities sorted...
1862
+ resultEntities = await nymph.getEntities(
1863
+ { class: TestModel, sort: 'number' },
1864
+ { type: '&', match: ['name', '^Multi Test '] },
1865
+ );
1866
+ expect(resultEntities.length).toEqual(100);
1867
+ for (let i = 0; i < resultEntities.length - 1; i++) {
1868
+ expect(resultEntities[i + 1].number ?? Infinity).toBeGreaterThan(
1869
+ resultEntities[i].number ?? 0,
1870
+ );
1871
+ expect(resultEntities[i].name).toEqual(
1872
+ `Multi Test ${100 - (resultEntities[i].number ?? 0)}`,
1873
+ );
1874
+ }
1875
+
1876
+ // Retrieving entities reverse sorted...
1877
+ resultEntities = await nymph.getEntities(
1878
+ { class: TestModel, sort: 'number', reverse: true },
1879
+ { type: '&', match: ['name', '^Multi Test '] },
1880
+ );
1881
+ expect(resultEntities.length).toEqual(100);
1882
+ for (let i = 0; i < resultEntities.length - 1; i++) {
1883
+ expect(resultEntities[i + 1].number ?? 0).toBeLessThan(
1884
+ resultEntities[i].number ?? Infinity,
1885
+ );
1886
+ expect(resultEntities[i].name).toEqual(
1887
+ `Multi Test ${100 - (resultEntities[i].number ?? 0)}`,
1888
+ );
1889
+ }
1890
+ });
1891
+
1707
1892
  it('delete reference', async () => {
1708
1893
  await createTestEntities();
1709
1894
 
1710
1895
  // Deleting referenced entities...
1896
+ await testEntity.reference?.$wake();
1711
1897
  expect(await testEntity.reference?.$delete()).toEqual(true);
1898
+ await Promise.all(testEntity.refArray?.map((e) => e.$wake()) || []);
1712
1899
  expect(testEntity.reference?.guid).toBeNull();
1713
1900
  });
1714
1901
 
@@ -1721,16 +1908,116 @@ This one's zip code is 92064.`;
1721
1908
 
1722
1909
  const entity = await nymph.getEntity(
1723
1910
  { class: TestModel },
1724
- { type: '&', guid: testGuid }
1911
+ { type: '&', guid: testGuid },
1725
1912
  );
1726
1913
 
1727
1914
  expect(entity).toBeNull();
1728
1915
  });
1916
+
1917
+ it('allows non-duplicate unique strings', async () => {
1918
+ // Creating entity...
1919
+ const uniqueEntityA = await TestModel.factory();
1920
+ uniqueEntityA.name = 'Entity Test ' + new Date().toLocaleString();
1921
+ uniqueEntityA.uniques = ['test a'];
1922
+
1923
+ // Saving entity...
1924
+ expect(await uniqueEntityA.$save()).toEqual(true);
1925
+ expect(uniqueEntityA.guid).not.toBeNull();
1926
+
1927
+ // Creating entity...
1928
+ const uniqueEntityB = await TestModel.factory();
1929
+ uniqueEntityB.name = 'Entity Test ' + new Date().toLocaleString();
1930
+ uniqueEntityB.uniques = ['test b'];
1931
+
1932
+ // Saving entity...
1933
+ expect(await uniqueEntityB.$save()).toEqual(true);
1934
+ expect(uniqueEntityB.guid).not.toBeNull();
1935
+
1936
+ expect(uniqueEntityA.guid).not.toEqual(uniqueEntityB.guid);
1937
+
1938
+ expect(await uniqueEntityA.$delete()).toEqual(true);
1939
+ expect(await uniqueEntityB.$delete()).toEqual(true);
1940
+ });
1941
+
1942
+ it('throws on duplicate unique strings', async () => {
1943
+ // Creating entity...
1944
+ const uniqueEntityA = await TestModel.factory();
1945
+ uniqueEntityA.name = 'Entity Test ' + new Date().toLocaleString();
1946
+ uniqueEntityA.uniques = ['test a'];
1947
+
1948
+ // Saving entity...
1949
+ expect(await uniqueEntityA.$save()).toEqual(true);
1950
+ expect(uniqueEntityA.guid).not.toBeNull();
1951
+
1952
+ // Creating entity...
1953
+ const uniqueEntityB = await TestModel.factory();
1954
+ uniqueEntityB.name = 'Entity Test ' + new Date().toLocaleString();
1955
+ uniqueEntityB.uniques = ['test a'];
1956
+
1957
+ // Saving entity...
1958
+ try {
1959
+ await uniqueEntityB.$save();
1960
+
1961
+ throw Error("Shouldn't get past the uniqueness check.");
1962
+ } catch (e: any) {
1963
+ expect(e).toBeInstanceOf(EntityUniqueConstraintError);
1964
+ }
1965
+ expect(uniqueEntityB.guid).toBeNull();
1966
+
1967
+ expect(await uniqueEntityA.$delete()).toEqual(true);
1968
+ });
1969
+
1970
+ it('allows duplicate unique string if first transaction is rolled back', async () => {
1971
+ // Creating transaction entity...
1972
+ const tnymphA = await nymph.startTransaction('test-unique-a');
1973
+ const TestModelA = tnymphA.getEntityClass(TestModel);
1974
+ const uniqueEntityA = await TestModelA.factory();
1975
+ uniqueEntityA.name = 'Entity Test ' + new Date().toLocaleString();
1976
+ uniqueEntityA.uniques = ['test a'];
1977
+
1978
+ // Saving entity...
1979
+ expect(await uniqueEntityA.$save()).toEqual(true);
1980
+ expect(uniqueEntityA.guid).not.toBeNull();
1981
+
1982
+ // Rolling back transaction...
1983
+ expect(await tnymphA.rollback('test-unique-a')).toEqual(true);
1984
+
1985
+ // Creating transaction entity...
1986
+ const tnymphB = await nymph.startTransaction('test-unique-b');
1987
+ const TestModelB = tnymphB.getEntityClass(TestModel);
1988
+ const uniqueEntityB = await TestModelB.factory();
1989
+ uniqueEntityB.name = 'Entity Test ' + new Date().toLocaleString();
1990
+ uniqueEntityB.uniques = ['test a'];
1991
+
1992
+ // Saving entity...
1993
+ expect(await uniqueEntityB.$save()).toEqual(true);
1994
+ expect(uniqueEntityB.guid).not.toBeNull();
1995
+
1996
+ expect(uniqueEntityA.guid).not.toEqual(uniqueEntityB.guid);
1997
+
1998
+ expect(await tnymphB.commit('test-unique-b')).toEqual(true);
1999
+
2000
+ const uniqueEntityACheck = await nymph.getEntity(
2001
+ { class: TestModel },
2002
+ { type: '&', guid: uniqueEntityA.guid ?? '' },
2003
+ );
2004
+ expect(uniqueEntityACheck).toBeNull();
2005
+
2006
+ const uniqueEntityBCheck = await nymph.getEntity(
2007
+ { class: TestModel },
2008
+ { type: '&', guid: uniqueEntityB.guid ?? '' },
2009
+ );
2010
+ expect(uniqueEntityBCheck).not.toBeNull();
2011
+
2012
+ if (uniqueEntityBCheck != null) {
2013
+ expect(await uniqueEntityBCheck.$delete()).toEqual(true);
2014
+ }
2015
+ });
1729
2016
  }
1730
2017
 
1731
2018
  export function UIDTest(
1732
2019
  nymph: Nymph,
1733
- it: (name: string, fn: () => void) => void
2020
+ it: (name: string, fn: () => void) => void,
1734
2021
  ) {
1735
2022
  it('delete old test data', async () => {
1736
2023
  expect(await nymph.deleteUID('TestUID')).toEqual(true);
@@ -1771,7 +2058,7 @@ export function UIDTest(
1771
2058
 
1772
2059
  export function ExportImportTest(
1773
2060
  nymph: Nymph,
1774
- it: (name: string, fn: () => void) => void
2061
+ it: (name: string, fn: () => void) => void,
1775
2062
  ) {
1776
2063
  const TestModel = nymph.addEntityClass(TestModelClass);
1777
2064
  const TestBModel = nymph.addEntityClass(TestBModelClass);
@@ -1807,23 +2094,38 @@ export function ExportImportTest(
1807
2094
  const bmodels = await nymph.getEntities({ class: TestBModel });
1808
2095
 
1809
2096
  expect(models.length).toEqual(30);
1810
- expect(bmodels.length).toEqual(10);
1811
-
1812
- const all = [...models, ...bmodels];
1813
- for (const model of all) {
1814
- if (model.index?.match(/^\d+a$/)) {
1815
- expect(model.null).toBeNull();
1816
- expect(model.string).toEqual('test');
1817
- expect(model.array).toEqual(['full', 'of', 'values', 500]);
1818
- expect(model.number).toEqual(30);
1819
- expect(model.timestamp).toBeGreaterThanOrEqual(strtotime('-2 minutes'));
1820
-
1821
- expect(model.reference?.guid).not.toBeNull();
1822
- expect(model.reference?.string).toEqual('another');
1823
- expect(model.reference?.index?.match(/^\d+b$/)).toBeTruthy();
1824
- expect(model.refArray?.[0].guid).not.toBeNull();
1825
- expect(model.refArray?.[0].guid).toEqual(model.reference?.guid);
1826
- }
2097
+ expect(bmodels.length).toEqual(30);
2098
+
2099
+ for (const model of models) {
2100
+ expect(model.name).toMatch(/^Entity Test /);
2101
+ expect(model.null).toBeDefined();
2102
+ expect(model.null).toBeNull();
2103
+ expect(model.string).toEqual('test');
2104
+ expect(model.array).toEqual([
2105
+ 'full',
2106
+ 'of',
2107
+ 'values',
2108
+ 500,
2109
+ { test: true },
2110
+ { nullbyte: '\\\x00\u0000 \x00' },
2111
+ ]);
2112
+ expect(model.match).toEqual(matchValue);
2113
+ expect(model.number).toEqual(30);
2114
+ expect(model.numberString).toEqual('30');
2115
+ expect(model.timestamp).toBeGreaterThanOrEqual(strtotime('-2 minutes'));
2116
+ expect(model.index).toMatch(/^\d+a$/);
2117
+
2118
+ await model.reference?.$wake();
2119
+ expect(model.reference?.guid).not.toBeNull();
2120
+ expect(model.reference?.string).toEqual('another');
2121
+ expect(model.reference?.index).toMatch(/^\d+b$/);
2122
+ expect(model.index?.substring(0, -1)).toEqual(
2123
+ model.reference?.index?.substring(0, -1),
2124
+ );
2125
+ expect(model.reference?.$inArray(bmodels)).toEqual(true);
2126
+ await Promise.all(model.refArray?.map((e) => e.$wake()) || []);
2127
+ expect(model.refArray?.[0].guid).not.toBeNull();
2128
+ expect(model.refArray?.[0].guid).toEqual(model.reference?.guid);
1827
2129
  }
1828
2130
  }
1829
2131
 
@@ -1836,22 +2138,29 @@ export function ExportImportTest(
1836
2138
  expect(await nymph.newUID('TestUID')).toEqual(2);
1837
2139
  expect(await nymph.newUID('TestUID2')).toEqual(1);
1838
2140
 
1839
- for (let i = 0; i < 20; i++) {
1840
- const EntityClass = i < 15 ? TestModel : TestBModel;
1841
-
2141
+ for (let i = 0; i < 30; i++) {
1842
2142
  // Creating entity...
1843
- const testEntity = await EntityClass.factory();
2143
+ const testEntity = await TestModel.factory();
1844
2144
 
1845
2145
  // Saving entity...
1846
2146
  testEntity.name = 'Entity Test ' + new Date().toLocaleString();
1847
2147
  testEntity.null = null;
1848
2148
  testEntity.string = 'test';
1849
- testEntity.array = ['full', 'of', 'values', 500];
2149
+ testEntity.array = [
2150
+ 'full',
2151
+ 'of',
2152
+ 'values',
2153
+ 500,
2154
+ { test: true },
2155
+ { nullbyte: '\\\x00\u0000 \x00' },
2156
+ ];
2157
+ testEntity.match = matchValue;
1850
2158
  testEntity.number = 30;
2159
+ testEntity.numberString = '30';
1851
2160
  testEntity.timestamp = Date.now();
1852
2161
  testEntity.index = i + 'a';
1853
2162
 
1854
- const entityReferenceTest = await EntityClass.factory();
2163
+ const entityReferenceTest = await TestBModel.factory();
1855
2164
  entityReferenceTest.string = 'another';
1856
2165
  entityReferenceTest.index = i + 'b';
1857
2166
 
@@ -1865,9 +2174,13 @@ export function ExportImportTest(
1865
2174
  await checkEntityDataAndCount();
1866
2175
  });
1867
2176
 
2177
+ it('needs migration', async () => {
2178
+ expect(await nymph.needsMigration()).toEqual(false);
2179
+ });
2180
+
1868
2181
  it('export data', async () => {
1869
2182
  expect(await nymph.export(__dirname + '/testentityexport.nex')).toEqual(
1870
- true
2183
+ true,
1871
2184
  );
1872
2185
  });
1873
2186
 
@@ -1884,7 +2197,7 @@ export function ExportImportTest(
1884
2197
  expect(bmodels.length).toEqual(0);
1885
2198
 
1886
2199
  expect(await nymph.import(__dirname + '/testentityexport.nex')).toEqual(
1887
- true
2200
+ true,
1888
2201
  );
1889
2202
 
1890
2203
  await checkEntityDataAndCount();
@@ -1892,3 +2205,114 @@ export function ExportImportTest(
1892
2205
  fs.unlinkSync(__dirname + '/testentityexport.nex');
1893
2206
  });
1894
2207
  }
2208
+
2209
+ const matchValue = `Hello, my name is Edward McCheese. It is a pleasure to meet you. As you can see, I have several hats of the most pleasant nature.
2210
+
2211
+ This one's email address is nice_hat-wednesday+newyork@im-a-hat.hat.
2212
+ This one's phone number is (555) 555-1818.
2213
+ This one's zip code is 92064.
2214
+ This one's favorite emojis are 🔥❤️😊😂⭐🤔
2215
+
2216
+ These hats are absolutely fantastic.
2217
+
2218
+ \x00\x00\x00
2219
+
2220
+ Lorem ipsum odor amet, consectetuer adipiscing elit. Metus ad mattis sit pretium per, dignissim imperdiet luctus. Congue rhoncus turpis etiam aenean ultricies dapibus justo nunc. Netus non primis quis habitasse lacus. Nascetur dapibus sociosqu ridiculus primis; elementum netus consectetur ridiculus litora. Tristique facilisis erat ex class nulla cursus amet. Metus vitae tempor euismod vel; ullamcorper ac quisque vestibulum. Mauris libero pulvinar facilisi eros natoque massa.
2221
+
2222
+ Nunc vel hac nec tristique vivamus. Leo volutpat convallis eget integer tellus cubilia tincidunt malesuada? Consequat elit nisi tristique vehicula cubilia maecenas metus facilisi malesuada. In mattis euismod ad magnis fusce. Nisi congue sociosqu rhoncus lobortis fringilla sollicitudin at platea. Iaculis ut et varius metus eleifend laoreet hac odio libero. Non ridiculus tempus ultricies nullam curabitur.
2223
+
2224
+ Amet pellentesque aliquam placerat; vestibulum blandit platea porttitor pulvinar. Tellus tristique ad morbi in ac placerat luctus. Ante efficitur inceptos commodo lacus sodales sit varius nunc consequat. Senectus non vel est convallis mauris. Venenatis feugiat massa nostra, purus class primis sodales odio. Risus nulla integer feugiat ridiculus porta nascetur. Rutrum tincidunt enim parturient libero nisl ante sagittis nisi. Cubilia massa non vehicula vehicula amet parturient pellentesque. Habitant dapibus fames lectus pretium rhoncus.
2225
+
2226
+ Ridiculus nascetur mauris iaculis hendrerit ridiculus gravida auctor in. Class suscipit augue finibus semper vulputate nec. Tristique mi eu praesent commodo fermentum inceptos penatibus lobortis. Libero enim orci ultricies egestas ut pellentesque. Laoreet massa ad curabitur tellus libero laoreet habitasse enim nascetur. Iaculis euismod a euismod conubia purus. Commodo condimentum ultrices lorem ligula aenean; netus mattis sem non.
2227
+
2228
+ Curabitur duis imperdiet mus integer vel bibendum; fusce malesuada. Dignissim duis himenaeos primis odio, congue pharetra? Egestas mus sit eget proin quis. Neque dapibus dapibus nam sociosqu; maecenas viverra himenaeos. Himenaeos faucibus himenaeos faucibus ex litora eros faucibus cras. Maximus scelerisque nullam nunc congue fringilla. Nisi eu magna erat morbi cras enim amet litora. Nostra primis vitae arcu, accumsan sollicitudin curabitur. Potenti sit vel vehicula metus leo id. Etiam blandit quisque nam orci; neque lacinia rutrum.
2229
+
2230
+ Aliquam mollis varius hendrerit sem eleifend fermentum. Sapien rutrum condimentum inceptos ex feugiat consectetur mollis magna diam. Natoque enim nisi, ex risus finibus lacinia conubia vivamus suscipit. Habitasse interdum lorem ante, bibendum posuere dis. Lacus porttitor sapien proin; consequat velit ipsum venenatis. Vivamus porta mattis morbi nunc torquent neque. Senectus vehicula tincidunt parturient fringilla id amet urna libero pharetra.
2231
+
2232
+ Faucibus netus tincidunt et viverra augue ligula est quis. Ipsum tempus vehicula tortor dis tortor ad. Ex tincidunt torquent eleifend aenean urna commodo. Quam nullam imperdiet volutpat vel condimentum cubilia sociosqu. Etiam tempor sapien mattis, venenatis aptent id risus. Efficitur luctus vel; nam ut commodo sociosqu hendrerit. Quisque placerat gravida rhoncus blandit vitae. Himenaeos id risus est mollis aliquet nam curabitur.
2233
+
2234
+ Habitasse sed est fames quis lobortis leo mattis. Nisl cursus tincidunt cursus felis porttitor. Ante integer turpis non class lobortis suscipit. Condimentum velit vulputate quis sapien, lacus magna adipiscing nec primis. Blandit consequat ipsum nostra dignissim; tincidunt torquent fames. Ac faucibus elit iaculis duis lobortis. Euismod facilisi massa turpis mus neque. Class vulputate quisque elementum suscipit nostra tempus adipiscing. Malesuada himenaeos finibus ad inceptos volutpat scelerisque inceptos.
2235
+
2236
+ Natoque platea at feugiat cras tellus facilisi suspendisse lacinia maximus. Duis vestibulum eget molestie turpis risus dapibus dignissim torquent? Nulla nibh aptent fringilla scelerisque euismod mauris ornare. Orci finibus taciti habitasse fringilla laoreet convallis. Class sed fringilla eget quisque sit auctor. Id cursus mauris praesent maecenas iaculis. Ullamcorper luctus habitant ultrices pharetra etiam mattis morbi fringilla lorem.
2237
+
2238
+ Pharetra porta orci ridiculus inceptos eleifend sem ante quis. Molestie velit penatibus libero per sem litora congue. Porta quis egestas vivamus vitae potenti ornare. Elit molestie nullam vitae quam viverra. Nisl fringilla massa ridiculus donec ridiculus sed magnis. Cursus ad enim consequat ultricies tortor rhoncus pellentesque augue. Netus facilisis tempor elementum interdum at sagittis habitasse. Pretium imperdiet duis diam ullamcorper donec at suscipit. Id per inceptos ac luctus massa imperdiet tempor. Parturient libero suscipit non tempor ligula ullamcorper placerat varius.
2239
+
2240
+ Libero duis suspendisse cubilia rhoncus scelerisque faucibus mattis. Leo fusce urna at per inceptos vel lobortis. Quisque ex duis euismod dictum hac nibh eros. Penatibus eleifend tellus donec elit primis phasellus habitant dictum. Imperdiet consequat facilisi massa, lacus gravida sodales id sapien. Ornare sapien sit convallis suscipit nunc enim. Tempus at vitae class sollicitudin proin. Dolor aenean felis netus consectetur mattis phasellus vestibulum. Orci fringilla sodales montes sed himenaeos ex massa natoque porttitor.
2241
+
2242
+ Mus condimentum dui mollis dolor accumsan ligula pretium? Est phasellus platea iaculis vehicula et eros vel rutrum placerat. Nulla laoreet faucibus; congue netus magna senectus lectus dictum. Sodales aliquam eget himenaeos adipiscing, tempor feugiat. Lorem pellentesque iaculis fames lectus cubilia ornare sagittis rhoncus? Bibendum viverra tellus libero congue dignissim metus tellus aenean ultrices. Sollicitudin cras sollicitudin mattis lacus facilisis fermentum scelerisque porttitor rutrum.
2243
+
2244
+ Sapien aptent fames curae, consectetur dapibus mauris sollicitudin tellus. Laoreet etiam dignissim, suscipit platea libero vitae taciti eu nec. Donec lobortis metus nisi; est enim himenaeos molestie tellus sapien. Sapien tellus rhoncus blandit fusce hendrerit feugiat. Maximus sit hendrerit tincidunt nec imperdiet hendrerit semper suscipit. Quam augue proin netus rutrum et sem. Neque penatibus cubilia nec metus porta. Ornare pulvinar quam auctor, elit curae ad donec dis. Egestas aptent non tortor potenti morbi mauris.
2245
+
2246
+ Montes dui in pharetra primis consequat ante integer. Vulputate libero gravida rutrum tortor suscipit massa! Netus rhoncus platea torquent dapibus consectetur suspendisse etiam sociosqu. Quis placerat mauris et quam nascetur. Dictumst mi rutrum justo vitae ultricies feugiat nulla faucibus morbi. Consectetur nec condimentum euismod sodales nisi purus; finibus elementum facilisi.
2247
+
2248
+ Senectus mus faucibus ut morbi eu maximus. Turpis tincidunt sodales sociosqu lorem amet pulvinar laoreet faucibus. Mus bibendum vulputate hendrerit sollicitudin eu ridiculus posuere augue leo? Cubilia nostra consequat; fusce egestas himenaeos class ornare nec. Est montes tortor vivamus congue inceptos erat mi eget pellentesque. Amet vulputate fringilla aliquet fames tristique. Rutrum malesuada dapibus vehicula risus nunc torquent habitant turpis habitant. Ipsum proin viverra adipiscing cras et augue hendrerit. Efficitur euismod aliquam habitant; sit nisl potenti.
2249
+
2250
+ Conubia dignissim metus phasellus tristique augue, nullam quam finibus. Dignissim vel enim mattis praesent penatibus. Sapien pharetra curae torquent turpis fermentum feugiat facilisis nisi. Lacinia justo ante mauris finibus vitae ante efficitur dis. Urna gravida conubia amet rhoncus felis ut lorem placerat. Quisque fermentum suscipit aenean nisi suscipit ac? Quis ornare faucibus amet conubia justo maximus hendrerit phasellus aenean. Ex vivamus vulputate in mollis mauris praesent vehicula erat neque.
2251
+
2252
+ Orci nullam commodo habitant volutpat per tincidunt mus sit. Nisi cubilia fringilla viverra at orci magnis massa nam orci. Duis iaculis sapien nulla nascetur elit porta fermentum. Amus libero vivamus vel finibus magnis placerat himenaeos. Integer posuere suscipit non vulputate enim. Conubia id lobortis habitasse luctus odio maecenas enim conubia non. Mus egestas massa platea nullam sociosqu, magnis cras. Quam placerat nisi dui gravida ultricies, facilisis eu pharetra vivamus.
2253
+
2254
+ Fusce maecenas dis finibus senectus nascetur tortor. Nec rhoncus pretium vivamus donec vel ligula curabitur. Velit dis laoreet aenean, fusce metus blandit erat. Ligula purus natoque, arcu finibus tincidunt efficitur dolor curabitur. Ac risus et ipsum; consequat integer phasellus diam. Praesent ipsum gravida placerat porta volutpat tincidunt maximus sapien. Phasellus gravida orci enim velit condimentum.
2255
+
2256
+ Dui id laoreet penatibus orci sit a. Iaculis dis porttitor luctus; lacus dignissim quam commodo lorem. Nullam dictum quisque accumsan porttitor tortor fusce aenean. Aliquet quisque ultricies malesuada auctor facilisi tristique. Dolor nulla conubia ultricies odio ad. Nunc consectetur venenatis consequat nisi habitant. Praesent accumsan scelerisque morbi aliquam sociosqu auctor, nostra aenean.
2257
+
2258
+ Mauris amet conubia egestas eu posuere nullam. Est neque dictum in, lacus aliquam ultrices vestibulum. Dapibus dis habitasse cras conubia felis nibh. Egestas nisl iaculis nostra neque enim, ridiculus praesent. Consectetur eleifend eu mus; elit sed pellentesque fringilla. Ullamcorper hendrerit nibh aptent per congue libero ultrices eget. Mollis velit ad tortor lobortis ipsum.
2259
+
2260
+ Tristique neque justo potenti himenaeos; pellentesque nam vehicula. Maximus etiam ut nullam semper; fames curabitur quam ad morbi. Interdum curabitur platea augue porttitor a gravida. Leo imperdiet id aenean sit; habitasse quam tempus pellentesque? Nostra leo aenean amet lectus ultricies ridiculus nascetur ullamcorper. Taciti in iaculis quam nascetur proin varius eget vehicula.
2261
+
2262
+ Mattis hendrerit tempus interdum diam elementum primis augue phasellus sociosqu. Imperdiet pulvinar imperdiet lacinia posuere class magnis. Montes viverra scelerisque laoreet sociosqu proin lacus. Nam id justo praesent curabitur nam accumsan imperdiet commodo. Sociosqu netus sapien proin interdum ac. Dapibus tempor et sodales, natoque consequat torquent.
2263
+
2264
+ Lectus ultricies amet bibendum blandit finibus erat pellentesque. Nam quis ultrices curae; lorem gravida malesuada velit taciti enim. Facilisis fermentum suspendisse leo tristique litora dapibus rhoncus convallis. Netus iaculis eleifend viverra urna, vulputate ac convallis. Faucibus torquent dictum, nisl sed parturient libero. Ornare class habitant per consequat adipiscing rhoncus feugiat.
2265
+
2266
+ Proin molestie nullam eros parturient parturient curabitur aliquet. Rhoncus mus aenean sem aliquet sem finibus neque rutrum commodo. Efficitur litora lobortis nascetur adipiscing curae faucibus? Bibendum leo velit augue; potenti primis malesuada lacus ipsum. Facilisi potenti facilisis nam tempor consequat. Magnis suspendisse primis duis quam; suscipit quis fermentum phasellus. Massa ridiculus habitasse ipsum arcu sit maecenas gravida nisi? Dolor egestas lacinia lacinia libero nam curae suspendisse purus. Tristique inceptos curae netus scelerisque magna hendrerit commodo quis parturient. Eget accumsan erat sociosqu vestibulum platea turpis habitasse.
2267
+
2268
+ Maximus dignissim sed conubia a ipsum nullam condimentum dictumst. Suspendisse congue phasellus congue lacus sollicitudin senectus curae. Consequat sagittis in fringilla suscipit scelerisque suscipit. Rhoncus pharetra sodales malesuada sollicitudin lectus. Est primis pretium finibus felis pharetra nulla sapien lacinia. Nunc lorem aptent tristique quisque etiam posuere non ullamcorper. Potenti mus sed mus; non id eleifend pellentesque magnis.
2269
+
2270
+ Iaculis morbi mattis; ornare tincidunt neque mus egestas consectetur ultrices. Porta dapibus pretium, vulputate dis amet neque. Posuere auctor lacinia maecenas ridiculus ullamcorper tempus egestas cubilia nec. Cursus nulla lacinia mi facilisi, nisl tempor. Tempus elementum laoreet magnis neque morbi felis per. Suspendisse lectus vitae nunc amet himenaeos euismod aliquam. Quisque integer dictum aenean fermentum dictumst torquent.
2271
+
2272
+ Sociosqu per suspendisse augue phasellus velit dapibus parturient. At sit eu finibus posuere tincidunt. Phasellus duis scelerisque scelerisque taciti est venenatis. Arcu habitant augue amet eget maximus torquent. Eget gravida ut quisque ligula vel mus. Erat quis himenaeos; velit eget varius viverra interdum. Neque dapibus malesuada est a gravida libero integer aptent. Semper eleifend per at magnis, laoreet nibh orci vel ligula.
2273
+
2274
+ Odio purus finibus inceptos malesuada duis. Neque magnis est laoreet nibh gravida sagittis ullamcorper sodales. Parturient ultricies mattis lacus risus laoreet praesent. Tincidunt eleifend quis sagittis id nascetur. Nam scelerisque varius feugiat phasellus enim mauris nam. Tortor iaculis et cras; blandit sollicitudin pellentesque justo. Nam lacinia volutpat fusce nibh mollis; himenaeos iaculis. Vulputate dictum mattis sollicitudin accumsan at hendrerit.
2275
+
2276
+ Ipsum augue faucibus senectus porta dapibus metus. Netus sem amet nullam fermentum in dolor bibendum. Lacus quis enim vivamus enim risus elit suspendisse arcu. Penatibus proin pellentesque consequat nibh turpis fusce. Potenti sociosqu nunc tempor amet torquent. Aliquet porttitor adipiscing parturient curabitur hac? Condimentum morbi netus erat class hendrerit aptent. Placerat viverra molestie at eget donec quisque. Varius sem erat dolor, urna nunc ac duis inceptos maximus.
2277
+
2278
+ Nostra adipiscing dapibus eros vivamus accumsan elementum curae dignissim dignissim. Iaculis quisque fusce at conubia est habitant ipsum. Porttitor libero lobortis lobortis habitasse quis quisque nunc euismod aenean. Bibendum nullam volutpat quam vitae felis sit. Mauris bibendum nulla litora nec id, elit lacinia. Orci odio nunc est ante commodo dis quis diam convallis? Mattis a per cras amet egestas ex pellentesque nascetur augue. Egestas per massa per non metus hendrerit feugiat eu?
2279
+
2280
+ Praesent habitasse est elementum mattis potenti. Fermentum interdum enim orci dui faucibus sodales nisi mus. Tortor facilisi nunc potenti; dignissim magna varius! Risus cursus ornare tincidunt a feugiat massa cubilia. Sociosqu quis pharetra efficitur lorem ornare sapien arcu euismod. Elementum donec maecenas praesent scelerisque viverra mi natoque. Lacinia nibh eu commodo ut class blandit magnis.
2281
+
2282
+ Ullamcorper himenaeos mollis nostra placerat quam pellentesque nibh. Curae posuere cras dis senectus fringilla congue ipsum sit. Eros maecenas duis morbi consequat himenaeos ridiculus purus erat. Nascetur maximus massa eros class phasellus integer sed gravida. Vel donec lacinia donec curabitur penatibus integer ornare. Varius quam lectus magna per a mauris.
2283
+
2284
+ Imperdiet tempus malesuada ultrices egestas taciti nibh elit lacus. Nunc tempus tellus vitae duis rhoncus leo facilisis. Sapien nec mi lacus mi aliquet. Diam convallis fringilla libero duis integer integer dictum vel. Dolor montes nibh sapien dapibus ultrices praesent. Aeuismod phasellus taciti elit vehicula sit sociosqu. Lobortis neque urna dignissim penatibus felis vulputate. Primis magnis placerat, ligula massa facilisis nec.
2285
+
2286
+ Duis interdum himenaeos dis nisl et tortor condimentum accumsan. Laoreet amet fusce dis malesuada iaculis maximus fringilla. Conubia mus nibh felis vestibulum ad convallis mollis. Metus vivamus lobortis habitasse id nam. Egestas pretium eu penatibus consectetur malesuada congue tempus fusce. Rutrum neque pulvinar duis ligula fermentum malesuada. Tincidunt mollis molestie imperdiet ridiculus pharetra maximus sodales curabitur.
2287
+
2288
+ Sem nec integer fusce neque sagittis. Rutrum ipsum ante; urna enim primis consectetur nulla. Arcu ligula lectus varius magna ipsum, et dictum. Pharetra dignissim inceptos tristique natoque tempor volutpat. Luctus tristique himenaeos duis orci maecenas vel morbi. Habitasse a lacinia dignissim commodo elementum maecenas eu mollis. Fermentum tellus sem condimentum mattis elit lectus. Platea fusce arcu cras varius natoque? Volutpat tincidunt ridiculus mus massa ante dis sem ornare magna. Bibendum ornare ultrices proin efficitur; nascetur risus arcu.
2289
+
2290
+ Orci erat orci amet mollis venenatis. Feugiat torquent ex mattis, inceptos etiam integer. Class senectus aptent vivamus, semper dolor nisi at pretium volutpat. Natoque semper enim enim primis ultricies, pharetra pulvinar. Natoque litora tortor accumsan ridiculus lacinia integer; aliquet penatibus ridiculus. Placerat vestibulum justo tristique sapien senectus, et interdum et ridiculus. Urna aenean vel himenaeos; finibus a est efficitur donec. Dictum egestas quis fusce arcu; sapien himenaeos pretium congue. Semper et sapien nisi nascetur venenatis eros integer blandit.
2291
+
2292
+ Arcu per phasellus vehicula ad molestie? Eget arcu eget inceptos, eu ullamcorper diam. Gravida placerat elit ut hendrerit odio. Est lobortis imperdiet venenatis primis a. Facilisis integer maecenas adipiscing metus, rutrum curabitur. Dolor adipiscing himenaeos senectus tempus faucibus cras.
2293
+
2294
+ Massa torquent torquent ullamcorper erat nisl parturient primis eu pulvinar! Ridiculus sollicitudin dis eu, laoreet praesent hendrerit platea euismod. Lacinia dignissim suspendisse sagittis eu rutrum himenaeos curae massa diam. Platea ornare ridiculus consequat curabitur augue vestibulum ridiculus. Vel consectetur vivamus accumsan risus elementum? Imperdiet nascetur efficitur aliquam habitasse nascetur. Hendrerit quisque magnis in lacinia quis mauris.
2295
+
2296
+ Molestie fermentum blandit, viverra condimentum purus himenaeos. Fermentum congue a suspendisse ornare semper laoreet. Pharetra lacus non, iaculis ad taciti varius. Etiam nam risus vestibulum curabitur facilisis mattis, lorem hac id. Dignissim nibh tempor quam porta lectus nunc tincidunt aliquet. Tortor maximus maximus natoque nam magna torquent nec lectus mus. Vel fermentum semper vulputate penatibus vel purus.
2297
+
2298
+ Fermentum tincidunt penatibus platea himenaeos etiam sodales ad erat posuere. Vehicula vulputate sem blandit nullam sem. Condimentum eget lacus ad malesuada augue dui justo. Lobortis quis mauris pellentesque quam interdum sagittis. Nulla ullamcorper aptent hendrerit fusce hendrerit, cras cras magna. Ex quam torquent, congue dis est vulputate lacinia. Dignissim proin lacinia platea tortor elementum nullam. Purus natoque scelerisque habitant vestibulum; metus dui neque ipsum. Pellentesque augue montes fringilla et, maecenas habitant a.
2299
+
2300
+ Quam sapien eu scelerisque tristique, integer in rutrum gravida. Egestas lacinia nisi praesent turpis lacus maximus mus gravida. Dolor eget ultrices rhoncus velit; mollis id. Mi vulputate sed blandit nullam parturient venenatis. Neque vulputate iaculis nascetur felis fames ipsum adipiscing nullam? Vitae faucibus elit congue himenaeos orci volutpat nam. Magna tempus convallis vivamus eu semper. Egestas curabitur integer quis habitasse id taciti hac sociosqu morbi. Duis felis cursus potenti blandit cras dolor pharetra.
2301
+
2302
+ Ultricies vel primis nec mus malesuada congue? Habitasse semper mus ultricies; fermentum himenaeos placerat sodales. Platea sapien malesuada dignissim suscipit dis cras. Etiam odio pharetra metus donec odio natoque. Cras diam curae dapibus accumsan tortor mi laoreet. Ex mollis massa inceptos inceptos adipiscing. Cras rhoncus natoque accumsan augue enim. Parturient porttitor habitant semper platea elementum dictum ornare? Sociosqu blandit nullam vivamus elementum semper himenaeos.
2303
+
2304
+ Orci elit aliquam luctus habitant interdum. Tellus sollicitudin aliquam donec potenti praesent augue magnis auctor. Mattis faucibus iaculis etiam imperdiet lectus ad habitasse sollicitudin ac. Consequat maecenas quam dis adipiscing neque sociosqu. Ullamcorper in praesent himenaeos purus blandit nibh. Dignissim platea amet urna laoreet sociosqu lacinia accumsan consectetur risus. Adipiscing nullam arcu lobortis mi scelerisque feugiat non. Accumsan lacinia urna sit urna tincidunt nam pulvinar urna. Tellus cursus ac himenaeos sed aptent phasellus.
2305
+
2306
+ Scelerisque curabitur eget morbi leo phasellus morbi magnis. Elit nunc non vulputate eget at. Viverra efficitur dignissim fames ut condimentum tincidunt elementum lacus egestas. Dictum phasellus leo auctor dui diam. Sollicitudin placerat elit vehicula vulputate et at eleifend ullamcorper. Primis diam hac class leo justo etiam magnis. Justo maximus venenatis facilisis egestas hendrerit aptent arcu tortor consectetur. Consequat mus curabitur nisl; blandit enim at bibendum tempor bibendum. Ad nam arcu vehicula himenaeos sociosqu eu faucibus accumsan.
2307
+
2308
+ Maximus malesuada faucibus phasellus donec ligula. Rutrum pellentesque ultricies nullam; aenean scelerisque elementum. Porta luctus consectetur pharetra consequat varius. Ut dapibus senectus venenatis scelerisque fames ligula congue. Magna hendrerit faucibus ultricies tincidunt phasellus pellentesque, maecenas consequat! Malesuada senectus praesent sed condimentum aenean mi. Interdum sollicitudin mattis, purus vitae netus gravida. Nullam magna risus leo sit urna aenean.
2309
+
2310
+ Ut lacinia potenti vel varius habitant mus nullam adipiscing. Commodo potenti conubia hendrerit enim massa ad blandit. Nisl a massa nunc risus, condimentum enim. Hac aenean massa lacinia lobortis ad dolor sem. Nisl ex interdum blandit pulvinar pellentesque lorem. Sapien proin malesuada netus parturient pulvinar nec. Ex semper amet sem maximus blandit cras felis. Donec tellus auctor eleifend placerat natoque. Rutrum maecenas sollicitudin nisl consectetur in nulla rhoncus. Id rhoncus nec mi non lacinia leo efficitur nisi.
2311
+
2312
+ Dolor non phasellus id nascetur id nisi litora cubilia interdum. Lectus dolor sodales eu nulla porttitor placerat vulputate. Praesent ullamcorper consequat nulla torquent facilisis nunc. Rhoncus augue eleifend mauris erat duis varius felis. Dignissim nunc pulvinar vehicula dignissim maximus elit metus senectus. Venenatis conubia pulvinar commodo dui montes cubilia.
2313
+
2314
+ Cursus velit lacus aenean elit conubia. Velit in inceptos enim, elit lobortis est facilisis. Suscipit cursus dictum enim libero neque dolor himenaeos eu. Porta in integer praesent quisque quis sit. Primis velit tempus sit curae vehicula porttitor. Scelerisque nisi diam vehicula mi fusce dictum. Tincidunt mus eleifend commodo ridiculus adipiscing.
2315
+
2316
+ Pellentesque quis dignissim euismod in fermentum quam lobortis porta. Dis euismod ultricies montes odio sapien condimentum integer per. Torquent nascetur ante ante; diam ultrices nec habitant. Augue congue a conubia commodo ultricies tortor. Quis ridiculus netus vivamus dictumst efficitur parturient hendrerit. Facilisis ultrices suspendisse elit sodales eleifend maecenas tempor. Habitasse platea congue ac, pretium augue odio interdum netus. Mattis odio mi leo integer nisi diam phasellus elementum. Tortor himenaeos curabitur enim sit ac mi dictumst faucibus sociosqu.
2317
+
2318
+ Duis ex viverra auctor praesent elit ac. Sit ex at cubilia aenean scelerisque finibus ridiculus. Hendrerit imperdiet potenti erat risus commodo. Sit donec ullamcorper facilisi neque varius, suscipit malesuada hac. Nulla lacinia pulvinar non volutpat pellentesque lobortis ultrices dis. Faucibus luctus fusce, aliquam magnis pharetra sed dui nulla viverra. Lectus hendrerit eu pellentesque nostra mauris suspendisse himenaeos. Lectus bibendum inceptos commodo nulla magnis proin.`;