UNPKG

@eang/core

Version:

eang - model driven enterprise event processing

263 lines 8.8 kB
import { v7 as uuidv7 } from 'uuid'; class Entity { id; key; typeOf; instanceOf; name; childOf; description; data; tags; attributes; createdBy; createdAt; updatedBy; updatedAt; get displayName() { return this.name || this.key; } get instanceOfId() { if (this.instanceOf) { return `${this.typeOf}/${this.instanceOf}`; } return undefined; } constructor(entityOpts) { this.id = entityOpts.id; this.key = entityOpts.key; this.typeOf = entityOpts.typeOf; this.createdAt = Date.now(); // Default to now if not provided if (entityOpts.instanceOf !== undefined) this.instanceOf = entityOpts.instanceOf; if (entityOpts.name !== undefined) this.name = entityOpts.name; if (entityOpts.childOf !== undefined) this.childOf = entityOpts.childOf; if (entityOpts.description !== undefined) this.description = entityOpts.description; if (entityOpts.data !== undefined) this.data = entityOpts.data; this.tags = entityOpts.tags || {}; this.attributes = entityOpts.attributes || {}; if (entityOpts.createdBy !== undefined) this.createdBy = entityOpts.createdBy; if (entityOpts.createdAt !== undefined) this.createdAt = entityOpts.createdAt; if (entityOpts.updatedBy !== undefined) this.updatedBy = entityOpts.updatedBy; if (entityOpts.updatedAt !== undefined) this.updatedAt = entityOpts.updatedAt; } } export class Obj extends Entity { entityType = 'obj'; constructor(objOpts) { let id; let key; let typeOf; if (objOpts.id) { id = objOpts.id; const { key: parsedKey, typeOf: parsedTypeOf } = parseCombinedId(objOpts.id); key = parsedKey; typeOf = parsedTypeOf; } else { typeOf = objOpts.typeOf; key = objOpts.key || uuidv7(); id = typeOf + '/' + key; } objOpts.id = id; objOpts.key = key; objOpts.typeOf = typeOf; super(objOpts); } } export class Cnx extends Entity { entityType = 'cnx'; typeOf; fromObjId; fromObjKey; fromObjTypeOf; fromObjInstanceOf; toObjId; toObjKey; toObjTypeOf; toObjInstanceOf; constructor(cnxOpts) { let id; let key; let typeOf; if (cnxOpts.id) { id = cnxOpts.id; const { key: parsedKey, typeOf: parsedTypeOf } = parseCombinedId(cnxOpts.id); key = parsedKey; typeOf = parsedTypeOf ?? cnxOpts.typeOf; if (cnxOpts.typeOf && parsedTypeOf !== cnxOpts.typeOf) { throw new Error(`Type mismatch: expected ${cnxOpts.typeOf}, got ${parsedTypeOf}`); } } else if (cnxOpts.typeOf) { typeOf = cnxOpts.typeOf; key = cnxOpts.key || uuidv7(); id = typeOf + '/' + key; } else { throw new Error('Either id or typeOf must be provided for Cnx'); } cnxOpts.id = id; cnxOpts.key = key; cnxOpts.typeOf = typeOf; super(cnxOpts); this.typeOf = typeOf; if (cnxOpts.fromObjId) { this.fromObjId = cnxOpts.fromObjId; const { key: fromKey, typeOf: fromTypeOf } = parseCombinedId(cnxOpts.fromObjId); this.fromObjKey = fromKey; this.fromObjTypeOf = fromTypeOf; } else if (cnxOpts.fromObjKey && cnxOpts.fromObjTypeOf) { this.fromObjKey = cnxOpts.fromObjKey; this.fromObjTypeOf = cnxOpts.fromObjTypeOf; this.fromObjId = cnxOpts.fromObjTypeOf + '/' + cnxOpts.fromObjKey; } else { throw new Error('fromObjId or fromObjKey and fromObjTypeOf are required for Cnx'); } if (cnxOpts.fromObjInstanceOf !== undefined) { this.fromObjInstanceOf = cnxOpts.fromObjInstanceOf; } if (cnxOpts.toObjId) { this.toObjId = cnxOpts.toObjId; const { key: toKey, typeOf: toTypeOf } = parseCombinedId(cnxOpts.toObjId); this.toObjKey = toKey; this.toObjTypeOf = toTypeOf; } else if (cnxOpts.toObjKey && cnxOpts.toObjTypeOf) { this.toObjKey = cnxOpts.toObjKey; this.toObjTypeOf = cnxOpts.toObjTypeOf; this.toObjId = cnxOpts.toObjTypeOf + '/' + cnxOpts.toObjKey; } else { throw new Error('toObjId or toObjKey and toObjTypeOf are required for Cnx'); } if (cnxOpts.toObjInstanceOf !== undefined) { this.toObjInstanceOf = cnxOpts.toObjInstanceOf; } } } export const EangEventType = { create: 'create', update: 'update', delete: 'delete', start: 'start', stop: 'stop' }; export class EntityEvent { entity; eventType; context; tenant; organizationalUnit; user; constructor(entity, eventType, context, options) { this.entity = entity; this.eventType = eventType; this.context = context; if (options?.tenant !== undefined) { this.tenant = options.tenant; } if (options?.organizationalUnit !== undefined) { this.organizationalUnit = options.organizationalUnit; } if (options?.user !== undefined) { this.user = options.user; } } static parse(entity, eventType, context, options) { return new EntityEvent(entity, eventType, context, options); } static create(entity, options) { if (!entity.createdAt) { entity.createdAt = Date.now(); } return new EntityEvent(entity, EangEventType.create, undefined, options); } static update(entity, context, options) { entity.updatedAt = Date.now(); // Apply new values to the entity before creating the event return new EntityEvent(entity, EangEventType.update, context, options); } static delete(entity, options) { return new EntityEvent(entity, EangEventType.delete, undefined, options); } static start(entity, context, options) { if ('createdAt' in entity && !entity.createdAt) { entity.createdAt = Date.now(); } if (!('startedAt' in entity) || !entity.startedAt) { entity.startedAt = Date.now(); } return new EntityEvent(entity, EangEventType.start, context, options); } static stop(entity, context, options) { if (!('stoppedAt' in entity) || !entity.stoppedAt) { entity.stoppedAt = Date.now(); } return new EntityEvent(entity, EangEventType.stop, context, options); } } export function parseCombinedId(id) { const sepIdx = id.indexOf('/'); if (sepIdx === -1 || sepIdx === 0 || sepIdx === id.length - 1) { throw new Error(`Invalid ID format: ${id}`); } return { typeOf: id.slice(0, sepIdx), key: id.slice(sepIdx + 1) }; } /** * Converts an entity (Obj or Cnx) to ArangoDB document format * @param entity The entity to convert * @returns ArangoDB document with proper _key, _from, _to fields */ export function toArangoDoc(entity) { // Prepare the document for ArangoDB const arangoDoc = { _key: entity.key, ...entity }; // Remove fields that shouldn't be stored or are redundant delete arangoDoc.key; delete arangoDoc.entityType; delete arangoDoc.id; // Remove empty tags and attributes objects if (arangoDoc.tags && typeof arangoDoc.tags === 'object' && Object.keys(arangoDoc.tags).length === 0) { delete arangoDoc.tags; } if (arangoDoc.attributes && typeof arangoDoc.attributes === 'object' && Object.keys(arangoDoc.attributes).length === 0) { delete arangoDoc.attributes; } // Handle connection entities differently if (entity.entityType === 'cnx') { // For connections, we need to set _from and _to for ArangoDB edge collection arangoDoc._from = entity.fromObjId; arangoDoc._to = entity.toObjId; // Remove the redundant connection fields that ArangoDB doesn't need delete arangoDoc.fromObjId; delete arangoDoc.fromObjKey; delete arangoDoc.fromObjTypeOf; delete arangoDoc.fromObjInstanceOf; delete arangoDoc.toObjId; delete arangoDoc.toObjKey; delete arangoDoc.toObjTypeOf; delete arangoDoc.toObjInstanceOf; } else { delete arangoDoc.typeOf; } return arangoDoc; } //# sourceMappingURL=entity.js.map