UNPKG

@nymphjs/nymph

Version:

Nymph.js - Nymph ORM

1,155 lines 91.4 kB
import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import fs from 'node:fs'; import strtotime from 'locutus/php/datetime/strtotime.js'; import { guid } from '@nymphjs/guid'; import { EntityUniqueConstraintError } from '../errors/index.js'; import { TestBModel as TestBModelClass, TestModel as TestModelClass, TestEmptyModel as TestEmptyModelClass, } from '../testArtifacts.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); export function EntitiesTest(nymph, it) { const TestModel = nymph.addEntityClass(TestModelClass); const TestBModel = nymph.addEntityClass(TestBModelClass); const TestEmptyModel = nymph.addEntityClass(TestEmptyModelClass); let testEntity; let testGuid; let refGuid; let createdMultiple = false; // The entities created by this function are required by many of the tests. async function createTestEntities() { if (testGuid != null) { return; } // Creating entity... testEntity = await TestModel.factory(); // Saving entity... testEntity.name = 'Entity Test ' + new Date().toLocaleString(); testEntity.null = null; testEntity.string = 'test'; testEntity.array = [ 'full', 'of', 'values', 500, { test: true }, { nullbyte: '\\\x00\u0000 \x00' }, ]; testEntity.match = matchValue; testEntity.number = 30; testEntity.numberString = '30'; testEntity.timestamp = Date.now(); expect(await testEntity.$save()).toEqual(true); expect(testEntity.guid).not.toBeNull(); testGuid = testEntity.guid; const entityReferenceTest = new TestModel(); entityReferenceTest.string = 'wrong'; entityReferenceTest.timestamp = strtotime('-2 days') * 1000; expect(await entityReferenceTest.$save()).toEqual(true); refGuid = entityReferenceTest.guid; testEntity.reference = entityReferenceTest; testEntity.refArray = [entityReferenceTest]; expect(await testEntity.$save()).toEqual(true); entityReferenceTest.test = 'good'; expect(await entityReferenceTest.$save()).toEqual(true); // Test asynchronous getEntity. testEntity = (await nymph.getEntity({ class: TestModel }, testGuid)); expect(testEntity).toBeInstanceOf(TestModel); expect(testEntity.guid).toEqual(testGuid); } // The entities created by this function are required by many of the tests. async function createMultipleTestEntities() { if (!createdMultiple) { createdMultiple = true; // Creating 100 entities... for (let i = 0; i < 100; i++) { const testEntity = await TestModel.factory(); testEntity.name = `Multi Test ${i}`; // Reverse the number for sort testing. testEntity.number = 100 - i; testEntity.$removeTag('test'); testEntity.$addTag('multiTest'); expect(await testEntity.$save()).toEqual(true); // Pause for a few milliseconds so the cdate and mdate can be sorted. await new Promise((res) => setTimeout(() => res(1), 5)); } } } it('delete old test data', async () => { let amodels = await nymph.getEntities({ class: TestModel }); expect(Array.isArray(amodels)).toEqual(true); for (const cur of amodels) { expect(await cur.$delete()).toEqual(true); } amodels = await nymph.getEntities({ class: TestModel }); expect(amodels.length).toEqual(0); let bmodels = await nymph.getEntities({ class: TestBModel }); expect(Array.isArray(bmodels)).toEqual(true); for (const cur of bmodels) { expect(await cur.$delete()).toEqual(true); } bmodels = await nymph.getEntities({ class: TestBModel }); expect(bmodels.length).toEqual(0); }); it('create entity', async () => { await createTestEntities(); }); it("doesn't create empty entity", async () => { const testEntity = await TestEmptyModel.factory(); expect(await testEntity.$save()).toBeFalsy(); expect(testEntity.guid).toBeNull(); }); it('update mdate on save', async () => { await createTestEntities(); const oldMdate = testEntity.mdate ?? Infinity; await new Promise((resolve) => setTimeout(() => resolve(true), 100)); await testEntity.$save(); expect(testEntity.mdate).toBeGreaterThan(oldMdate); }); it('create multiple entities', async () => { return createMultipleTestEntities(); }); it('by guid', async () => { await createTestEntities(); // Retrieving entity by GUID... let resultEntity = await nymph.getEntity({ class: TestModel }, testGuid); expect(testEntity.$is(resultEntity)).toEqual(true); // Using class constructor... resultEntity = await TestModel.factory(testGuid); expect(testEntity.$is(resultEntity)).toEqual(true); // Testing wrong GUID... resultEntity = await nymph.getEntity({ class: TestModel }, guid()); expect(testEntity.$is(resultEntity)).toEqual(false); }); it('guaranteed guid', async () => { // Creating entity... const testEntity = await TestModel.factory(); // Saving entity... testEntity.name = 'Entity Test ' + new Date().toLocaleString(); testEntity.null = null; testEntity.string = 'test'; testEntity.array = []; testEntity.match = matchValue; testEntity.number = 30; testEntity.numberString = '30'; testEntity.timestamp = Date.now(); // Get the guaranteed GUID. const testGuid = testEntity.$getGuaranteedGUID(); expect(await testEntity.$save()).toEqual(true); expect(testEntity.guid).not.toBeNull(); expect(testEntity.guid).toEqual(testGuid); // Retrieving entity by GUID... let resultEntity = await nymph.getEntity({ class: TestModel }, testGuid); expect(testEntity.$is(resultEntity)).toEqual(true); // Delete the entity. expect(await testEntity.$delete()).toEqual(true); }); it('transactions', async () => { await createTestEntities(); // Verify not in a transaction. expect(await nymph.inTransaction()).toEqual(false); let transaction = await nymph.startTransaction('test'); testEntity.$nymph = transaction; if (!(await transaction.inTransaction())) { console.log('This Nymph driver or database seems to not support transactions. Skipping transaction tests.'); await transaction.rollback('test'); return; } // Change a value in the test entity. testEntity.string = 'bad value'; expect(await testEntity.$save()).toEqual(true); // Rollback the transaction. await transaction.rollback('test'); // Verify not in a transaction. expect(await transaction.inTransaction()).toEqual(false); // Verify the value is correct. await testEntity.$refresh(); expect(testEntity.string).toEqual('test'); // Start a new transaction. transaction = await nymph.startTransaction('test'); testEntity.$nymph = transaction; // Verify in a transaction. expect(await transaction.inTransaction()).toEqual(true); // Delete the entity. expect(await testEntity.$delete()).toEqual(true); const resultEntity = await transaction.getEntity({ class: TestModel }, testGuid); expect(resultEntity).toBeNull(); // Rollback the transaction. await transaction.rollback('test'); // Verify not in a transaction. expect(await transaction.inTransaction()).toEqual(false); // Verify it's back. testEntity = (await transaction.getEntity({ class: TestModel }, testGuid)); expect(testEntity.guid).toEqual(testGuid); // Start a new transaction with a dot in the name. transaction = await nymph.startTransaction('test.1'); testEntity.$nymph = transaction; // Verify in a transaction. expect(await transaction.inTransaction()).toEqual(true); // Make a change. testEntity.string = 'fish'; expect(await testEntity.$save()).toEqual(true); // Commit the transaction. await transaction.commit('test.1'); testEntity.$nymph = nymph; // Verify not in a transaction. expect(await transaction.inTransaction()).toEqual(false); // Verify the value is correct. await testEntity.$refresh(); expect(testEntity.string).toEqual('fish'); // Finally, change it back. testEntity.string = 'test'; expect(await testEntity.$save()).toEqual(true); // TODO: nested transactions }); it('options', async () => { await createTestEntities(); // Testing entity order, offset, limit... const resultEntities = await nymph.getEntities({ class: TestModel, reverse: true, offset: 1, limit: 1, sort: 'cdate', }, { type: '&', tag: 'test' }); expect(resultEntities.length).toEqual(1); expect(testEntity.$is(resultEntities[0])).toEqual(true); }); it('guid and tags', async () => { await createTestEntities(); // Retrieving entity by GUID and tags... const resultEntity = await nymph.getEntity({ class: TestModel }, { type: '&', guid: testGuid, tag: 'test' }); expect(testEntity.$is(resultEntity)).toEqual(true); }); it('or selector', async () => { await createTestEntities(); // Retrieving entity by GUID and tags... const resultEntity = await nymph.getEntity({ class: TestModel }, { type: '|', guid: [testGuid, guid()] }); expect(testEntity.$is(resultEntity)).toEqual(true); }); it('wrong or selector', async () => { await createTestEntities(); // Retrieving entity by GUID and tags... const resultEntity = await nymph.getEntity({ class: TestModel }, { type: '|', guid: [guid(), guid()] }); expect(testEntity.$is(resultEntity)).toEqual(false); }); it('not guid', async () => { await createTestEntities(); // Retrieving entity by !GUID... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', '!guid': guid(), tag: 'test' }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('not tags', async () => { await createTestEntities(); // Retrieving entity by !tags... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', guid: testGuid, '!tag': ['barbecue', 'pickles'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('guid and wrong tags', async () => { await createTestEntities(); // Testing GUID and wrong tags... const resultEntity = await nymph.getEntity({ class: TestModel }, { type: '&', guid: testGuid, tag: ['pickles'] }); expect(resultEntity).toBeNull(); }); it('tags', async () => { await createTestEntities(); // Retrieving entity by tags... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test' }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong tags', async () => { await createTestEntities(); // Testing wrong tags... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'pickles' }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('inclusive tags', async () => { await createTestEntities(); // Retrieving entity by tags inclusively... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', tag: ['pickles', 'test', 'barbecue'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong inclusive tags', async () => { await createTestEntities(); // Testing wrong inclusive tags... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', tag: ['pickles', 'barbecue'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('mixed tags', async () => { await createTestEntities(); // Retrieving entity by mixed tags... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test' }, { type: '|', tag: ['pickles', 'test', 'barbecue'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong inclusive mixed tags', async () => { await createTestEntities(); // Testing wrong inclusive mixed tags... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test' }, { type: '|', tag: ['pickles', 'barbecue'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('wrong exclusive mixed tags', async () => { await createTestEntities(); // Testing wrong exclusive mixed tags... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'pickles' }, { type: '|', tag: ['test', 'barbecue'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('defined', async () => { await createTestEntities(); // Retrieving entity by defined... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', defined: 'string' }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('not defined', async () => { await createTestEntities(); // Retrieving entity by !defined... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', '!defined': 'pickles' }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('defined in a not and clause', async () => { await createTestEntities(); // Retrieving entity by defined in not and clause... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '!&', defined: 'pickles' }, { type: '&', tag: 'test' }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('equal', async () => { await createTestEntities(); // Retrieving entity by equal... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', equal: ['string', 'test'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by equal... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', equal: ['null', null] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by equal... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', equal: ['boolean', true] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by equal... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', equal: ['number', 30] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by equal... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', equal: [ 'array', [ 'full', 'of', 'values', 500, { test: true }, { nullbyte: '\\\x00\u0000 \x00' }, ], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by equal... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', equal: ['match', matchValue], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('not equal', async () => { await createTestEntities(); const referenceEntity = await TestModel.factory(refGuid); expect(referenceEntity.guid).toEqual(refGuid); // Retrieving entity by !equal... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', '!equal': ['string', 'wrong'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); expect(referenceEntity.$inArray(resultEntity)).toEqual(false); }); it('like', async () => { await createTestEntities(); // Retrieving entity by like... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', like: ['string', 't_s%'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('not like', async () => { await createTestEntities(); const referenceEntity = await TestModel.factory(refGuid); expect(referenceEntity.guid).toEqual(refGuid); // Retrieving entity by !like... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', '!like': ['string', 'wr_n%'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); expect(referenceEntity.$inArray(resultEntity)).toEqual(false); }); it('ilike', async () => { await createTestEntities(); // Retrieving entity by ilike... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', ilike: ['string', 'T_s%'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('not ilike', async () => { await createTestEntities(); const referenceEntity = await TestModel.factory(refGuid); expect(referenceEntity.guid).toEqual(refGuid); // Retrieving entity by !ilike... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', '!ilike': ['string', 'wr_n%'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); expect(referenceEntity.$inArray(resultEntity)).toEqual(false); }); it('like with wrong case', async () => { await createTestEntities(); // Retrieving entity by like... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', like: ['string', 'T_s%'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('tags and equal', async () => { await createTestEntities(); // Retrieving entity by tags and equal... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', equal: ['string', 'test'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong tags right equal', async () => { await createTestEntities(); // Testing wrong tags and right equal... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'pickles', equal: ['string', 'test'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('right tags wrong equal', async () => { await createTestEntities(); // Testing right tags and wrong equal... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', equal: ['string', 'pickles'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('wrong tags wrong equal', async () => { await createTestEntities(); // Testing wrong tags and wrong equal... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'pickles', equal: ['string', 'pickles'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('contain', async () => { await createTestEntities(); // Retrieving entity by contain... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', contain: ['array', 'values'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by contain... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', contain: ['array', 500] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by contain... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', contain: ['array', { test: true }] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('not contain', async () => { await createTestEntities(); // Retrieving entity by !contain... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test' }, { type: '!&', contain: ['array', 'pickles'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong contain', async () => { await createTestEntities(); // Testing wrong contain... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', contain: ['array', 'pickles'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Testing wrong contain... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', contain: ['string', 'pickles'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('match', async () => { await createTestEntities(); // Retrieving entity by regex match... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', match: ['match', '.*'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', match: ['match', 'Edward McCheese'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test' }, { type: '|', match: [ ['string', '[0-9]'], ['match', 'Edward McCheese'], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', match: ['match', '[-a-zA-Z0-9+_]+@[-a-zA-Z0-9_]+.[-a-zA-Z0-9_]{2,4}'], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', match: ['match', '\\([0-9]{3}\\) [0-9]{3}-[0-9]{4}'], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('imatch', async () => { await createTestEntities(); // Retrieving entity by regex match... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', imatch: ['match', 'edward mccheese'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong match', async () => { await createTestEntities(); // Testing wrong regex match... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', match: ['match', '='] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'pickle', match: ['match', '.*'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', match: [ ['string', '[0-9]'], ['match', ',,'], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('match wrong case', async () => { await createTestEntities(); // Retrieving entity by regex match... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', match: ['match', 'edward mccheese'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('match and equal inclusive', async () => { await createTestEntities(); // Retrieving entity by regex + equal inclusively... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test' }, { type: '|', equal: ['string', 'pickles'], match: ['string', 'test'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('greater than', async () => { await createTestEntities(); // Retrieving entity by inequality... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gt: [ ['number', 30], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gt: [ ['number', 31], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gt: [ ['number', 29], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gt: [ ['numberString', 30], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gt: [ ['numberString', 31], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gt: [ ['numberString', 29], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('greater than or equal', async () => { await createTestEntities(); // Retrieving entity by inequality... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gte: [ ['number', 30], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gte: [ ['number', 31], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gte: [ ['number', 29], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gte: [ ['numberString', 30], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gte: [ ['numberString', 31], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gte: [ ['numberString', 29], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('less than', async () => { await createTestEntities(); // Retrieving entity by inequality... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lt: [ ['number', 30], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lt: [ ['number', 31], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lt: [ ['number', 29], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lt: [ ['numberString', 30], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lt: [ ['numberString', 31], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lt: [ ['numberString', 29], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('less than or equal', async () => { await createTestEntities(); // Retrieving entity by inequality... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lte: [ ['number', 30], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lte: [ ['number', 31], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lte: [ ['number', 29], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lte: [ ['numberString', 30], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lte: [ ['numberString', 31], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by inequality... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', lte: [ ['numberString', 29], ['pickles', 100], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('not inequality', async () => { await createTestEntities(); // Retrieving entity by !inequality... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test' }, { type: '!&', gte: ['number', 60] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong inequality', async () => { await createTestEntities(); // Testing wrong inequality... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', lte: ['number', 29.99] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('greater than cdate', async () => { await createTestEntities(); // Retrieving entity by time... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', gt: ['cdate', (testEntity.cdate ?? 0) - 120] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong cdate', async () => { await createTestEntities(); // Testing wrong time... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', gte: ['cdate', (testEntity.cdate ?? 0) + 1] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('time selector', async () => { await createTestEntities(); const referenceEntity = await TestModel.factory(refGuid); // Retrieving entity by relative time... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', gt: ['timestamp', null, '-1 day'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); expect(referenceEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by relative time inclusively... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', gt: [ ['timestamp', null, '-1 day'], ['timestamp', null, '+5 days'], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); expect(referenceEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by relative time... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', gt: ['timestamp', null, '-3 days'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); expect(referenceEntity.$inArray(resultEntity)).toEqual(true); // Retrieving entity by relative time... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', gt: ['cdate', null, '-1 day'] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); expect(referenceEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong time selector', async () => { await createTestEntities(); const referenceEntity = await TestModel.factory(refGuid); // Retrieving entity by relative time... let resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', gt: ['timestamp', null, '+1 day'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); expect(referenceEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by relative time... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', lt: ['timestamp', null, '-3 days'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); expect(referenceEntity.$inArray(resultEntity)).toEqual(false); // Retrieving entity by relative time... resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test', gt: ['cdate', null, '+1 day'] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); expect(referenceEntity.$inArray(resultEntity)).toEqual(false); }); it('references', async () => { await createTestEntities(); // Testing referenced entities... await testEntity.reference?.$wake(); expect(testEntity.reference?.test).toEqual('good'); // Testing referenced entity arrays... await Promise.all(testEntity.refArray?.map((e) => e.$wake()) || []); expect(testEntity.refArray?.[0].test).toEqual('good'); }); it('ref', async () => { await createTestEntities(); // Retrieving entity by reference... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', ref: ['reference', refGuid] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('not ref', async () => { await createTestEntities(); // Retrieving entity by !reference... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', tag: 'test' }, { type: '!&', ref: ['reference', guid()] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong ref', async () => { await createTestEntities(); // Testing wrong reference... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', ref: ['reference', guid()] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('nonexistent ref', async () => { await createTestEntities(); // Testing non-existent reference... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', ref: ['pickle', refGuid] }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('inclusive ref', async () => { await createTestEntities(); // Retrieving entity by inclusive reference... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', ref: [ ['reference', refGuid], ['reference', guid()], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong inclusive ref', async () => { await createTestEntities(); // Testing wrong inclusive reference... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '|', ref: [ ['reference', guid()], ['reference', guid()], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('ref in an array', async () => { await createTestEntities(); // Retrieving entity by array reference... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', ref: ['refArray', refGuid] }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('wrong ref in an array', async () => { await createTestEntities(); // Testing wrong array reference... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', ref: [ ['refArray', refGuid], ['refArray', guid()], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(false); }); it('logic operations', async () => { await createTestEntities(); // Testing logic operations... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', '!ref': [ ['refArray', guid()], ['refArray', guid()], ], '!lte': ['number', 29.99], }, { type: '|', '!lte': [ ['number', 29.99], ['number', 30], ], }, { type: '!&', '!equal': ['string', 'test'], '!contain': [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ['array', { test: true }], ['array', { nullbyte: '\\\x00\u0000 \x00' }], ], }, { type: '!|', '!equal': ['string', 'test'], contain: [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); }); it('count return', async () => { await createTestEntities(); const result = await nymph.getEntities({ class: TestModel }); // Testing count return... const resultCount = await nymph.getEntities({ class: TestModel, return: 'count', }); expect(resultCount).toBeGreaterThanOrEqual(1); expect(resultCount).toEqual(result.length); const resultSelectors = await nymph.getEntities({ class: TestModel }, { type: '&', ref: ['reference', refGuid] }); // Testing count return with selectors... const resultSelectorsCount = await nymph.getEntities({ class: TestModel, return: 'count' }, { type: '&', ref: ['reference', refGuid] }); expect(resultSelectorsCount).toBeGreaterThanOrEqual(1); expect(resultSelectorsCount).toEqual(resultSelectors.length); // Testing count return with limit... const resultSelectorsLimit = await nymph.getEntities({ class: TestModel, limit: 1, return: 'count', }); expect(resultSelectorsLimit).toEqual(1); // Testing count return with limit... const resultSelectorsSingle = await nymph.getEntity({ class: TestModel, return: 'count', }); expect(resultSelectorsSingle).toEqual(1); // Testing empty count... const resultSelectorsEmpty = await nymph.getEntities({ class: TestModel, return: 'count' }, { type: '&', ref: ['reference', guid()] }); expect(resultSelectorsEmpty).toEqual(0); }); it('guid return', async () => { await createTestEntities(); // Testing guid return using logic operations... const resultGuid = await nymph.getEntities({ class: TestModel, return: 'guid' }, { type: '&', '!ref': [ ['refArray', guid()], ['refArray', guid()], ], '!lte': ['number', 29.99], }, { type: '|', '!lte': [ ['number', 29.99], ['number', 30], ], }, { type: '!&', '!equal': ['string', 'test'], '!contain': [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ['array', { test: true }], ['array', { nullbyte: '\\\x00\u0000 \x00' }], ], }, { type: '!|', '!equal': ['string', 'test'], contain: [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ], }); expect(resultGuid.indexOf(testEntity.guid ?? '')).toBeGreaterThan(-1); }); it('object return', async () => { await createTestEntities(); // Testing object return using logic operations... const resultObjects = await nymph.getEntities({ class: TestModel, return: 'object' }, { type: '&', '!ref': [ ['refArray', guid()], ['refArray', guid()], ], '!lte': ['number', 29.99], }, { type: '|', '!lte': [ ['number', 29.99], ['number', 30], ], }, { type: '!&', '!equal': ['string', 'test'], '!contain': [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ['array', { test: true }], ['array', { nullbyte: '\\\x00\u0000 \x00' }], ], }, { type: '!|', '!equal': ['string', 'test'], contain: [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ], }); const resultObject = resultObjects.find((entity) => entity.guid === testEntity.guid); expect(resultObject).toBeInstanceOf(Object); expect(resultObject).not.toBeInstanceOf(TestModel); expect(Array.isArray(resultObject?.tags)).toBeTruthy(); expect(resultObject?.string).toEqual('test'); }); it('deep selector', async () => { await createTestEntities(); // Testing deep selectors... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', '!ref': [ ['refArray', guid()], ['refArray', guid()], ], '!lte': ['number', 29.99], }, { type: '&', selector: [ { type: '|', '!lte': [ ['number', 29.99], ['number', 30], ], }, { type: '!&', '!equal': ['string', 'test'], '!contain': [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ['array', { test: true }], ['array', { nullbyte: '\\\x00\u0000 \x00' }], ], }, { type: '!|', '!equal': ['string', 'test'], contain: [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ], }, ], }); expect(testEntity.$inArray(resultEntity)).toEqual(true); const resultEntity2 = await nymph.getEntities({ class: TestModel }, { type: '&', '!ref': [ ['refArray', guid()], ['refArray', guid()], ], '!lte': ['number', 29.99], }, { type: '|', selector: [ { type: '&', '!lte': [ ['number', 29.99], ['number', 30], ], }, { type: '!&', '!equal': ['string', 'test'], '!contain': [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ['array', { test: true }], ['array', { nullbyte: '\\\x00\u0000 \x00' }], ], }, { type: '&', '!equal': ['string', 'test'], contain: [ ['array', 'full'], ['array', 'of'], ['array', 'values'], ['array', 500], ], }, ], }); expect(testEntity.$inArray(resultEntity2)).toEqual(true); const resultEntity3 = await nymph.getEntities({ class: TestModel }, { type: '|', selector: [ { type: '&', '!ref': ['refArray', guid()], '!lte': ['number', 29.99], }, { type: '&', gte: ['number', 16000] }, ], }); expect(testEntity.$inArray(resultEntity3)).toEqual(true); const resultEntity4 = await nymph.getEntities({ class: TestModel }, { type: '|', selector: [ { type: '&', '!ref': ['refArray', guid()], '!lte': ['number', 29.99], }, { type: '&', selector: { type: '&', selector: { type: '&', gte: ['number', 16000] }, }, }, ], }); expect(testEntity.$inArray(resultEntity4)).toEqual(true); }); it('wrong deep selector', async () => { // Testing wrong deep selectors... const resultEntity = await nymph.getEntities({ class: TestModel }, { type: '&', selector: [ { type: '&', '!ref': ['refArray', guid()], '!lte'