UNPKG

@e22m4u/js-repository

Version:

Реализация репозитория для работы с базами данных в Node.js

647 lines (622 loc) 22.6 kB
import {expect} from 'chai'; import {format} from '@e22m4u/js-format'; import {DataType} from './properties/index.js'; import {DatabaseSchema} from '../../database-schema.js'; import {DefinitionRegistry} from '../definition-registry.js'; import {ModelDataTransformer} from './model-data-transformer.js'; import {PropertyTransformerRegistry} from './properties/index.js'; describe('ModelDataTransformer', function () { describe('transform', function () { it('throws an error if the given model name is not defined', function () { const dbs = new DatabaseSchema(); const T = dbs.getService(ModelDataTransformer); const throwable = () => T.transform('model', {}); expect(throwable).to.throw('The model "model" is not defined.'); }); it('throws an error if the given model data is not a pure object', function () { const dbs = new DatabaseSchema(); const T = dbs.getService(ModelDataTransformer); const throwable = v => () => T.transform('model', v); const error = v => format( 'The data of the model "model" should be an Object, but %s given.', v, ); expect(throwable('str')).to.throw(error('"str"')); expect(throwable('')).to.throw(error('""')); expect(throwable(10)).to.throw(error('10')); expect(throwable(0)).to.throw(error('0')); expect(throwable(true)).to.throw(error('true')); expect(throwable(false)).to.throw(error('false')); expect(throwable(undefined)).to.throw(error('undefined')); expect(throwable(null)).to.throw(error('null')); expect(throwable([])).to.throw(error('Array')); expect(throwable(new Date())).to.throw(error('Date')); }); it('does nothing with the given model if no transformers are set', function () { const dbs = new DatabaseSchema(); dbs.defineModel({ name: 'model', properties: { foo: DataType.STRING, bar: { type: DataType.STRING, default: 'test', }, }, }); const T = dbs.getService(ModelDataTransformer); const modelData = {baz: 'qux'}; const res = T.transform('model', modelData); expect(res).to.be.eql(modelData); }); describe('the option "transform" with a string value', function () { it('transforms the property value by its transformer', function () { const dbs = new DatabaseSchema(); const myTransformer = value => String(value); dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: 'myTransformer', }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {foo: 10}); expect(res).to.be.eql({foo: '10'}); }); it('passes specific arguments to the transformer function', function () { const dbs = new DatabaseSchema(); const myTransformer = (value, options, context) => { expect(value).to.be.eq('input'); expect(options).to.be.undefined; expect(context).to.be.eql({ transformerName: 'myTransformer', modelName: 'model', propName: 'foo', }); return 'transformed'; }; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: 'myTransformer', }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {foo: 'input'}); expect(res).to.be.eql({foo: 'transformed'}); }); it('does not transform a property value if it is not provided', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: 'myTransformer', }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {}); expect(res).to.be.eql({}); }); it('does not transform undefined and null values', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: 'myTransformer', }, }, }); const T = dbs.getService(ModelDataTransformer); const res1 = T.transform('model', {foo: undefined}); const res2 = T.transform('model', {foo: null}); expect(res1).to.be.eql({foo: undefined}); expect(res2).to.be.eql({foo: null}); }); it('the parameter "isPartial" prevents to transform values of not provided properties', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: 'myTransformer', }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {}, true); expect(res).to.be.eql({}); }); it('transforms the property value by its asynchronous transformer', async function () { const dbs = new DatabaseSchema(); const myTransformer1 = (value, options) => { expect(options).to.be.undefined; return Promise.resolve(`${value}2`); }; const myTransformer2 = (value, options) => { expect(options).to.be.undefined; return Promise.resolve(`${value}3`); }; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer1', myTransformer1) .addTransformer('myTransformer2', myTransformer2); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: 'myTransformer1', }, bar: { type: DataType.STRING, transform: 'myTransformer2', }, }, }); const T = dbs.getService(ModelDataTransformer); const promise = T.transform('model', {foo: '1', bar: '2'}); expect(promise).to.be.instanceof(Promise); const res = await promise; expect(res).to.be.eql({foo: '12', bar: '23'}); }); }); describe('the option "transform" with an array value', function () { it('transforms given properties by their transformers', function () { const dbs = new DatabaseSchema(); const myTransformer = value => String(value); dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: ['myTransformer'], }, bar: { type: DataType.ANY, transform: ['myTransformer'], }, baz: { type: DataType.ANY, transform: ['myTransformer'], }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {foo: 1, bar: 2, baz: 3}); expect(res).to.be.eql({foo: '1', bar: '2', baz: '3'}); }); it('transforms the property value by its transformers in specified order', function () { const dbs = new DatabaseSchema(); const order = []; const myTransformer1 = value => { order.push('myTransformer1'); return value + '1'; }; const myTransformer2 = value => { order.push('myTransformer2'); return value + '2'; }; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer1', myTransformer1) .addTransformer('myTransformer2', myTransformer2); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: ['myTransformer1', 'myTransformer2'], }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {foo: 'value'}); expect(res).to.be.eql({foo: 'value12'}); expect(order).to.be.eql(['myTransformer1', 'myTransformer2']); }); it('passes specific arguments to the transformer function', function () { const dbs = new DatabaseSchema(); const myTransformer = (value, options, context) => { expect(value).to.be.eq('input'); expect(options).to.be.undefined; expect(context).to.be.eql({ transformerName: 'myTransformer', modelName: 'model', propName: 'foo', }); return 'transformed'; }; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: ['myTransformer'], }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {foo: 'input'}); expect(res).to.be.eql({foo: 'transformed'}); }); it('does not transform a property value if it is not provided', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: ['myTransformer'], }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {}); expect(res).to.be.eql({}); }); it('transforms undefined and null values', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: ['myTransformer'], }, }, }); const T = dbs.getService(ModelDataTransformer); const res1 = T.transform('model', {foo: undefined}); const res2 = T.transform('model', {foo: null}); expect(res1).to.be.eql({foo: undefined}); expect(res2).to.be.eql({foo: null}); }); it('the parameter "isPartial" prevents to transform values of not provided properties', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: ['myTransformer'], }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {}, true); expect(res).to.be.eql({}); }); it('transforms the property value by its asynchronous transformers', async function () { const dbs = new DatabaseSchema(); const myTransformer1 = (value, options) => { expect(options).to.be.undefined; return Promise.resolve(`${value}2`); }; const myTransformer2 = (value, options) => { expect(options).to.be.undefined; return Promise.resolve(`${value}3`); }; const myTransformer3 = (value, options) => { expect(options).to.be.undefined; return Promise.resolve(`${value}4`); }; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer1', myTransformer1) .addTransformer('myTransformer2', myTransformer2) .addTransformer('myTransformer3', myTransformer3); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: ['myTransformer1', 'myTransformer2'], }, bar: { type: DataType.STRING, transform: ['myTransformer2', 'myTransformer3'], }, }, }); const T = dbs.getService(ModelDataTransformer); const promise = T.transform('model', {foo: '1', bar: '2'}); expect(promise).to.be.instanceof(Promise); const res = await promise; expect(res).to.be.eql({foo: '123', bar: '234'}); }); }); describe('the option "transform" with an object value', function () { it('transforms given properties by their transformers', function () { const dbs = new DatabaseSchema(); const myTransformer = value => String(value); dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: {myTransformer: true}, }, bar: { type: DataType.ANY, transform: {myTransformer: true}, }, baz: { type: DataType.ANY, transform: {myTransformer: true}, }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {foo: 1, bar: 2, baz: 3}); expect(res).to.be.eql({foo: '1', bar: '2', baz: '3'}); }); it('transforms the property value by its transformers in specified order', function () { const dbs = new DatabaseSchema(); const order = []; const myTransformer1 = value => { order.push('myTransformer1'); return value + '1'; }; const myTransformer2 = value => { order.push('myTransformer2'); return value + '2'; }; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer1', myTransformer1) .addTransformer('myTransformer2', myTransformer2); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: { myTransformer1: true, myTransformer2: true, }, }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {foo: 'value'}); expect(res).to.be.eql({foo: 'value12'}); expect(order).to.be.eql(['myTransformer1', 'myTransformer2']); }); it('passes specific arguments to the transformer function', function () { const dbs = new DatabaseSchema(); const myTransformer = (value, options, context) => { expect(value).to.be.eq('input'); expect(options).to.be.eql({ option1: 'value1', option2: 'value2', }); expect(context).to.be.eql({ transformerName: 'myTransformer', modelName: 'model', propName: 'foo', }); return 'transformed'; }; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: { myTransformer: { option1: 'value1', option2: 'value2', }, }, }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {foo: 'input'}); expect(res).to.be.eql({foo: 'transformed'}); }); it('does not transform a property value if it is not provided', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: { myTransformer: true, }, }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {}); expect(res).to.be.eql({}); }); it('transforms undefined and null values', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: { myTransformer: true, }, }, }, }); const T = dbs.getService(ModelDataTransformer); const res1 = T.transform('model', {foo: undefined}); const res2 = T.transform('model', {foo: null}); expect(res1).to.be.eql({foo: undefined}); expect(res2).to.be.eql({foo: null}); }); it('the parameter "isPartial" prevents to transform values of not provided properties', function () { const dbs = new DatabaseSchema(); const myTransformer = () => 'transformed'; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', myTransformer); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: { myTransformer: true, }, }, }, }); const T = dbs.getService(ModelDataTransformer); const res = T.transform('model', {}, true); expect(res).to.be.eql({}); }); it('transforms the property value by its asynchronous transformers', async function () { const dbs = new DatabaseSchema(); const myTransformer1 = (value, options) => { expect(options).to.be.eq('foo'); return Promise.resolve(`${value}2`); }; const myTransformer2 = (value, options) => { expect(options).to.be.eq('bar'); return Promise.resolve(`${value}3`); }; const myTransformer3 = (value, options) => { expect(options).to.be.eq('baz'); return Promise.resolve(`${value}4`); }; dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer1', myTransformer1) .addTransformer('myTransformer2', myTransformer2) .addTransformer('myTransformer3', myTransformer3); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.STRING, transform: { myTransformer1: 'foo', myTransformer2: 'bar', }, }, bar: { type: DataType.STRING, transform: { myTransformer2: 'bar', myTransformer3: 'baz', }, }, }, }); const T = dbs.getService(ModelDataTransformer); const promise = T.transform('model', {foo: '1', bar: '2'}); expect(promise).to.be.instanceof(Promise); const res = await promise; expect(res).to.be.eql({foo: '123', bar: '234'}); }); }); it('the option "transform" requires a non-empty String, an Array or an Object', function () { const dbs = new DatabaseSchema(); dbs .getService(PropertyTransformerRegistry) .addTransformer('myTransformer', () => 'transformed'); dbs.defineModel({ name: 'model', properties: { foo: { type: DataType.ANY, transform: undefined, }, }, }); const T = dbs.getService(ModelDataTransformer); const throwable = v => () => { const models = dbs.getService(DefinitionRegistry)['_models']; models.model.properties.foo.transform = v; T.transform('model', {foo: 'bar'}); }; const error = v => format( 'The provided option "transform" of the property "foo" in the model "model" ' + 'should be a non-empty String, an Array of String or an Object, ' + 'but %s given.', v, ); expect(throwable('')).to.throw(error('""')); expect(throwable(10)).to.throw(error('10')); expect(throwable(0)).to.throw(error('0')); expect(throwable(true)).to.throw(error('true')); expect(throwable(false)).to.throw(error('false')); throwable('myTransformer')(); throwable(['myTransformer'])(); throwable([])(); throwable({myTransformer: true})(); throwable({})(); }); }); });