cqrs-swissknife
Advanced tools
Comparing version 0.4.3 to 0.4.4
'use strict'; | ||
const { asyncParamApiCallback, noop, nameRetriever } = require('../../utils'); | ||
const { | ||
asyncParamApiCallback, | ||
noop, | ||
nameRetriever, | ||
toFlatArray, | ||
} = require('../../utils'); | ||
@@ -18,5 +23,5 @@ module.exports = ({ eventFullName, reaction, identifier }, { ViewBuilder, PreEventExtender, EventExtender }, customApiBuilder = noop) => { | ||
if (!Array.isArray(reaction)) | ||
reaction = [reaction]; | ||
reaction = toFlatArray(reaction); | ||
reaction.forEach((item) => { | ||
@@ -23,0 +28,0 @@ // event handler |
@@ -6,2 +6,4 @@ 'use strict'; | ||
const { firstFilenamePart } = require('../utils'); | ||
// const denormalizerBuilder = require('./denormalizerBuilder'); | ||
@@ -19,5 +21,12 @@ | ||
const basename = firstFilenamePart(collectionFile); | ||
collections[path.basename(collectionName, '.js')] = { | ||
if (collections[basename]) | ||
throw new Error(`Duplicate readmodel: [${basename}] in: ${collectionFile} and ${collections[basename].path}.`); | ||
const { schema } = require(collectionFile); // eslint-disable-line | ||
collections[basename] = { | ||
path: collectionFile, | ||
schema, | ||
}; | ||
@@ -24,0 +33,0 @@ }); |
@@ -8,2 +8,9 @@ 'use strict'; | ||
const deferredEventsSymbol = Symbol('aggregate:deferedEvents'); | ||
const commandSymbol = Symbol('aggregate:command'); | ||
const modeSymbol = Symbol('aggregate:modeSymbol'); | ||
const HANDLER_MORE = 'handler'; | ||
const ASYNC_HANDLER_MODE = 'async_handle'; | ||
// direct copy from : https://github.com/adrai/node-cqrs-domain/blob/9b17c73853ec59d451d3101492cb00b16e1ec9e3/lib/definitions/aggregate.js#L70 | ||
@@ -79,10 +86,22 @@ const generateEvent = (aggregate, model, eventEnricher, cmd, name, payload, metadata, version = 0) => { | ||
const generateAggregateApi = (aggregate, eventEnricher = valueop) => { | ||
const AggregateApi = function AggregateApi(aggregateModel, command) { | ||
const AggregateApi = function AggregateApi(aggregateModel, command, mode = HANDLER_MORE) { | ||
this._aggregateModel = aggregateModel; | ||
this._command = command; | ||
this.id = this._aggregateModel.id; | ||
this[modeSymbol] = mode; | ||
this[commandSymbol] = command; | ||
this.apply.__self = this; | ||
if (mode === ASYNC_HANDLER_MODE && !this._aggregateModel[deferredEventsSymbol]) { | ||
this._aggregateModel[deferredEventsSymbol] = this._aggregateModel[deferredEventsSymbol] || []; | ||
} else if (mode === HANDLER_MORE && this._aggregateModel[deferredEventsSymbol]) { | ||
this._aggregateModel[deferredEventsSymbol].forEach(params => this.apply(...params)); | ||
this._aggregateModel[deferredEventsSymbol] = []; | ||
} | ||
}; | ||
AggregateApi.prototype.get = function get(attr) { | ||
if (!attr) | ||
return this._aggregateModel.attributes; | ||
return this._aggregateModel.get(attr); | ||
@@ -92,3 +111,5 @@ }; | ||
AggregateApi.prototype.apply = function apply(name, payload, metadata) { | ||
generateEvent(aggregate, this._aggregateModel, eventEnricher, this._command, name, payload, metadata); | ||
if (this[modeSymbol] === HANDLER_MORE) | ||
return generateEvent(aggregate, this._aggregateModel, eventEnricher, this[commandSymbol], name, payload, metadata); | ||
return this._aggregateModel[deferredEventsSymbol].push([name, payload, metadata]); | ||
// this._aggregateModel.apply(eventEnricher(evt, this._aggregateModel, this._command) || evt); | ||
@@ -95,0 +116,0 @@ }; |
@@ -6,2 +6,20 @@ 'use strict'; | ||
const buildErrorBuilders = ({ BusinessRuleError, ValidationError }) => ({ | ||
businessRule(error) { | ||
if (error instanceof BusinessRuleError) | ||
return error; | ||
return new BusinessRuleError(error.message || error, error); | ||
}, | ||
validation(error) { | ||
if (error instanceof ValidationError) | ||
return error; | ||
return new ValidationError(error.message || error, error); | ||
}, | ||
}); | ||
const buildDefinitions = (definitions) => { | ||
definitions.errorBuilders = buildErrorBuilders(definitions.errors); | ||
return definitions; | ||
}; | ||
const buildContext = async ([contextName, aggregates], { Context, ...definitions }, customApiBuilder) => { | ||
@@ -24,3 +42,3 @@ const context = new Context({ name: contextName, externallyLoaded: true }); | ||
for(const entries of domainTreeEntries) // eslint-disable-line | ||
domainTree[entries[0]] = await buildContext(entries, definitions, customApiBuilder); // eslint-disable-line | ||
domainTree[entries[0]] = await buildContext(entries, buildDefinitions(definitions), customApiBuilder); // eslint-disable-line | ||
return domainTree; | ||
@@ -27,0 +45,0 @@ }; |
@@ -35,3 +35,3 @@ 'use strict'; | ||
{ | ||
commands = {}, events = {}, initialState = {}, rules = {}, eventEnricher, idGenerator, options = {}, | ||
commands = {}, events = {}, initialState = {}, rules = [], eventEnricher, idGenerator, options = {}, | ||
}, { | ||
@@ -38,0 +38,0 @@ Aggregate, |
'use strict'; | ||
const { asyncParamApiCallback } = require('../../utils'); | ||
const { asyncParamCustomErrorApiCallback } = require('../../utils'); | ||
@@ -36,4 +36,5 @@ const nameGenerator = (context, aggregateName, index) => `${context}:${aggregateName}:businessRule:${index}`; | ||
BusinessRule, | ||
errorBuilders, | ||
}, | ||
customApiBuilder, | ||
) => rulesNormalizer(context, aggregateName, rules).map(rule => new BusinessRule({ name: rule.name, description: rule.description }, asyncParamApiCallback(rule.rule, (cs, ps, e, c) => customApiBuilder(c), 'currentState', 'previousState', 'events', 'command'))); | ||
) => rulesNormalizer(context, aggregateName, rules).map(rule => new BusinessRule({ name: rule.name, description: rule.description }, asyncParamCustomErrorApiCallback(rule.rule, errorBuilders.businessRule, (cs, ps, e, c) => customApiBuilder(c), 'currentState', 'previousState', 'events', 'command'))); |
'use strict'; | ||
const { nextify, asyncParamApiCallback } = require('../../utils'); | ||
const { nextify, asyncParamCustomErrorApiCallback, toFlatArray } = require('../../utils'); | ||
@@ -55,2 +55,3 @@ /* | ||
validatorFunctionBuilder, | ||
errorBuilders, | ||
}, | ||
@@ -63,6 +64,4 @@ customApiBuilder, | ||
if (!Array.isArray(command)) | ||
command = [command]; | ||
command = toFlatArray(command); | ||
const result = { | ||
@@ -78,3 +77,3 @@ preLoadConditions: [], | ||
if (typeof item === 'function') { | ||
result.command = new Command(commandSettings, (cmd, agg) => item(cmd, new AggregateApi(agg, cmd), customApiBuilder(cmd))); | ||
result.command = new Command(commandSettings, (cmd, agg) => item(cmd, new AggregateApi(agg, cmd, 'handler'), customApiBuilder(cmd))); | ||
continue; | ||
@@ -95,8 +94,10 @@ } | ||
if (item.preLoadCondition) { | ||
result.preLoadConditions.push(new PreLoadCondition({ name: [commandName] }, asyncParamApiCallback(item.preLoadCondition, customApiBuilder, 'cmd'))); | ||
result.preLoadConditions.push(new PreLoadCondition({ name: [commandName] }, asyncParamCustomErrorApiCallback(item.preLoadCondition, errorBuilders.businessRule, customApiBuilder, 'cmd'))); | ||
continue; | ||
} | ||
if (item.preCondition) | ||
result.preConditions.push(new PreCondition({ name: [commandName] }, asyncParamApiCallback(item.preCondition, customApiBuilder, 'cmd', 'agg'))); | ||
if (item.preCondition) { | ||
const condition = ('mode' in item) ? async (cmd, agg) => item.preCondition(cmd, new AggregateApi(agg, cmd, item.mode)) : item.preCondition; | ||
result.preConditions.push(new PreCondition({ name: [commandName] }, asyncParamCustomErrorApiCallback(condition, errorBuilders.businessRule, customApiBuilder, 'cmd', 'agg'))); | ||
} | ||
} | ||
@@ -103,0 +104,0 @@ |
@@ -6,2 +6,6 @@ 'use strict'; | ||
const { toFlatArray, firstFilenamePart } = require('../utils'); | ||
const schemaExtractor = (handler = []) => ({ schema: (toFlatArray(handler).find(item => 'schema' in item) || {}).schema }); | ||
const loadAggregate = (filePath, { commands = {}, events = {} }) => { | ||
@@ -15,4 +19,5 @@ const aggregate = { | ||
// commands | ||
Object.entries(commands).forEach(([commandName]) => { | ||
aggregate.commands[commandName] = {}; | ||
Object.entries(commands).forEach(([commandName, commandHandler]) => { | ||
const { schema } = schemaExtractor(commandHandler); | ||
aggregate.commands[commandName] = schema ? { schema } : {}; | ||
}); | ||
@@ -34,9 +39,11 @@ | ||
if (!fs.statSync(aggregateFile).isFile()) | ||
if (!fs.statSync(aggregateFile).isFile() || path.extname(aggregateFile) !== '.js') | ||
return; | ||
if (path.extname(aggregateFile) !== '.js') return; | ||
const basename = firstFilenamePart(aggregateFile); | ||
context[path.basename(aggregateName, '.js')] = loadAggregate(aggregateFile, require(aggregateFile)); // eslint-disable-line | ||
if (context[basename]) | ||
throw new Error(`Duplicate aggregator: [${basename}] in: ${aggregateFile} and ${context[basename].path}.`); | ||
context[basename] = loadAggregate(aggregateFile, require(aggregateFile)); // eslint-disable-line | ||
}); | ||
@@ -43,0 +50,0 @@ |
'use strict'; | ||
const command = require('./command/index'); | ||
const event = require('./event/index'); | ||
const command = require('./command'); | ||
const event = require('./event'); | ||
@@ -6,0 +6,0 @@ module.exports = { |
{ | ||
"name": "cqrs-swissknife", | ||
"version": "0.4.3", | ||
"version": "0.4.4", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
'use strict'; | ||
const { asyncParamApiCallback, nameRetriever } = require('../../utils'); | ||
const { asyncParamApiCallback, nameRetriever, toFlatArray } = require('../../utils'); | ||
@@ -18,4 +18,3 @@ module.exports = ({ reactions = {}, identity = {} }, customApiBuilder = saga => saga, { Saga }) => Object.entries(reactions).map(([fullName, reaction]) => { | ||
if (!Array.isArray(reaction)) | ||
reaction = [reaction]; | ||
reaction = toFlatArray(reaction); | ||
@@ -22,0 +21,0 @@ reaction.forEach((item) => { |
@@ -6,2 +6,4 @@ 'use strict'; | ||
const { firstFilenamePart } = require('../utils'); | ||
const loadCollections = (sagasDirectory) => { | ||
@@ -17,3 +19,8 @@ const sagas = {}; | ||
sagas[path.basename(sagaName, '.js')] = { | ||
const basename = firstFilenamePart(sagaFile); | ||
if (sagas[basename]) | ||
throw new Error(`Duplicate saga: [${basename}] in: ${sagaFile} and ${sagas[basename].path}.`); | ||
sagas[basename] = { | ||
path: sagaFile, | ||
@@ -20,0 +27,0 @@ }; |
'use strict'; | ||
const path = require('path'); | ||
const noop = () => ({}); | ||
const valueop = v => v; | ||
const isObject = val => val != null && typeof val === 'object' && Array.isArray(val) === false; | ||
const isString = val => typeof val === 'string'; | ||
const flat = arr => arr.reduce((a, b) => a.concat(Array.isArray(b) ? flat(b) : b), []); | ||
const toFlatArray = (workflow) => { | ||
if (!Array.isArray(workflow)) | ||
return [workflow]; | ||
return flat(workflow); | ||
}; | ||
const assureAsync = (fn) => { | ||
if (typeof fn.then === 'function') | ||
return fn; | ||
return async (...params) => fn(...params); | ||
}; | ||
const promisifyWrappers = { | ||
@@ -28,5 +52,5 @@ 1: fn => function promisified(par1) { | ||
const nextifyWrappers = { | ||
1: fn => (par1, next) => Promise.resolve(fn(par1)).then(() => next(), error => next(error)), | ||
2: fn => (par1, par2, next) => Promise.resolve(fn(par1, par2)).then(() => next(), error => next(error)), | ||
3: fn => (par1, par2, par3, next) => Promise.resolve(fn(par1, par2, par3)).then(() => next(), error => next(error)), | ||
1: fn => (par1, next) => fn(par1).then(() => next(), error => next(error)), | ||
2: fn => (par1, par2, next) => fn(par1, par2).then(() => next(), error => next(error)), | ||
3: fn => (par1, par2, par3, next) => fn(par1, par2, par3).then(() => next(), error => next(error)), | ||
}; | ||
@@ -40,3 +64,3 @@ | ||
return asyncFn(fn); | ||
return asyncFn(assureAsync(fn)); | ||
}; | ||
@@ -55,8 +79,9 @@ | ||
const asyncParamApiCallbacks = { | ||
1: (fn, api) => (par1, callback) => Promise.resolve(fn(par1, api(par1))).then(result => callback(null, result), error => callback(error)), | ||
2: (fn, api) => (par1, par2, callback) => Promise.resolve(fn(par1, par2, api(par1, par2))).then(result => callback(null, result), error => callback(error)), | ||
3: (fn, api) => (par1, par2, par3, callback) => Promise.resolve(fn(par1, par2, par3, api(par1, par2, par3))).then(result => callback(null, result), error => callback(error)), | ||
4: (fn, api) => (par1, par2, par3, par4, callback) => Promise.resolve(fn(par1, par2, par3, par4, api(par1, par2, par3, par4))).then(result => callback(null, result), error => callback(error)), | ||
1: (fn, errorBuilder, api) => (par1, callback) => fn(par1, api(par1)).then(result => callback(null, result), error => callback(errorBuilder(error))), | ||
2: (fn, errorBuilder, api) => (par1, par2, callback) => fn(par1, par2, api(par1, par2)).then(result => callback(null, result), error => callback(errorBuilder(error))), | ||
3: (fn, errorBuilder, api) => (par1, par2, par3, callback) => fn(par1, par2, par3, api(par1, par2, par3)).then(result => callback(null, result), error => callback(errorBuilder(error))), | ||
4: (fn, errorBuilder, api) => (par1, par2, par3, par4, callback) => fn(par1, par2, par3, par4, api(par1, par2, par3, par4)).then(result => callback(null, result), error => callback(errorBuilder(error))), | ||
}; | ||
const asyncParamApiCallback = (fn, api, ...params) => { | ||
@@ -68,13 +93,14 @@ const asyncFn = asyncParamApiCallbacks[params.length]; | ||
return asyncFn(fn, api); | ||
return asyncFn(assureAsync(fn), valueop, api); | ||
}; | ||
const noop = () => ({}); | ||
const asyncParamCustomErrorApiCallback = (fn, errorBuilder = valueop, api, ...params) => { | ||
const asyncFn = asyncParamApiCallbacks[params.length]; | ||
const valueop = v => v; | ||
if (!asyncFn) | ||
throw new Error(`Async param callback function with ${params.length} parameters is not implemented yet.`); | ||
const isObject = val => val != null && typeof val === 'object' && Array.isArray(val) === false; | ||
return asyncFn(assureAsync(fn), errorBuilder, api); | ||
}; | ||
const isString = val => typeof val === 'string'; | ||
const nameRetriever = { | ||
@@ -92,6 +118,11 @@ /** | ||
const firstFilenamePart = filename => path.basename(filename).split('.', 1)[0]; | ||
module.exports = { | ||
toFlatArray, | ||
flat, | ||
nextify, | ||
promisify, | ||
asyncParamApiCallback, | ||
asyncParamCustomErrorApiCallback, | ||
noop, | ||
@@ -102,2 +133,3 @@ valueop, | ||
nameRetriever, | ||
firstFilenamePart, | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
32231
840
8