@e22m4u/js-repository
Version:
Реализация репозитория для работы с базами данных в Node.js
1,491 lines (1,439 loc) • 147 kB
JavaScript
import {expect} from 'chai';
import {format} from '@e22m4u/js-format';
import {MemoryAdapter} from './memory-adapter.js';
import {DataType} from '../../definition/index.js';
import {DatabaseSchema} from '../../database-schema.js';
import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../../definition/index.js';
describe('MemoryAdapter', function () {
describe('_getTableOrCreate', function () {
it('returns an existing table or creates a new', function () {
const dbs = new DatabaseSchema();
dbs.defineModel({name: 'model'});
const A = dbs.getService(MemoryAdapter);
const table = A._getTableOrCreate('model');
expect(table).to.be.instanceof(Map);
const sameTable = A._getTableOrCreate('model');
expect(table).to.be.eq(sameTable);
});
it('uses a model name to find a table, even a table name is specified', function () {
const dbs = new DatabaseSchema();
dbs.defineModel({
name: 'myModel',
tableName: 'myTable',
});
const A = dbs.getService(MemoryAdapter);
const table = A._getTableOrCreate('myModel');
expect(table).to.be.instanceof(Map);
const sameTable = A._getTableOrCreate('myModel');
expect(table).to.be.eq(sameTable);
});
it('stores a table by specified table name', function () {
const dbs = new DatabaseSchema();
dbs.defineModel({
name: 'myModel',
tableName: 'myTable',
});
const A = dbs.getService(MemoryAdapter);
const table = A._getTableOrCreate('myModel');
expect(table).to.be.instanceof(Map);
const sameTable = A._tables.get('myTable');
expect(table).to.be.eq(sameTable);
});
});
describe('_genNextIdValue', function () {
it('returns an unique number identifier', function () {
const dbs = new DatabaseSchema();
dbs.defineModel({name: 'model'});
const A = dbs.getService(MemoryAdapter);
const id1 = A._genNextIdValue('model', DEF_PK);
const id2 = A._genNextIdValue('model', DEF_PK);
const id3 = A._genNextIdValue('model', DEF_PK);
expect(id1).to.be.eq(1);
expect(id2).to.be.eq(2);
expect(id3).to.be.eq(3);
});
});
describe('create', function () {
it('skips existing values when generating a new identifier for a default primary key', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
});
const adapter = new MemoryAdapter(dbs.container, {});
const result1 = await adapter.create('model', {});
const result2 = await adapter.create('model', {});
const result3 = await adapter.create('model', {[DEF_PK]: 3});
const result4 = await adapter.create('model', {});
expect(result1).to.be.eql({[DEF_PK]: 1});
expect(result2).to.be.eql({[DEF_PK]: 2});
expect(result3).to.be.eql({[DEF_PK]: 3});
expect(result4).to.be.eql({[DEF_PK]: 4});
});
it('skips existing values when generating a new identifier for a specified primary key', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.NUMBER,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const result1 = await adapter.create('model', {});
const result2 = await adapter.create('model', {});
const result3 = await adapter.create('model', {myId: 3});
const result4 = await adapter.create('model', {});
expect(result1).to.be.eql({myId: 1});
expect(result2).to.be.eql({myId: 2});
expect(result3).to.be.eql({myId: 3});
expect(result4).to.be.eql({myId: 4});
});
it('generates a new identifier when a value of a primary key has not provided', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 'string', bar: 10};
const created = await adapter.create('model', input);
const idValue = created[DEF_PK];
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier when a value of a primary key is undefined', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {
[DEF_PK]: undefined,
foo: 'string',
bar: 10,
};
const created = await adapter.create('model', input);
const idValue = created[DEF_PK];
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier when a value of a primary key is null', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {
[DEF_PK]: null,
foo: 'string',
bar: 10,
};
const created = await adapter.create('model', input);
const idValue = created[DEF_PK];
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier when a value of a primary key is an empty string', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {
[DEF_PK]: '',
foo: 'string',
bar: 10,
};
const created = await adapter.create('model', input);
const idValue = created[DEF_PK];
expect(idValue).to.be.not.eq('');
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier when a value of a primary key is zero', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {
[DEF_PK]: 0,
foo: 'string',
bar: 10,
};
const created = await adapter.create('model', input);
const idValue = created[DEF_PK];
expect(idValue).to.be.not.eq(0);
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier for a primary key of a "number" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.NUMBER,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const result1 = await adapter.create('model', {});
const result2 = await adapter.create('model', {});
const result3 = await adapter.create('model', {});
expect(result1).to.be.eql({myId: 1});
expect(result2).to.be.eql({myId: 2});
expect(result3).to.be.eql({myId: 3});
});
it('generates a new identifier for a primary key of an "any" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.ANY,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const result1 = await adapter.create('model', {});
const result2 = await adapter.create('model', {});
const result3 = await adapter.create('model', {});
expect(result1).to.be.eql({myId: 1});
expect(result2).to.be.eql({myId: 2});
expect(result3).to.be.eql({myId: 3});
});
it('throws an error when generating a new value for a primary key of a "string" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.STRING,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.create('model', {foo: 'string', bar: 10});
await expect(promise).to.be.rejectedWith(
'The memory adapter able to generate only Number identifiers, ' +
'but the primary key "myId" of the model "model" is defined as String. ' +
'Do provide your own value for the "myId" property, or change the type ' +
'in the primary key definition to a Number that will be ' +
'generated automatically.',
);
});
it('throws an error when generating a new value for a primary key of a "boolean" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.BOOLEAN,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.create('model', {foo: 'string', bar: 10});
await expect(promise).to.be.rejectedWith(
'The memory adapter able to generate only Number identifiers, ' +
'but the primary key "myId" of the model "model" is defined as Boolean. ' +
'Do provide your own value for the "myId" property, or change the type ' +
'in the primary key definition to a Number that will be ' +
'generated automatically.',
);
});
it('throws an error when generating a new value for a primary key of an "array" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.ARRAY,
itemType: DataType.NUMBER,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.create('model', {});
await expect(promise).to.be.rejectedWith(
'The memory adapter able to generate only Number identifiers, ' +
'but the primary key "myId" of the model "model" is defined as Array. ' +
'Do provide your own value for the "myId" property, or change the type ' +
'in the primary key definition to a Number that will be ' +
'generated automatically.',
);
});
it('throws an error when generating a new value for a primary key of an "object" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.OBJECT,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.create('model', {});
await expect(promise).to.be.rejectedWith(
'The memory adapter able to generate only Number identifiers, ' +
'but the primary key "myId" of the model "model" is defined as Object. ' +
'Do provide your own value for the "myId" property, or change the type ' +
'in the primary key definition to a Number that will be ' +
'generated automatically.',
);
});
it('allows to specify an identifier value for a new item', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const idValue = 5;
const input = {foo: 'string', bar: 10};
const created = await adapter.create('model', {
[DEF_PK]: idValue,
...input,
});
expect(created).to.be.eql({[DEF_PK]: idValue, ...input});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, ...input});
});
it('throws an error if a given identifier value already exists', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {foo: 'string'});
const promise = adapter.create('model', created);
await expect(promise).to.be.rejectedWith(
format(
'The value 1 of the primary key %v already exists in the model "model".',
DEF_PK,
),
);
});
it('sets default values if they are not provided for a new item', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
default: 10,
},
bar: {
type: DataType.STRING,
default: 'string',
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {});
const idValue = created[DEF_PK];
const defaults = {foo: 10, bar: 'string'};
expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
});
it('sets default values for properties provided with an undefined value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
default: 1,
},
bar: {
type: DataType.NUMBER,
default: 2,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {foo: undefined});
const idValue = created[DEF_PK];
const defaults = {foo: 1, bar: 2};
expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
});
it('sets default values for properties provided with a null value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
default: 1,
},
bar: {
type: DataType.NUMBER,
default: 2,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {foo: null});
const idValue = created[DEF_PK];
const defaults = {foo: 1, bar: 2};
expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
});
it('uses a specified column name for a primary key', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
primaryKey: true,
columnName: 'bar',
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {});
expect(created).to.be.eql({foo: created.foo});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(created.foo);
expect(tableData).to.be.eql({bar: created.foo});
});
it('uses a specified column name for a regular property', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
columnName: 'bar',
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {foo: 10});
const idValue = created[DEF_PK];
expect(created).to.be.eql({[DEF_PK]: idValue, foo: 10});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, bar: 10});
});
it('uses a specified column name for a regular property with a default value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
columnName: 'bar',
default: 10,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {});
const idValue = created[DEF_PK];
expect(created).to.be.eql({[DEF_PK]: idValue, foo: 10});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, bar: 10});
});
it('uses a short form of a fields clause to filter a return value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 'string', bar: 10};
const filter = {fields: 'foo'};
const result = await adapter.create('model', input, filter);
expect(result).to.be.eql({[DEF_PK]: result[DEF_PK], foo: input.foo});
});
it('uses a full form of a fields clause to filter a return value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
baz: DataType.BOOLEAN,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 'string', bar: 10, baz: true};
const filter = {fields: ['foo', 'bar']};
const result = await adapter.create('model', input, filter);
expect(result).to.be.eql({
[DEF_PK]: result[DEF_PK],
foo: input.foo,
bar: input.bar,
});
});
it('a fields clause uses property names instead of column names', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.STRING,
columnName: 'fooCol',
},
bar: {
type: DataType.NUMBER,
columnName: 'barCol',
},
baz: {
type: DataType.BOOLEAN,
columnName: 'bazCol',
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 'string', bar: 10, baz: true};
const filter = {fields: ['foo', 'bar']};
const result = await adapter.create('model', input, filter);
expect(result).to.be.eql({
[DEF_PK]: result[DEF_PK],
foo: input.foo,
bar: input.bar,
});
});
});
describe('replaceById', function () {
it('removes properties when replacing an item by a given identifier', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.NUMBER,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 1, bar: 2};
const created = await adapter.create('model', input);
const idValue = created[DEF_PK];
expect(created).to.be.eql({[DEF_PK]: idValue, ...input});
const replaced = await adapter.replaceById('model', idValue, {foo: 2});
expect(replaced).to.be.eql({[DEF_PK]: idValue, foo: 2});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, foo: 2});
});
it('ignores identifier value in a given data in case of a default primary key', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
});
const adapter = new MemoryAdapter(dbs.container, {});
const createdModelData = await adapter.create('model', {[DEF_PK]: 10});
expect(createdModelData).to.be.eql({[DEF_PK]: 10});
const table = adapter._getTableOrCreate('model');
const createdTableData = table.get(10);
expect(createdTableData).to.be.eql({[DEF_PK]: 10});
const replacedModelData = await adapter.replaceById('model', 10, {
[DEF_PK]: 20,
});
expect(replacedModelData).to.be.eql({[DEF_PK]: 10});
const replacedTableData = table.get(10);
expect(replacedTableData).to.be.eql({[DEF_PK]: 10});
});
it('ignores identifier value in a given data in case of a specified primary key', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.NUMBER,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const createdModelData = await adapter.create('model', {myId: 10});
expect(createdModelData).to.be.eql({myId: 10});
const table = adapter._getTableOrCreate('model');
const createdTableData = table.get(10);
expect(createdTableData).to.be.eql({myId: 10});
const replacedModelData = await adapter.replaceById('model', 10, {
myId: 20,
});
expect(replacedModelData).to.be.eql({myId: 10});
const replacedTableData = table.get(10);
expect(replacedTableData).to.be.eql({myId: 10});
});
it('sets a default values for removed properties when replacing an item', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
default: 1,
},
bar: {
type: DataType.NUMBER,
default: 2,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {});
const idValue = created[DEF_PK];
const defaults = {foo: 1, bar: 2};
expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
const replacing = {foo: 2};
const replaced = await adapter.replaceById('model', idValue, replacing);
expect(replaced).to.be.eql({
[DEF_PK]: idValue,
...defaults,
...replacing,
});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({
[DEF_PK]: idValue,
...defaults,
...replacing,
});
});
it('sets a default values for replaced properties with an undefined value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
default: 1,
},
bar: {
type: DataType.NUMBER,
default: 2,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {});
const idValue = created[DEF_PK];
const defaults = {foo: 1, bar: 2};
expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
const replaced = await adapter.replaceById('model', idValue, {
foo: undefined,
});
expect(replaced).to.be.eql({[DEF_PK]: idValue, ...defaults});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
});
it('sets a default values for replaced properties with a null value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
default: 1,
},
bar: {
type: DataType.NUMBER,
default: 2,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const created = await adapter.create('model', {});
const idValue = created[DEF_PK];
const defaults = {foo: 1, bar: 2};
expect(created).to.be.eql({[DEF_PK]: idValue, ...defaults});
const replaced = await adapter.replaceById('model', idValue, {
foo: null,
});
expect(replaced).to.be.eql({[DEF_PK]: idValue, ...defaults});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({[DEF_PK]: idValue, ...defaults});
});
it('throws an error if a given identifier does not exist', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.NUMBER,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.replaceById('model', 1, {foo: 2});
await expect(promise).to.be.rejectedWith(
format(
'The value 1 of the primary key %v does not exist in the model "model".',
DEF_PK,
),
);
});
it('uses a specified column name for a primary key', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
primaryKey: true,
columnName: 'qux',
},
bar: DataType.NUMBER,
baz: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {bar: 1, baz: 2};
const createdModelData = await adapter.create('model', input);
expect(createdModelData).to.be.eql({
foo: createdModelData.foo,
...input,
});
const table = adapter._getTableOrCreate('model');
const createdTableData = table.get(createdModelData.foo);
expect(createdTableData).to.be.eql({
qux: createdModelData.foo,
...input,
});
const replacing = {bar: 2};
const replacedModelData = await adapter.replaceById(
'model',
createdModelData.foo,
replacing,
);
expect(replacedModelData).to.be.eql({
foo: createdModelData.foo,
...replacing,
});
const replacedTableData = table.get(createdModelData.foo);
expect(replacedTableData).to.be.eql({
qux: createdModelData.foo,
...replacing,
});
});
it('uses a specified column name for a regular property', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
columnName: 'baz',
},
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 1, bar: 2};
const createdModelData = await adapter.create('model', input);
const idValue = createdModelData[DEF_PK];
expect(createdModelData).to.be.eql({[DEF_PK]: idValue, ...input});
const table = adapter._getTableOrCreate('model');
const createdTableData = table.get(idValue);
expect(createdTableData).to.be.eql({
[DEF_PK]: idValue,
baz: input.foo,
bar: input.bar,
});
const replacing = {foo: 2};
const replacedModelData = await adapter.replaceById(
'model',
idValue,
replacing,
);
expect(replacedModelData).to.be.eql({[DEF_PK]: idValue, ...replacing});
const replacedTableData = table.get(idValue);
expect(replacedTableData).to.be.eql({
[DEF_PK]: idValue,
baz: replacing.foo,
});
});
it('uses a specified column name for a regular property with a default value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.NUMBER,
columnName: 'baz',
default: 1,
},
bar: {
type: DataType.NUMBER,
default: 2,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const createdModelData = await adapter.create('model', {});
const idValue = createdModelData[DEF_PK];
const defaults = {foo: 1, bar: 2};
expect(createdModelData).to.be.eql({[DEF_PK]: idValue, ...defaults});
const table = adapter._getTableOrCreate('model');
const createdTableData = table.get(idValue);
expect(createdTableData).to.be.eql({
[DEF_PK]: idValue,
baz: defaults.foo,
bar: defaults.bar,
});
const replacing = {foo: 2};
const replacedModelData = await adapter.replaceById(
'model',
idValue,
replacing,
);
expect(replacedModelData).to.be.eql({
[DEF_PK]: idValue,
foo: replacing.foo,
bar: defaults.bar,
});
const replacedTableData = table.get(idValue);
expect(replacedTableData).to.be.eql({
[DEF_PK]: idValue,
baz: replacing.foo,
bar: defaults.bar,
});
});
it('allows to specify a short form of a fields clause to filter a return value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 'string', bar: 10};
const createdModelData = await adapter.create('model', input);
const idValue = createdModelData[DEF_PK];
expect(createdModelData).to.be.eql({[DEF_PK]: idValue, ...input});
const table = adapter._getTableOrCreate('model');
const createdTableData = table.get(idValue);
expect(createdTableData).to.be.eql({[DEF_PK]: idValue, ...input});
const replacedModelData = await adapter.replaceById(
'model',
idValue,
input,
{fields: 'foo'},
);
expect(replacedModelData).to.be.eql({[DEF_PK]: idValue, foo: input.foo});
const replacedTableData = table.get(idValue);
expect(replacedTableData).to.be.eql({[DEF_PK]: idValue, ...input});
});
it('allows to specify a full form of a fields clause to filter a return value', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
baz: DataType.BOOLEAN,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 'string', bar: 10, baz: true};
const createdModelData = await adapter.create('model', input);
const idValue = createdModelData[DEF_PK];
expect(createdModelData).to.be.eql({[DEF_PK]: idValue, ...input});
const table = adapter._getTableOrCreate('model');
const createdTableData = table.get(idValue);
expect(createdTableData).to.be.eql({[DEF_PK]: idValue, ...input});
const replacedModelData = await adapter.replaceById(
'model',
idValue,
input,
{fields: ['foo', 'bar']},
);
expect(replacedModelData).to.be.eql({
[DEF_PK]: idValue,
foo: input.foo,
bar: input.bar,
});
const replacedTableData = table.get(idValue);
expect(replacedTableData).to.be.eql({[DEF_PK]: idValue, ...input});
});
it('a fields clause uses property names instead of column names', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: {
type: DataType.STRING,
columnName: 'fooCol',
},
bar: {
type: DataType.NUMBER,
columnName: 'barCol',
},
baz: {
type: DataType.BOOLEAN,
columnName: 'bazCol',
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 'string', bar: 10, baz: true};
const createdModelData = await adapter.create('model', input);
const idValue = createdModelData[DEF_PK];
expect(createdModelData).to.be.eql({[DEF_PK]: idValue, ...input});
const table = adapter._getTableOrCreate('model');
const createdTableData = table.get(idValue);
expect(createdTableData).to.be.eql({
[DEF_PK]: idValue,
fooCol: input.foo,
barCol: input.bar,
bazCol: input.baz,
});
const replacedModelData = await adapter.replaceById(
'model',
idValue,
input,
{fields: ['foo', 'bar']},
);
expect(replacedModelData).to.be.eql({
[DEF_PK]: idValue,
foo: input.foo,
bar: input.bar,
});
const replacedTableData = table.get(idValue);
expect(replacedTableData).to.be.eql({
[DEF_PK]: idValue,
fooCol: input.foo,
barCol: input.bar,
bazCol: input.baz,
});
});
});
describe('replaceOrCreate', function () {
it('generates a new identifier when a value of a primary key has not provided', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {foo: 'string', bar: 10};
const created = await adapter.replaceOrCreate('model', input);
const idValue = created[DEF_PK];
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier when a value of a primary key is undefined', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {
[DEF_PK]: undefined,
foo: 'string',
bar: 10,
};
const created = await adapter.replaceOrCreate('model', input);
const idValue = created[DEF_PK];
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier when a value of a primary key is null', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {
[DEF_PK]: null,
foo: 'string',
bar: 10,
};
const created = await adapter.replaceOrCreate('model', input);
const idValue = created[DEF_PK];
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier when a value of a primary key is an empty string', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {
[DEF_PK]: '',
foo: 'string',
bar: 10,
};
const created = await adapter.replaceOrCreate('model', input);
const idValue = created[DEF_PK];
expect(idValue).to.be.not.eq('');
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier when a value of a primary key is zero', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
foo: DataType.STRING,
bar: DataType.NUMBER,
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const input = {
[DEF_PK]: 0,
foo: 'string',
bar: 10,
};
const created = await adapter.replaceOrCreate('model', input);
const idValue = created[DEF_PK];
expect(idValue).to.be.not.eq(0);
expect(created).to.be.eql({...input, [DEF_PK]: idValue});
const table = adapter._getTableOrCreate('model');
const tableData = table.get(idValue);
expect(tableData).to.be.eql({...input, [DEF_PK]: idValue});
});
it('generates a new identifier for a primary key of a "number" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.NUMBER,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const result1 = await adapter.replaceOrCreate('model', {});
const result2 = await adapter.replaceOrCreate('model', {});
const result3 = await adapter.replaceOrCreate('model', {});
expect(result1).to.be.eql({myId: 1});
expect(result2).to.be.eql({myId: 2});
expect(result3).to.be.eql({myId: 3});
});
it('generates a new identifier for a primary key of an "any" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.ANY,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const result1 = await adapter.replaceOrCreate('model', {});
const result2 = await adapter.replaceOrCreate('model', {});
const result3 = await adapter.replaceOrCreate('model', {});
expect(result1).to.be.eql({myId: 1});
expect(result2).to.be.eql({myId: 2});
expect(result3).to.be.eql({myId: 3});
});
it('throws an error when generating a new value for a primary key of a "string" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.STRING,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.replaceOrCreate('model', {
foo: 'string',
bar: 10,
});
await expect(promise).to.be.rejectedWith(
'The memory adapter able to generate only Number identifiers, ' +
'but the primary key "myId" of the model "model" is defined as String. ' +
'Do provide your own value for the "myId" property, or change the type ' +
'in the primary key definition to a Number that will be ' +
'generated automatically.',
);
});
it('throws an error when generating a new value for a primary key of a "boolean" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.BOOLEAN,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.replaceOrCreate('model', {
foo: 'string',
bar: 10,
});
await expect(promise).to.be.rejectedWith(
'The memory adapter able to generate only Number identifiers, ' +
'but the primary key "myId" of the model "model" is defined as Boolean. ' +
'Do provide your own value for the "myId" property, or change the type ' +
'in the primary key definition to a Number that will be ' +
'generated automatically.',
);
});
it('throws an error when generating a new value for a primary key of an "array" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.ARRAY,
itemType: DataType.NUMBER,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.replaceOrCreate('model', {});
await expect(promise).to.be.rejectedWith(
'The memory adapter able to generate only Number identifiers, ' +
'but the primary key "myId" of the model "model" is defined as Array. ' +
'Do provide your own value for the "myId" property, or change the type ' +
'in the primary key definition to a Number that will be ' +
'generated automatically.',
);
});
it('throws an error when generating a new value for a primary key of an "object" type', async function () {
const dbs = new DatabaseSchema();
dbs.defineDatasource({
name: 'memory',
adapter: 'memory',
});
dbs.defineModel({
name: 'model',
datasource: 'memory',
properties: {
myId: {
type: DataType.OBJECT,
primaryKey: true,
},
},
});
const adapter = new MemoryAdapter(dbs.container, {});
const promise = adapter.replaceOrCreate('model', {});
await expect(promise).to.be.rejectedWith(
'The memory adapter able to generate only Number identifiers, ' +
'but the primary key