|
|
@@ -0,0 +1,172 @@
|
|
|
+import {expect} from 'chai';
|
|
|
+import {DataProjectionService} from './data-projection-service.js';
|
|
|
+import {ProjectionSchemaRegistry} from './projection-schema-registry.js';
|
|
|
+
|
|
|
+describe('DataProjectionService', function () {
|
|
|
+ describe('defineProjection', function () {
|
|
|
+ it('should validate the given definition', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const throwable = () => dps.defineProjection({});
|
|
|
+ expect(throwable).to.throw(
|
|
|
+ 'Definition option "name" must be a non-empty String, ' +
|
|
|
+ 'but undefined was given.',
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should register the given definition', function () {
|
|
|
+ const def = {name: 'mySchema', schema: {}};
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ dps.defineProjection(def);
|
|
|
+ const registry = dps.getService(ProjectionSchemaRegistry);
|
|
|
+ const res = registry.getDefinition(def.name);
|
|
|
+ expect(res).to.be.eql(def);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should throw an error if the schema name is already registered', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const def = {name: 'mySchema', schema: {}};
|
|
|
+ dps.defineProjection(def);
|
|
|
+ const throwable = () => dps.defineProjection(def);
|
|
|
+ expect(throwable).to.throw(
|
|
|
+ 'Projection schema "mySchema" is already registered.',
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should return the current instance', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const res = dps.defineProjection({name: 'mySchema', schema: {}});
|
|
|
+ expect(res).to.be.eq(dps);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('projectData', function () {
|
|
|
+ it('should project the data object by the given schema', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const res = dps.projectData({foo: true, bar: false}, {foo: 10, bar: 20});
|
|
|
+ expect(res).to.be.eql({foo: 10});
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should project the data object by the schema name', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ dps.defineProjection({name: 'mySchema', schema: {foo: true, bar: false}});
|
|
|
+ const res = dps.projectData('mySchema', {foo: 10, bar: 20, baz: 30});
|
|
|
+ expect(res).to.be.eql({foo: 10, baz: 30});
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should exclude properties without rules in the strict mode', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ dps.defineProjection({name: 'mySchema', schema: {foo: true, bar: false}});
|
|
|
+ const res = dps.projectData(
|
|
|
+ 'mySchema',
|
|
|
+ {foo: 10, bar: 20, baz: 30},
|
|
|
+ {strict: true},
|
|
|
+ );
|
|
|
+ expect(res).to.be.eql({foo: 10});
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should allow override the "nameResolver" option', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const schemaName = 'mySchema';
|
|
|
+ let invoked = 0;
|
|
|
+ const nameResolver = name => {
|
|
|
+ invoked++;
|
|
|
+ expect(name).to.be.eq(schemaName);
|
|
|
+ return {foo: true, bar: false};
|
|
|
+ };
|
|
|
+ const res = dps.projectData(
|
|
|
+ 'mySchema',
|
|
|
+ {foo: 10, bar: 20},
|
|
|
+ {nameResolver},
|
|
|
+ );
|
|
|
+ expect(res).to.be.eql({foo: 10});
|
|
|
+ expect(invoked).to.be.eq(1);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should pass the service container to the schema factory', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ let invoked = 0;
|
|
|
+ const factory = container => {
|
|
|
+ invoked++;
|
|
|
+ expect(container).to.be.eq(dps.container);
|
|
|
+ return {foo: true, bar: false};
|
|
|
+ };
|
|
|
+ const res = dps.projectData(factory, {foo: 10, bar: 20});
|
|
|
+ expect(res).to.be.eql({foo: 10});
|
|
|
+ expect(invoked).to.be.eq(1);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should allow override the "factoryArgs" option', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ let invoked = 0;
|
|
|
+ const factoryArgs = [1, 2, 3];
|
|
|
+ const factory = (...args) => {
|
|
|
+ invoked++;
|
|
|
+ expect(args).to.be.eql(factoryArgs);
|
|
|
+ return {foo: true, bar: false};
|
|
|
+ };
|
|
|
+ const res = dps.projectData(factory, {foo: 10, bar: 20}, {factoryArgs});
|
|
|
+ expect(res).to.be.eql({foo: 10});
|
|
|
+ expect(invoked).to.be.eq(1);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('projectInput', function () {
|
|
|
+ it('should invoke the "projectData" method with the "input" scope and return its result', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const schema = {foo: true, bar: false};
|
|
|
+ const data = {foo: 10, bar: 20};
|
|
|
+ const options = {extra: true};
|
|
|
+ const result = {foo: 10};
|
|
|
+ let invoked = 0;
|
|
|
+ dps.projectData = (...args) => {
|
|
|
+ expect(args).to.be.eql([schema, data, {extra: true, scope: 'input'}]);
|
|
|
+ invoked++;
|
|
|
+ return result;
|
|
|
+ };
|
|
|
+ const res = dps.projectInput(schema, data, options);
|
|
|
+ expect(res).to.be.eq(result);
|
|
|
+ expect(invoked).to.be.eq(1);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should project the given object with the "input" scope', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const schema = {
|
|
|
+ foo: {select: false, scopes: {input: true}},
|
|
|
+ bar: {select: true, scopes: {input: false}},
|
|
|
+ };
|
|
|
+ const data = {foo: 10, bar: 20};
|
|
|
+ const res = dps.projectInput(schema, data);
|
|
|
+ expect(res).to.be.eql({foo: 10});
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('projectOutput', function () {
|
|
|
+ it('should invoke the "projectData" method with the "output" scope and return its result', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const schema = {foo: true, bar: false};
|
|
|
+ const data = {foo: 10, bar: 20};
|
|
|
+ const options = {extra: true};
|
|
|
+ const result = {foo: 10};
|
|
|
+ let invoked = 0;
|
|
|
+ dps.projectData = (...args) => {
|
|
|
+ expect(args).to.be.eql([schema, data, {extra: true, scope: 'output'}]);
|
|
|
+ invoked++;
|
|
|
+ return result;
|
|
|
+ };
|
|
|
+ const res = dps.projectOutput(schema, data, options);
|
|
|
+ expect(res).to.be.eq(result);
|
|
|
+ expect(invoked).to.be.eq(1);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should project the given object with the "output" scope', function () {
|
|
|
+ const dps = new DataProjectionService();
|
|
|
+ const schema = {
|
|
|
+ foo: {select: false, scopes: {output: true}},
|
|
|
+ bar: {select: true, scopes: {output: false}},
|
|
|
+ };
|
|
|
+ const data = {foo: 10, bar: 20};
|
|
|
+ const res = dps.projectOutput(schema, data);
|
|
|
+ expect(res).to.be.eql({foo: 10});
|
|
|
+ });
|
|
|
+ });
|
|
|
+});
|