@getanthill/datastore
Version:
Event-Sourced Datastore
174 lines • 6.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = getGraph;
exports.getEntitiesFromGraph = getEntitiesFromGraph;
const DEFAULT_FIELDS = {
id: 'id',
group: 'group',
nodes: 'nodes',
edges: 'edges',
source: 'source',
target: 'target',
value: 'value',
key: 'key',
entity_id_suffix: '_id',
entity_type_suffix: '_type',
correlation_field: 'correlation_field',
};
function addNode(fields, id, group) {
return {
[fields.id]: id,
[fields.group]: group,
};
}
function addEdge(fields, source, target, value, key, correlationField) {
return {
[fields.source]: source,
[fields.target]: target,
[fields.value]: value,
[fields.key]: key,
[fields.correlation_field]: correlationField,
};
}
function getFieldsFromOptions(options) {
return {
...DEFAULT_FIELDS,
...options === null || options === void 0 ? void 0 : options.fields,
};
}
function addEdgesFromDiscovery(models, graph, modelName, key, modelNames = [], options) {
const fields = getFieldsFromOptions(options);
modelNames.forEach((l) => {
if (!models.hasModel(l)) {
return;
}
const linkedModel = models.getModel(l);
graph[fields.edges].push(addEdge(fields, modelName, l, 1, key, linkedModel.getCorrelationField()));
});
}
function addEdgeWithoutLink(models, graph, modelName, key, options) {
const fields = getFieldsFromOptions(options);
if (key.endsWith(fields.entity_id_suffix)) {
const target = key
.replace(fields.entity_id_suffix, 's')
.replace(/ss$/, 's');
if (!models.hasModel(target) || target === modelName) {
return;
}
graph[fields.edges].push(addEdge(fields, modelName, target, 1, key, models.getModel(target).getCorrelationField()));
}
}
function addEdgesFromEntityTypeLink(models, graph, modelName, key, modelNames = [], options) {
const fields = getFieldsFromOptions(options);
modelNames.forEach((l) => graph[fields.edges].push(addEdge(fields, modelName, l, 1, key, models.getModel(l).getCorrelationField())));
}
function addEdgesFromProperties(models, graph, modelName, options) {
var _a, _b, _c, _d;
const fields = getFieldsFromOptions(options);
const model = models.getModel(modelName);
const schema = model.getOriginalSchema();
const properties = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.model) === null || _a === void 0 ? void 0 : _a.properties) !== null && _b !== void 0 ? _b : {};
const links = (_d = (_c = model.getModelConfig()) === null || _c === void 0 ? void 0 : _c.links) !== null && _d !== void 0 ? _d : [];
for (const key in properties) {
/* @ts-ignore */
const link = links[key];
const entityKey = key.replace(fields.entity_id_suffix, '');
const entityTypeKey = `${entityKey}${fields.entity_type_suffix}`;
/**
* Discovery process
*/
if (options.mustDiscover !== false && properties[entityTypeKey]) {
addEdgesFromDiscovery(models, graph, modelName, key, properties[entityTypeKey].enum, options);
continue;
}
/**
* group_id -> groups
* account_id -> accounts
*/
if (!link) {
addEdgeWithoutLink(models, graph, modelName, key, options);
continue;
}
if (properties[link]) {
addEdgesFromEntityTypeLink(models, graph, modelName, key, properties[link].enum, options);
continue;
}
if (!models.hasModel(link)) {
continue;
}
graph[fields.edges].push(addEdge(fields, modelName, link, 1, key, models.getModel(link).getCorrelationField()));
}
}
function getGraph(models, options = {}) {
const fields = getFieldsFromOptions(options);
const graph = {
[fields.nodes]: [],
[fields.edges]: [],
};
for (const modelName of models.MODELS.keys()) {
if (models.isInternalModel(modelName) === true) {
continue;
}
graph[fields.nodes].push(addNode(fields, modelName, graph[fields.nodes].length));
addEdgesFromProperties(models, graph, modelName, options);
}
return graph;
}
function getEntityId(modelName, correlationId) {
return `${modelName}:${correlationId}`;
}
async function getEntitiesFromGraph(services, modelName, query, options = {}, entities = new Map()) {
var _a, _b, _c, _d;
if ((Array.isArray(options.models) && !options.models.includes(modelName)) ||
!services.models) {
return entities;
}
const graph = (_a = options.graph) !== null && _a !== void 0 ? _a : getGraph(services.models);
const Model = services.models.getModel(modelName);
const correlationField = Model.getCorrelationField();
const entityIds = new Set();
const cursor = await Model.find(services.mongodb, {
...query,
[Model.getIsArchivedProperty()]: {
$in: [null, false, true],
},
}, {
projection: {
_id: 0,
...(options.withCorrelationFieldOnly === true
? {
[correlationField]: 1,
}
: {}),
},
});
while (await cursor.hasNext()) {
let entity = await cursor.next();
const entityId = getEntityId(modelName, entity[correlationField]);
if (entities.has(entityId)) {
continue;
}
if ('handler' in options && options.handler) {
entity = await options.handler(services, Model, entity);
}
entityIds.add(entity[correlationField]);
entities.set(entityId, entity);
}
// Descendant nodes
const childrenModels = (_b = graph === null || graph === void 0 ? void 0 : graph.edges) === null || _b === void 0 ? void 0 : _b.filter((edge) => edge.target === modelName);
for (const childModel of childrenModels) {
const sourceModel = services.models.getModel(childModel.source);
const link = (_d = (_c = sourceModel.getModelConfig()) === null || _c === void 0 ? void 0 : _c.links) === null || _d === void 0 ? void 0 : _d[childModel.key];
const childQuery = {
[childModel.key]: {
$in: Array.from(entityIds.values()),
},
};
if (sourceModel.getSchema().model.properties[link]) {
childQuery[link] = childModel.target;
}
await getEntitiesFromGraph(services, childModel.source, childQuery, { ...options, graph }, entities);
}
return entities;
}
//# sourceMappingURL=graph.js.map