UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

297 lines 13.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.mapDateTimeFormatToEitherStringOrObject = exports.replaceEncryptedFields = exports.replaceEntityEncryptedFields = exports.merge = exports.mergeWithArrays = void 0; const lodash_1 = __importDefault(require("lodash")); const c = __importStar(require("../constants")); const utils_1 = require("../utils"); const PROPERTIES_MODEL_CONFIG_PATH = 'schema.model.properties'; const MERGE_ARRAY_KEYS = Object.freeze(['required', 'indexes']); function mergeWithArrays(objValue, srcValue, key) { if (Array.isArray(objValue) && MERGE_ARRAY_KEYS.includes(key)) { return objValue.concat(srcValue).filter(utils_1.unique); } } exports.mergeWithArrays = mergeWithArrays; function merge(...args) { // @ts-ignore return lodash_1.default.mergeWith.call(null, ...args); } exports.merge = merge; function getDefaultEvents(services, modelConfig, properties) { if (modelConfig.with_default_events === false) { return {}; } return { [c.EVENT_TYPE_CREATED]: { '0_0_0': { type: 'object', additionalProperties: modelConfig.schema?.model?.additionalProperties ?? false, required: ['type', 'v', ...(modelConfig.schema?.model?.required ?? [])], properties: { ...properties, ...c.COMPONENT_STATE_PROPERTIES, ...c.COMPONENT_EVENT_PROPERTIES, [services.config.features.properties.is_readonly]: c.COMPONENTS.is_readonly, }, }, }, [c.EVENT_TYPE_UPDATED]: { '0_0_0': { type: 'object', additionalProperties: modelConfig.schema?.model?.additionalProperties ?? false, required: ['type', 'v'], properties: { ...properties, ...c.COMPONENT_STATE_PROPERTIES, ...c.COMPONENT_EVENT_PROPERTIES, [services.config.features.properties.is_readonly]: c.COMPONENTS.is_readonly, }, }, }, [c.EVENT_TYPE_PATCHED]: { '0_0_0': { type: 'object', additionalProperties: modelConfig.schema?.model?.additionalProperties ?? false, required: ['json_patch'], properties: { json_patch: c.COMPONENT_JSON_PATCH, }, }, }, [c.EVENT_TYPE_ARCHIVED]: { '0_0_0': { type: 'object', additionalProperties: modelConfig.schema?.model?.additionalProperties ?? false, properties: { ...properties, [services.config.features.properties.is_readonly]: c.COMPONENTS.is_readonly, [services.config.features.properties.is_archived]: c.COMPONENTS.is_archived, [services.config.features.properties.is_deleted]: c.COMPONENTS.is_deleted, }, }, }, [c.EVENT_TYPE_DELETED]: { '0_0_0': { type: 'object', additionalProperties: modelConfig.schema?.model?.additionalProperties ?? false, properties: { ...properties, [services.config.features.properties.is_readonly]: c.COMPONENTS.is_readonly, [services.config.features.properties.is_archived]: c.COMPONENTS.is_archived, [services.config.features.properties.is_deleted]: c.COMPONENTS.is_deleted, }, }, }, [c.EVENT_TYPE_RESTORED]: { '0_0_0': { type: 'object', additionalProperties: modelConfig.schema?.model?.additionalProperties ?? false, required: ['type', 'v'], properties: { ...properties, ...c.COMPONENT_STATE_PROPERTIES, ...c.COMPONENT_EVENT_PROPERTIES, [services.config.features.properties.is_readonly]: c.COMPONENTS.is_readonly, [services.config.features.properties.is_archived]: c.COMPONENTS.is_archived, [services.config.features.properties.is_deleted]: c.COMPONENTS.is_deleted, }, }, }, [c.EVENT_TYPE_ROLLBACKED]: { '0_0_0': { type: 'object', additionalProperties: modelConfig.schema?.model?.additionalProperties ?? false, required: ['type', 'v'], properties: { ...properties, ...c.COMPONENT_STATE_PROPERTIES, ...c.COMPONENT_EVENT_PROPERTIES, [services.config.features.properties.is_readonly]: c.COMPONENTS.is_readonly, [services.config.features.properties.is_archived]: c.COMPONENTS.is_archived, [services.config.features.properties.is_deleted]: c.COMPONENTS.is_deleted, }, }, }, }; } function extendEventsWithDefaultFields(jsonSchema) { for (const eventType in jsonSchema.events) { for (const eventVersion in jsonSchema.events[eventType]) { lodash_1.default.set(jsonSchema, ['events', eventType, eventVersion], lodash_1.default.mergeWith({}, { type: 'object', additionalProperties: false, required: ['type', 'v'], properties: { type: c.COMPONENTS.type, v: c.COMPONENTS.v, version: c.COMPONENTS.version, json_patch: c.COMPONENT_JSON_PATCH, created_at: c.COMPONENTS.created_at, }, }, jsonSchema.events[eventType][eventVersion], mergeWithArrays)); } } return jsonSchema; } function replaceEventsEncryptedFields(modelConfig, clonedModelConfig) { for (const eventName in clonedModelConfig.schema?.events) { for (const eventVersion in clonedModelConfig.schema.events[eventName]) { for (const field of modelConfig.encrypted_fields ?? []) { if (lodash_1.default.has(clonedModelConfig.schema.events[eventName][eventVersion].properties, field)) { lodash_1.default.set(clonedModelConfig.schema.events[eventName][eventVersion].properties, field, { description: lodash_1.default.get(clonedModelConfig.schema.events[eventName][eventVersion] .properties, field, { description: '', }).description, anyOf: [ { type: 'object', description: `\`encrypted\` ${lodash_1.default.get(clonedModelConfig.schema.events[eventName][eventVersion] .properties, field, {}).description ?? ''}`, properties: { hash: { type: 'string', description: '`sha512` value', example: 'b8cccea15437aef415090bda6acb3b0ad3d4cf7d3e4cf816772e4b43e8f9d08af392bb98b8d532e07249f0d1304e6d65e007205c39913ee5db95578be398f4bd', }, encrypted: { type: 'string', description: 'Encrypted value', example: '03d72e:1e9f1a960adfd0815530f7133c97dcd2:648b63622bb5bc3145de4d3f15fe05651ebdedbeab1d11986538214c4a25b834', }, }, }, lodash_1.default.get(clonedModelConfig.schema.events[eventName][eventVersion] .properties, field), ], }); } } } } } function replaceEntityEncryptedFields(modelConfig, clonedModelConfig) { for (const field of modelConfig.encrypted_fields ?? []) { lodash_1.default.set(clonedModelConfig.schema.model.properties, field, { description: lodash_1.default.get(clonedModelConfig.schema.model.properties, field, { description: '', }).description, anyOf: [ { type: 'object', description: `\`encrypted\` ${lodash_1.default.get(clonedModelConfig.schema.model.properties, field, {}) .description ?? ''}`, properties: { hash: { type: 'string', description: '`sha512` value', example: 'b8cccea15437aef415090bda6acb3b0ad3d4cf7d3e4cf816772e4b43e8f9d08af392bb98b8d532e07249f0d1304e6d65e007205c39913ee5db95578be398f4bd', }, encrypted: { type: 'string', description: 'Encrypted value', example: '03d72e:1e9f1a960adfd0815530f7133c97dcd2:648b63622bb5bc3145de4d3f15fe05651ebdedbeab1d11986538214c4a25b834', }, }, }, lodash_1.default.get(clonedModelConfig.schema.model.properties, field), ], }); } return clonedModelConfig; } exports.replaceEntityEncryptedFields = replaceEntityEncryptedFields; function replaceEncryptedFields(modelConfig) { const clonedModelConfig = lodash_1.default.cloneDeep(modelConfig); replaceEntityEncryptedFields(modelConfig, clonedModelConfig); replaceEventsEncryptedFields(modelConfig, clonedModelConfig); return clonedModelConfig; } exports.replaceEncryptedFields = replaceEncryptedFields; function buildJsonSchema(services, modelConfig) { const extendedModelConfig = replaceEncryptedFields(modelConfig); const correlationField = extendedModelConfig.correlation_field || c.DEFAULT_CORRELATION_FIELD; const properties = { [correlationField]: c.COMPONENT_CORRELATION_ID, ...lodash_1.default.get(extendedModelConfig, PROPERTIES_MODEL_CONFIG_PATH, {}), }; if (extendedModelConfig.with_blockchain_hash === true) { properties[extendedModelConfig.current_hash_field ?? 'hash'] = { type: 'string', description: 'Entity hash', }; properties[extendedModelConfig.previous_hash_field ?? 'prev'] = { type: 'string', description: 'Previous entity hash', }; properties[extendedModelConfig.nonce_field ?? 'nonce'] = { type: 'integer', description: 'Nonce value', }; } const modelJsonSchema = { $id: 'events', components: c.COMPONENTS, retry_duration: 0, model: { type: 'object', additionalProperties: extendedModelConfig.schema?.model?.additionalProperties ?? false, required: extendedModelConfig.schema?.model?.required, properties: { ...properties, version: c.COMPONENT_EVENT_VERSION, created_at: c.COMPONENTS.created_at, updated_at: c.COMPONENTS.updated_at, [services.config.features.properties.is_readonly]: c.COMPONENTS.is_readonly, [services.config.features.properties.is_archived]: c.COMPONENTS.is_archived, [services.config.features.properties.is_deleted]: c.COMPONENTS.is_deleted, }, }, events: getDefaultEvents(services, extendedModelConfig, properties), }; return extendEventsWithDefaultFields(lodash_1.default.mergeWith({}, modelJsonSchema, extendedModelConfig.schema, mergeWithArrays)); } exports.default = buildJsonSchema; function mapDateTimeFormatToEitherStringOrObject(schema) { return lodash_1.default.mergeWith({}, schema, (src, obj) => { if (obj?.type && obj?.format?.startsWith('date')) { return { oneOf: [ obj, { ...obj, type: 'object', }, ], }; } }); } exports.mapDateTimeFormatToEitherStringOrObject = mapDateTimeFormatToEitherStringOrObject; //# sourceMappingURL=schema.js.map