@mvp-rockets/namma-generator
Version:
A generator to generate mvp-rockets projects
248 lines (215 loc) • 7.57 kB
JavaScript
/* eslint-disable no-restricted-syntax */
/* eslint-disable guard-for-in */
const R = require('ramda');
const db = require('db/repository');
const common = require('helpers/common');
const { whenResult, doNothing } = require('lib');
const { notEmpty } = require('validation');
const data = require('./data');
const dataValueUpdater = require('./update-data-value');
let cache = [];
const factory = async function () {
if (arguments.length === 0) {
throw new Error('factory requires at least one argument');
}
const init = Array.prototype.slice.call(arguments);
const all = R.map(async (need) => await need(), init);
const allEntities = await Promise.all(all);
cache = cache.concat(allEntities);
return R.compose(
R.head,
R.mapAccum((acc, data) => [Object.assign(acc, R.head(data)), data], {})
)(allEntities);
};
const build = function (entity, useValue, name) {
name = name || entity.name;
if (typeof (useValue) === 'function') {
useValue = useValue || withNoValueChange;
} else {
useValue = useValue != undefined ? withValue(useValue) : withNoValueChange;
}
return async function () {
const data = await R.composeWith(R.andThen)([withName(name), useValue, (data) => {
if (entity.update) { return entity.update(data); } return data;
}, entity.build])();
return [data, entity];
};
};
const buildSingle = function (entity, value) {
return R.composeWith(R.andThen)([getEntity, R.head, addToCache, build(entity, value)])();
};
const createAssociatedEntities = R.curry(
async (name, data, dependencies, changeDependency) => {
for (const index in dependencies) {
const dependency = dependencies[index];
let dataTransformer = dependency[0];
let entity = dependency[1];
if (changeDependency && changeDependency[entity.name]) {
dataTransformer = changeDependency[entity.name][0];
entity = changeDependency[entity.name][1];
}
const createdDependency = await create(
entity,
dataTransformer(R.head(data)[name]),
entity.name,
changeDependency
)();
const parentEntity = R.head(data)[name];
parentEntity[entity.name] = createdDependency[0][entity.name];
}
}
);
const create = (entity, value, name, changeDependency) => {
if (!entity) throw Error('entity not defined');
name = name || entity.name;
return async () => {
const data = await build(entity, value, name)();
if (R.head(data)[name].created_by_factory) {
return data;
}
if (notEmpty(entity.dependency)) {
await createAssociatedEntities(
entity.name,
data,
entity.dependency,
changeDependency
);
}
const promises = R.map(db.execute, entity.create(R.head(data)[name]));
const result = await Promise.all(promises);
whenResult((createdEntity) => R.head(data)[name].created_by_factory = true)(result[0]);
whenResult(doNothing, (e) => console.trace(entity.name, e))(result[0]);
whenResult(doNothing, (e) => {
throw e;
})(result[0]);
if (entity.transform) {
R.head(data)[name] = entity.transform(
common.getDataFromResult(null, result),
R.head(data)[name]
);
}
return data;
};
};
const addToCache = (data) => {
cache.push(data);
return data;
};
var getEntity = function (data) {
const propertyName = R.compose(R.head, R.keys)(data);
return data[propertyName];
};
const createSingle = (entity, value, changeDependency) => R.composeWith(R.andThen)([
getEntity,
R.head,
addToCache,
create(entity, value, entity.name, changeDependency)]
)();
const deleteAssociatedEntities = async (entity, data, changeDependency) => {
let deletedEntity;
if (data) {
if (entity.has) {
const deleteResult = R.map((dependent) => {
let transformer = dependent[0];
let dependentEntity = dependent[1];
if (changeDependency && changeDependency[entity.name]) {
[transformer, dependentEntity] = changeDependency[entity.name];
}
const transformedData = transformer(data);
return deleteAssociatedEntities(
dependentEntity,
transformedData,
changeDependency
);
}, entity.has);
const result = await Promise.all(deleteResult);
}
try {
entity.delete(data).forEach(async (entityToDelete) => {
await db.execute(entityToDelete);
});
} catch (e) {
console.error(entity.name);
console.error(e);
}
if (entity.dependency) {
const deleteResult = R.map((dependent) => {
let transformer = dependent[0];
let dependentEntity = dependent[1];
if (changeDependency && changeDependency[entity.name]) {
transformer = changeDependency[entity.name][0];
dependentEntity = changeDependency[entity.name][1];
}
const transformedData = transformer(data);
return deleteAssociatedEntities(
dependentEntity,
transformedData,
changeDependency
);
}, entity.dependency);
await Promise.all(deleteResult);
}
}
return data;
};
const deleteEntity = R.curry(async (changeDependency, entityToDelete) => {
const data = R.compose(getEntity, R.head)(entityToDelete);
const entity = R.last(entityToDelete);
return deleteAssociatedEntities(entity, data, changeDependency);
});
const deleteAll = async function (changeDependency) {
const dataToDelete = cache;
cache = [];
return Promise.all(R.map(deleteEntity(changeDependency), dataToDelete));
};
var withName = R.curry((name, entity) => {
const data = {};
data[name] = entity;
return data;
});
const keyify = (obj, prefix = '') => Object.keys(obj).reduce((res, el) => {
if (Array.isArray(obj[el])) {
return res;
} if (typeof obj[el] === 'object' && obj[el] !== null) {
return [...res, ...keyify(obj[el], `${prefix + el}.`)];
}
return [...res, prefix + el];
}, []);
var withValue = R.curry((value, entity) => R.mergeDeepRight(entity, value));
var withNoValueChange = (data) => data;
const retriveNestedEntity = (name, object) => {
const foundProperty = R.has(name, object);
if (foundProperty) {
return {
found: true,
value: object[name]
};
}
if (R.keys(object).length === 0) {
return {
found: false
};
}
for (const [key, value] of Object.entries(object)) {
const response = retriveNestedEntity(name, value);
if (response.found) return response;
}
return {
found: false
};
};
module.exports = R.mergeAll([
data,
{
factory,
build,
buildSingle,
create,
createSingle,
deleteEntity,
deleteAll,
withValue,
retriveNestedEntity
},
dataValueUpdater
]);