@nymphjs/nymph
Version:
Nymph.js - Nymph ORM
1,757 lines (1,510 loc) • 107 kB
text/typescript
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 type Nymph from '../Nymph.js';
import { EntityUniqueConstraintError } from '../errors/index.js';
import {
TestBModel as TestBModelClass,
TestModel as TestModelClass,
TestModelData,
TestEmptyModel as TestEmptyModelClass,
} from '../testArtifacts.js';
const __dirname = dirname(fileURLToPath(import.meta.url));
export function EntitiesTest(
nymph: Nymph,
it: (name: string, fn: () => void) => void,
) {
const TestModel = nymph.addEntityClass(TestModelClass);
const TestBModel = nymph.addEntityClass(TestBModelClass);
const TestEmptyModel = nymph.addEntityClass(TestEmptyModelClass);
let testEntity: TestModelClass & TestModelData;
let testGuid: string;
let refGuid: string;
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.search = searchValue;
testEntity.number = 30;
testEntity.numberString = '30';
testEntity.timestamp = Date.now();
expect(await testEntity.$save()).toEqual(true);
expect(testEntity.guid).not.toBeNull();
testGuid = testEntity.guid as string;
const entityReferenceTest: TestModelClass & TestModelData = new TestModel();
entityReferenceTest.string = 'wrong';
entityReferenceTest.timestamp = strtotime('-2 days') * 1000;
expect(await entityReferenceTest.$save()).toEqual(true);
refGuid = entityReferenceTest.guid as string;
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,
)) as TestModelClass & TestModelData;
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('create, list, and delete indexes', async () => {
// Delete existing indexes.
const existingIndexes = await nymph.getIndexes(TestModel.ETYPE);
for (let index of existingIndexes) {
await nymph.deleteIndex(TestModel.ETYPE, index.scope, index.name);
}
const existingBIndexes = await nymph.getIndexes(TestBModel.ETYPE);
for (let index of existingBIndexes) {
await nymph.deleteIndex(TestBModel.ETYPE, index.scope, index.name);
}
const sortByName = (arr: { name: string }[]) => {
arr.sort((a, b) => a.name.localeCompare(b.name));
return arr;
};
expect(
await nymph.addIndex(TestModel.ETYPE, {
scope: 'data',
name: 'testindex',
property: 'test',
}),
).toEqual(true);
expect(sortByName(await nymph.getIndexes(TestModel.ETYPE))).toEqual([
{ scope: 'data', name: 'testindex', property: 'test' },
]);
expect(
await nymph.addIndex(TestModel.ETYPE, {
scope: 'data',
name: 'secondone',
property: 'match',
}),
).toEqual(true);
expect(sortByName(await nymph.getIndexes(TestModel.ETYPE))).toEqual([
{ scope: 'data', name: 'secondone', property: 'match' },
{ scope: 'data', name: 'testindex', property: 'test' },
]);
expect(
await nymph.addIndex(TestModel.ETYPE, {
scope: 'references',
name: 'refone',
property: 'reference',
}),
).toEqual(true);
expect(sortByName(await nymph.getIndexes(TestModel.ETYPE))).toEqual([
{ scope: 'references', name: 'refone', property: 'reference' },
{ scope: 'data', name: 'secondone', property: 'match' },
{ scope: 'data', name: 'testindex', property: 'test' },
]);
expect(
await nymph.addIndex(TestModel.ETYPE, {
scope: 'tokens',
name: 'tokenone',
property: 'search',
}),
).toEqual(true);
expect(sortByName(await nymph.getIndexes(TestModel.ETYPE))).toEqual([
{ scope: 'references', name: 'refone', property: 'reference' },
{ scope: 'data', name: 'secondone', property: 'match' },
{ scope: 'data', name: 'testindex', property: 'test' },
{ scope: 'tokens', name: 'tokenone', property: 'search' },
]);
expect(
await nymph.addIndex(TestBModel.ETYPE, {
scope: 'data',
name: 'flooflab',
property: 'string',
}),
).toEqual(true);
expect(sortByName(await nymph.getIndexes(TestBModel.ETYPE))).toEqual([
{ scope: 'data', name: 'flooflab', property: 'string' },
]);
expect(sortByName(await nymph.getIndexes(TestModel.ETYPE))).toEqual([
{ scope: 'references', name: 'refone', property: 'reference' },
{ scope: 'data', name: 'secondone', property: 'match' },
{ scope: 'data', name: 'testindex', property: 'test' },
{ scope: 'tokens', name: 'tokenone', property: 'search' },
]);
expect(
await nymph.deleteIndex(TestBModel.ETYPE, 'data', 'flooflab'),
).toEqual(true);
expect(await nymph.getIndexes(TestBModel.ETYPE)).toEqual([]);
expect(sortByName(await nymph.getIndexes(TestModel.ETYPE))).toEqual([
{ scope: 'references', name: 'refone', property: 'reference' },
{ scope: 'data', name: 'secondone', property: 'match' },
{ scope: 'data', name: 'testindex', property: 'test' },
{ scope: 'tokens', name: 'tokenone', property: 'search' },
]);
expect(
await nymph.deleteIndex(TestModel.ETYPE, 'data', 'testindex'),
).toEqual(true);
expect(sortByName(await nymph.getIndexes(TestModel.ETYPE))).toEqual([
{ scope: 'references', name: 'refone', property: 'reference' },
{ scope: 'data', name: 'secondone', property: 'match' },
{ scope: 'tokens', name: 'tokenone', property: 'search' },
]);
});
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,
)) as TestModelClass & TestModelData;
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...
let 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);
// Testing null sort...
resultEntities = await nymph.getEntities(
{
class: TestModel,
reverse: true,
sort: null,
},
{ type: '&', tag: 'test' },
);
expect(testEntity.$inArray(resultEntities)).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', '.*'] }, // anything
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
resultEntity = await nymph.getEntities(
{ class: TestModel },
{ type: '&', tag: 'test', match: ['match', 'Edward McCheese'] }, // a substring
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
resultEntity = await nymph.getEntities(
{ class: TestModel },
{ type: '&', tag: 'test' },
{
type: '|',
match: [
['string', '[0-9]'],
['match', 'Edward McCheese'],
],
}, // inclusive test
);
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}'],
}, // a simple email
);
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}'],
}, // a phone number
);
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'] }, // a substring
);
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'] }, // a substring
);
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('basic search', async () => {
await createTestEntities();
// Retrieving entity by full text search...
let resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: [
'search',
'Declaration of the thirteen united States of America',
],
}, // a substring
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
resultEntity = await nymph.getEntities(
{ class: TestModel },
{ type: '&', tag: 'test' },
{
type: '|',
search: [
['string', 'pickle'],
['search', 'Declaration of the thirteen united States of America'],
],
}, // inclusive test
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: ['search', 'July 4, 1776'],
}, // a string with a number
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
});
it('or search', async () => {
await createTestEntities();
// Retrieving entity by full text search...
let resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: ['search', 'Declaration or pickles'],
}, // a string with an or
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
});
it('series search', async () => {
await createTestEntities();
// Retrieving entity by full text search...
let resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: ['search', '"excited domestic insurrections"'],
}, // double quoted substring
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: ['search', "'exciting domestic insurrected'"],
}, // single quoted substring
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
});
it('negated search', async () => {
await createTestEntities();
// Retrieving entity by full text search...
let resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: ['search', '-pickle'],
}, // negated term
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
});
it('combined search', async () => {
await createTestEntities();
// Retrieving entity by full text search...
let resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: ['search', 'Declaration -pickle'],
}, // negated term with positive term
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: ['search', 'Declaration "General Congress"'],
}, // terms found in separate areas
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
});
it('wrong search', async () => {
await createTestEntities();
// Testing wrong search...
let resultEntity = await nymph.getEntities(
{ class: TestModel },
{ type: '&', search: ['search', 'pickles'] },
);
expect(testEntity.$inArray(resultEntity)).toEqual(false);
resultEntity = await nymph.getEntities(
{ class: TestModel },
{ type: '&', tag: 'pickle', search: ['search', 'Declaration'] },
);
expect(testEntity.$inArray(resultEntity)).toEqual(false);
resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '|',
search: [
['string', 'pickle'],
['search', 'Hawaii'],
],
},
);
expect(testEntity.$inArray(resultEntity)).toEqual(false);
});
it('search with only stop words', async () => {
await createTestEntities();
// Testing wrong search...
let resultEntity = await nymph.getEntities(
{ class: TestModel },
{ type: '&', search: ['search', 'i am'] },
);
expect(resultEntity).toEqual([]);
});
it('search must be case insensitive', async () => {
await createTestEntities();
// Retrieving entity by full text search...
const resultEntity = await nymph.getEntities(
{ class: TestModel },
{
type: '&',
tag: 'test',
search: [
'search',
'DECLARATION OF THE THIRTEEN UNITED STATES OF AMERICA',
],
}, // a substring
);
expect(testEntity.$inArray(resultEntity)).toEqual(true);
});
it('search and equal inclusive', async () => {
await createTestEntities();
// Retrieving entity by fts + equal inclusively...
const resultEntity = await nymph.getEntities(
{ class: TestModel },
{ type: '&', tag: 'test' },
{ type: '|', equal: ['string', 'pickles'], search: ['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).toBeGre