UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

1,083 lines (1,075 loc) 41.4 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.decrypt = exports.encrypt = exports.createModelSnapshot = exports.getModelEvents = exports.restoreVersion = exports.getModelAtVersion = exports.getModel = exports.getModels = exports.patchModel = exports.updateModel = exports.createModel = exports.stream = exports.buildAdditionalPaths = exports.defaultSchema = exports.getEntityName = exports.buildFromModel = exports.eventNametoCamelCase = exports.findLinks = exports.build = void 0; const filter_1 = __importDefault(require("lodash/filter")); const get_1 = __importDefault(require("lodash/get")); const has_1 = __importDefault(require("lodash/has")); const isObject_1 = __importDefault(require("lodash/isObject")); const merge_1 = __importDefault(require("lodash/merge")); const omit_1 = __importDefault(require("lodash/omit")); const c = __importStar(require("../../constants")); const components_1 = __importDefault(require("./components")); const MIME_APPLICATION_JSON = 'application/json'; function build(origin, models) { let spec = (0, merge_1.default)({ paths: { [`/stream/{model}/{source}`]: { post: stream(models), }, [`/stream/{model}/{source}/sse`]: { get: stream(models, true), }, }, }, origin); for (const [modelName, model] of new Map([...models.MODELS.entries()].sort())) { if (models.isInternalModel(modelName) === false) { const links = findLinks(model, models); spec = buildFromModel(spec, model, links); } } return spec; } exports.build = build; function walkKeysDeep(obj, cb, p = []) { for (const k in obj) { cb(k, p); if ((0, isObject_1.default)(obj[k])) { walkKeysDeep(obj[k], cb, [...p, k]); } } } function showHandler(event) { if (event['x-show-handler'] !== true) { return ''; } let description = ''; if ((0, has_1.default)(event, 'handler')) { description += ` ### Handler \`\`\` function handler(state, event) { ${(0, get_1.default)(event, 'handler')} } \`\`\``; } return description; } function findLinks(model, models) { const links = {}; walkKeysDeep(model.getSchema().model.properties, (k, p) => { if (k.endsWith('_id') && k !== model.getCorrelationField()) { const linkedModel = models.getModelByCorrelationField(k); /* istanbul ignore next */ if (linkedModel !== null) { links[k] = { path: [ ...p.filter((fragment) => !['items', 'properties'].includes(fragment)), k, ].join('/'), model: linkedModel, }; } } }); return links; } exports.findLinks = findLinks; function eventNametoCamelCase(str) { return str .toLowerCase() .replace(/([-_][a-zA-Z])/g, (group) => group.toUpperCase().replace('-', '').replace('_', '')); } exports.eventNametoCamelCase = eventNametoCamelCase; function buildFromModel(spec, model, links) { const collection = model.getCollectionName(); const schema = model.getSchema(); const modelConfig = model.getModelConfig(); const tagName = getEntityName(model); const entityName = getEntityName(model, true); const events = Object.keys(schema.events); const additionnalPaths = buildAdditionalPaths(model); const component = schema.model; const processings = modelConfig.processings ?? []; const processingsStr = processings .map((processing, i) => { const title = 'Activity ' + tagName[0] + '.' + (i + 1) + ' - `' + processing.field + '` - ' + processing.name; let str = '### ' + title + '\n\n'; str += processing.purpose + '\n'; if (Array.isArray(processing.tokens)) { str += '#### tokens\n'; str += processing.tokens.map((p) => `- \`${p}\``).join('\n'); str += '\n\n'; } str += '#### Persons\n'; str += processing.persons.map((p) => `- ${p}`).join('\n'); str += '\n\n'; str += '#### Recipients\n'; str += processing.recipients.map((p) => `- ${p}`).join('\n'); str += '\n\n'; return str; }) .join('\n'); return { ...spec, components: { ...spec.components, schemas: { ...spec.components.schemas, [entityName]: { ...component, required: component.required ?? undefined, }, }, }, tags: [ ...(spec.tags || []), { name: tagName, description: `${modelConfig.description ?? 'Routes available for the model <code>' + entityName + '</code>'} Events available to this model: ${events.length > 0 ? events.map((event) => '<code>' + event + '</code>').join(', ') : 'none'}. <details> <summary>JSON Schema</summary> \`\`\`json ${JSON.stringify(schema.model, null, 2)} \`\`\` </summary> </details> <details> <summary>Data Processings (${processings.length})</summary> ${processingsStr} </summary> </details> `, }, ], paths: (0, merge_1.default)({}, spec.paths, { [`/${collection}`]: { get: getModels(model, links), }, [`/${collection}/encrypt`]: { post: encrypt(model, links), }, [`/${collection}/decrypt`]: { post: decrypt(model, links), }, [`/${collection}/events`]: { post: getModelEvents(model, links, { skipCorrelationField: true }), }, [`/${collection}/{${model.getCorrelationField()}}`]: { get: getModel(model, links), }, [`/${collection}/{${model.getCorrelationField()}}/events`]: { get: getModelEvents(model, links), }, [`/${collection}/{${model.getCorrelationField()}}/snapshot`]: { post: createModelSnapshot(model, links), }, [`/${collection}/{${model.getCorrelationField()}}/{version}`]: { get: getModelAtVersion(model, links), }, }, events.includes(c.EVENT_TYPE_CREATED) && { [`/${collection}`]: { post: createModel(model, links), }, }, events.includes(c.EVENT_TYPE_UPDATED) && { [`/${collection}/{${model.getCorrelationField()}}`]: { post: updateModel(model, links), }, }, events.includes(c.EVENT_TYPE_PATCHED) && { [`/${collection}/{${model.getCorrelationField()}}`]: { patch: patchModel(model, links), }, }, events.includes(c.EVENT_TYPE_RESTORED) && { [`/${collection}/{${model.getCorrelationField()}}/{version}/restore`]: { post: restoreVersion(model, links), }, }, additionnalPaths), }; } exports.buildFromModel = buildFromModel; function getEntityName(model, singular = false) { let collection = typeof model === 'string' ? model : model.getCollectionName(); if (singular === true) { collection = collection.replace(/s$/, ''); } return collection.charAt(0).toUpperCase() + collection.slice(1); } exports.getEntityName = getEntityName; function buildLinks(links) { const _links = {}; for (const key in links) { _links[getEntityName(links[key].model, true)] = { operationId: eventNametoCamelCase(`GET_${getEntityName(links[key].model, true)}`), parameters: { /** * @fixme Apply the camelCase only for GraphQL because in the current * implementation, the link on REST is invalid */ [key]: `$response.body#/${eventNametoCamelCase(links[key].path)}`, // For GraphQL }, }; } return _links; } function defaultSchema(model) { return { tags: [getEntityName(model)], security: [ { apiKey: [], }, ], responses: { default: { $ref: '#/components/responses/default', }, }, }; } exports.defaultSchema = defaultSchema; function buildAdditionalPaths(model) { const additionnalPaths = {}; const collection = model.getCollectionName(); const schema = model.getSchema(); const originalSchema = model.getOriginalSchema(); const events = schema.events; const entityName = getEntityName(model, true); for (const eventType in events) { if (![ c.EVENT_TYPE_CREATED, c.EVENT_TYPE_UPDATED, c.EVENT_TYPE_RESTORED, c.EVENT_TYPE_ROLLBACKED, c.EVENT_TYPE_PATCHED, c.EVENT_TYPE_ARCHIVED, c.EVENT_TYPE_DELETED, ].includes(eventType)) { const eventTypeLowered = eventType.toLocaleLowerCase(); for (const eventVersion in events[eventType]) { const event = events[eventType][eventVersion]; const required = (0, filter_1.default)(event.required, (r) => !['v', 'type'].includes(r)); const routeSpec = (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`${entityName}_${eventType}`), summary: event.title || `${eventTypeLowered}:v${eventVersion}`, description: event.description || `Business event <code>${eventType}</code> at version <code>${eventVersion}</code>`, parameters: [ { in: 'path', name: model.getCorrelationField(), description: 'Correlation id', schema: c.COMPONENT_CORRELATION_ID, required: true, }, ], requestBody: { content: { [MIME_APPLICATION_JSON]: { schema: { ...(0, omit_1.default)(event, 'handler', 'handlers', 'x-responses', 'x-show-handler', 'is_created', 'is_fhe', 'upsert'), properties: { ...(0, omit_1.default)(event.properties, 'v', 'type', 'version', 'json_patch', 'created_at', 'updated_at'), }, required: required.length ? required : undefined, }, }, }, }, responses: { 200: { description: 'Entity successfully updated', content: { [MIME_APPLICATION_JSON]: { schema: { $ref: `#/components/schemas/${entityName}`, }, }, }, }, 400: { ...components_1.default.responses[400], description: 'Invalid Model / Event schema validation error', }, 409: components_1.default.responses[409], 422: components_1.default.responses[422], }, }); routeSpec.description += showHandler(event); const additionalResponses = {}; (event['x-responses'] || []).forEach((response) => { additionalResponses[response.status] = { description: response.description, content: { 'application/json': { example: { status: response.status, message: response.description, details: response.details, }, schema: { $ref: '#/components/schemas/error', }, }, }, }; }); routeSpec.responses = { ...routeSpec.responses, ...additionalResponses, }; const originalEvent = (0, get_1.default)(originalSchema, `events.${eventType}.${eventVersion}`, {}); routeSpec.requestBody.content[MIME_APPLICATION_JSON].schema.properties = { ...routeSpec.requestBody.content[MIME_APPLICATION_JSON].schema .properties, ...(0, omit_1.default)(originalEvent.properties, 'v', 'type', 'version', 'json_patch', 'created_at', 'updated_at'), }; additionnalPaths[`/${collection}/{${model.getCorrelationField()}}/${eventTypeLowered}/${eventVersion}`] = { post: routeSpec, }; } } } return additionnalPaths; } exports.buildAdditionalPaths = buildAdditionalPaths; function stream(models, isSSE = false) { const entityName = 'all'; return (0, merge_1.default)({}, { operationId: eventNametoCamelCase(`stream_${entityName}${isSSE === true ? '_sse' : ''}`), summary: `Stream ${entityName} changes${isSSE === true ? ' SSE' : ''}`, description: `Stream <code>${entityName}</code> changes in the database such as creation or update${isSSE === true ? ' with Server Sent Events' : ''}.`, parameters: [ { in: 'path', name: 'model', description: 'Model name', schema: { type: 'string', example: 'users', enum: [ 'all', ...Array.from(models.MODELS.keys()).filter((m) => models.isInternalModel(m) === false), ], }, required: true, }, { in: 'path', name: 'source', description: 'Data source to stream', schema: { type: 'string', enum: ['entities', 'events'], example: 'entities', }, required: true, }, { in: 'header', name: 'output', description: 'Expected output', schema: { type: 'string', enum: ['entity', 'raw'], example: 'entity', }, required: false, }, ], ...(isSSE === false && { requestBody: { content: { [MIME_APPLICATION_JSON]: { schema: { type: 'array', items: { type: 'object', }, default: [], example: [ { $match: { 'fullDocument.firstname': 'John', }, }, ], }, }, }, }, }), responses: { 200: { description: 'Stream of JSON objects', content: { [isSSE === true ? 'text/event-stream' : MIME_APPLICATION_JSON]: { schema: { type: 'array', items: { type: 'object', }, example: [ { firstname: 'John', }, ], }, }, }, }, 400: components_1.default.responses[400], 404: components_1.default.responses[404], }, }); } exports.stream = stream; function createModel(model, links) { const schema = model.getSchema(); const event = schema.events[c.EVENT_TYPE_CREATED]['0_0_0']; const required = (0, filter_1.default)(event.required, (r) => !['v', 'type'].includes(r)); const entityName = getEntityName(model, true); const routeSpec = (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`create_${entityName}`), summary: event.title || `Create a new ${entityName}`, description: event.description || `Create a new <code>${entityName}</code> in the database.`, requestBody: { content: { [MIME_APPLICATION_JSON]: { schema: { ...(0, omit_1.default)(event, 'handler'), properties: { ...(0, omit_1.default)(event.properties, 'v', 'type', 'version', 'json_patch', 'created_at', 'updated_at', model.getIsReadonlyProperty(model.getModelConfig()), model.getIsArchivedProperty(model.getModelConfig()), model.getIsDeletedProperty(model.getModelConfig())), }, required: required.length ? required : undefined, }, }, }, }, responses: { 200: { description: 'Entity successfully created', content: { [MIME_APPLICATION_JSON]: { schema: { $ref: `#/components/schemas/${entityName}`, }, }, }, links: buildLinks(links), }, 400: { ...components_1.default.responses[400], description: 'Invalid Model / Event schema validation error', }, 409: components_1.default.responses[409], }, }); routeSpec.description += showHandler(event); const originalSchema = model.getOriginalSchema(); if (originalSchema) { const originalEvent = (0, get_1.default)(originalSchema, `events.${c.EVENT_TYPE_CREATED}.0_0_0`, {}); routeSpec.requestBody.content[MIME_APPLICATION_JSON].schema.properties = { ...routeSpec.requestBody.content[MIME_APPLICATION_JSON].schema.properties, ...(0, omit_1.default)(originalEvent.properties, 'v', 'type', 'version', 'json_patch', 'created_at', 'updated_at'), }; } return routeSpec; } exports.createModel = createModel; function updateModel(model, links) { const schema = model.getSchema(); const event = schema.events[c.EVENT_TYPE_UPDATED]['0_0_0']; const required = (0, filter_1.default)(event.required, (r) => !['v', 'type'].includes(r)); const entityName = getEntityName(model, true); const routeSpec = (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`update_${entityName}`), summary: event.title || `Update a ${entityName}`, description: event.description || `Update an existing <code>${entityName}</code> already present in the database.`, parameters: [ { in: 'path', name: model.getCorrelationField(), description: 'Correlation id', schema: c.COMPONENT_CORRELATION_ID, required: true, }, ], requestBody: { content: { [MIME_APPLICATION_JSON]: { schema: { ...(0, omit_1.default)(event, 'handler'), properties: { ...(0, omit_1.default)(event.properties, 'v', 'type', 'version', 'json_patch', 'created_at', 'updated_at', model.getIsReadonlyProperty(model.getModelConfig()), model.getIsArchivedProperty(model.getModelConfig()), model.getIsDeletedProperty(model.getModelConfig())), }, required: required.length ? required : undefined, }, }, }, }, responses: { 200: { description: 'Entity successfully updated', content: { [MIME_APPLICATION_JSON]: { schema: { $ref: `#/components/schemas/${entityName}`, }, }, }, links: buildLinks(links), }, 400: { ...components_1.default.responses[400], description: 'Invalid Model / Event schema validation error', }, 409: components_1.default.responses[409], 422: components_1.default.responses[422], }, }); routeSpec.description += showHandler(event); const originalSchema = model.getOriginalSchema(); if (originalSchema) { const originalEvent = (0, get_1.default)(originalSchema, `events.${c.EVENT_TYPE_UPDATED}.0_0_0`, {}); routeSpec.requestBody.content[MIME_APPLICATION_JSON].schema.properties = { ...routeSpec.requestBody.content[MIME_APPLICATION_JSON].schema.properties, ...(0, omit_1.default)(originalEvent.properties, 'v', 'type', 'version', 'json_patch', 'created_at', 'updated_at'), }; } return routeSpec; } exports.updateModel = updateModel; function patchModel(model, links) { const schema = model.getSchema(); const event = schema.events[c.EVENT_TYPE_PATCHED]['0_0_0']; const entityName = getEntityName(model, true); const routeSpec = (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`patch_${entityName}`), summary: event.title || `Patch a ${entityName}`, description: event.description || `Patch an existing <code>${entityName}</code> already present in the database.`, parameters: [ { in: 'path', name: model.getCorrelationField(), description: 'Correlation id', schema: c.COMPONENT_CORRELATION_ID, required: true, }, ], requestBody: { content: { [MIME_APPLICATION_JSON]: { schema: { type: 'object', required: ['json_patch'], additionalProperties: false, properties: { json_patch: event.properties.json_patch, }, }, }, }, }, responses: { 200: { description: 'Entity successfully patched', content: { [MIME_APPLICATION_JSON]: { schema: { $ref: `#/components/schemas/${entityName}`, }, }, }, links: buildLinks(links), }, 400: { ...components_1.default.responses[400], description: 'Invalid Model / Event schema validation error', }, 409: components_1.default.responses[409], 422: components_1.default.responses[422], }, }); routeSpec.description += showHandler(event); return routeSpec; } exports.patchModel = patchModel; function getModels(model, links) { const modelConfig = model.getModelConfig(); const originalSchema = model.getOriginalSchema(); const schema = model.getSchema(); const entityName = getEntityName(model); const indexedFields = modelConfig.indexes?.reduce((current, index) => [...current, ...Object.keys(index.fields)], [modelConfig.correlation_field]); const parameters = Object.keys(schema.model.properties) .filter((key) => { return ![ model.getIsArchivedProperty(modelConfig), model.getIsDeletedProperty(modelConfig), ].includes(key); }) .map((key) => { const isIndexed = indexedFields?.includes(key); const paramSchema = { // Remove default value in the GET find query parameters: ...(0, omit_1.default)(schema.model.properties[key], 'default'), description: `${isIndexed ? '<code>index</code> ' : ''}${schema.model.properties[key].description ?? ''}`, }; const _schema = { anyOf: [ paramSchema, { type: 'array', items: paramSchema, }, { type: 'object', }, ], }; return { in: 'query', name: key, description: `${isIndexed ? '<code>index</code> ' : ''}${schema.model.properties[key].description ?? ''}`, schema: _schema, required: false, }; }); // Raw queries support: parameters.push({ in: 'query', name: '_q', description: 'MongoDb query in JSON stringified', schema: { type: 'string', }, }, { in: 'query', name: '_must_hash', description: 'Do we need to hash query values before find results if needed?', schema: { type: 'boolean', }, }, { in: 'header', name: 'page', ...components_1.default.headers['pagination-page'], }, { in: 'header', name: 'page-size', ...components_1.default.headers['pagination-size'], }, { in: 'header', name: 'decrypt', description: 'should we decipher the value', schema: { type: 'string', enum: ['true', 'false'], }, }); return (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`GET_${entityName}`), summary: `Find ${entityName}`, description: `Find <code>${entityName}</code> present in the database.`, parameters, responses: { 200: { description: 'List of entities', content: { [MIME_APPLICATION_JSON]: { schema: { type: 'array', items: { $ref: `#/components/schemas/${getEntityName(model, true)}`, }, }, }, }, headers: { 'correlation-field': { description: 'Correlation field of the model', schema: { type: 'string', }, }, page: { ...components_1.default.headers['pagination-page'], }, 'page-size': { ...components_1.default.headers['pagination-size'], }, 'page-count': { ...components_1.default.headers['pagination-count'], }, count: { description: 'Total number of items', schema: { type: 'integer', minimum: 0, }, }, }, links: buildLinks(links), }, 400: components_1.default.responses[400], }, }); } exports.getModels = getModels; function getModel(model, links) { const entityName = getEntityName(model, true); return (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`GET_${entityName}`), summary: `Get a ${entityName}`, description: `Get a specific <code>${entityName}</code> uniquely identified by its <code>${model.getCorrelationField()}</code>.`, parameters: [ { in: 'path', name: model.getCorrelationField(), description: 'Correlation id', schema: c.COMPONENT_CORRELATION_ID, required: true, }, { in: 'header', name: 'decrypt', description: 'should we decipher the value', schema: { type: 'string', enum: ['true', 'false'], }, }, ], responses: { 200: { description: 'Entity successfully fetched', content: { [MIME_APPLICATION_JSON]: { schema: { $ref: `#/components/schemas/${entityName}`, }, }, }, links: buildLinks(links), }, 400: components_1.default.responses[400], 404: components_1.default.responses[404], }, }); } exports.getModel = getModel; function getModelAtVersion(model, links) { const entityName = getEntityName(model, true); return (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`${entityName}_AT_VERSION`), summary: `Get ${entityName} at version`, description: `Get a specific version for a <code>${entityName}</code>.`, parameters: [ { in: 'path', name: model.getCorrelationField(), description: 'Correlation id', schema: c.COMPONENT_CORRELATION_ID, required: true, }, { in: 'path', name: 'version', schema: { type: 'string', default: '0', }, required: true, description: 'Version', }, ], responses: { 200: { description: 'The model at the given version', content: { [MIME_APPLICATION_JSON]: { schema: { $ref: `#/components/schemas/${entityName}`, }, }, }, links: buildLinks(links), }, 400: components_1.default.responses[400], 404: components_1.default.responses[404], }, }); } exports.getModelAtVersion = getModelAtVersion; function restoreVersion(model, links) { const entityName = getEntityName(model, true); return (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`RESTORE_${entityName}_AT_VERSION`), summary: `Restore ${entityName} at version`, description: `Restore a specific version of the <code>${entityName}</code>.`, parameters: [ { in: 'path', name: model.getCorrelationField(), description: 'Correlation id', schema: c.COMPONENT_CORRELATION_ID, required: true, }, { in: 'path', name: 'version', schema: { type: 'integer', default: 0, }, required: true, description: 'Version', }, ], responses: { 200: { description: 'The model at the given version', content: { [MIME_APPLICATION_JSON]: { schema: { $ref: `#/components/schemas/${entityName}`, }, }, }, links: buildLinks(links), }, 400: components_1.default.responses[400], 404: components_1.default.responses[404], 409: components_1.default.responses[409], }, }); } exports.restoreVersion = restoreVersion; function getModelEvents(model, links, options = { skipCorrelationField: false }) { const entityName = getEntityName(model, true); let operationId = eventNametoCamelCase(`${entityName}_EVENTS`); let summary = `Get a ${entityName} events`; let description = `Get all events attached to a <code>${entityName}</code>.`; let parameters = [ { in: 'path', name: model.getCorrelationField(), description: 'Correlation id', schema: c.COMPONENT_CORRELATION_ID, required: true, }, ]; if (options.skipCorrelationField === true) { operationId = eventNametoCamelCase(`${entityName}_ALL_EVENTS`); summary = 'Get all events'; description = `Get all events created for this kind of entities whatever the value of the correlation ID`; parameters = []; } return (0, merge_1.default)({}, defaultSchema(model), { operationId, summary, description, parameters: [ ...parameters, { in: 'header', name: 'page', ...components_1.default.headers['pagination-page'], }, { in: 'header', name: 'page-size', ...components_1.default.headers['pagination-size'], }, ], responses: { 200: { description: 'Entity events successfully fetched', content: { [MIME_APPLICATION_JSON]: { schema: { type: 'array', items: { type: 'object', required: ['v', 'type', 'version'], properties: { type: c.COMPONENT_EVENT_TYPE, v: c.COMPONENT_EVENT_TYPE_VERSION, version: c.COMPONENT_EVENT_VERSION, }, }, }, }, }, links: buildLinks(links), }, 400: components_1.default.responses[400], 404: components_1.default.responses[404], }, }); } exports.getModelEvents = getModelEvents; function createModelSnapshot(model, links) { const entityName = getEntityName(model, true); return (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`CREATE_${entityName}_SNAPSHOT`), summary: `Create snapshot`, description: `Create a snapshot of a <code>${entityName}</code> to keep a frozen version in database.`, parameters: [ { in: 'path', name: model.getCorrelationField(), description: 'Correlation id', schema: c.COMPONENT_CORRELATION_ID, required: true, }, ], responses: { 200: { description: 'Snapshot successfully created', content: { [MIME_APPLICATION_JSON]: { schema: { $ref: `#/components/schemas/${entityName}`, }, }, }, links: buildLinks(links), }, 400: components_1.default.responses[400], 422: components_1.default.responses[422], }, }); } exports.createModelSnapshot = createModelSnapshot; function encrypt(model, links) { const originalSchema = model.getOriginalSchema(); const schema = model.getSchema(); const entityName = getEntityName(model, true); return (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`ENCRYPT_${entityName}`), summary: `Encrypt fields`, description: `Encrypt fields in <code>${entityName}</code>.`, requestBody: { content: { [MIME_APPLICATION_JSON]: { schema: { type: 'array', items: { type: 'object', properties: schema.model.properties, }, }, }, }, }, responses: { 200: { description: 'Encrypted fields', content: { [MIME_APPLICATION_JSON]: { schema: { type: 'array', items: { ...(0, omit_1.default)((0, get_1.default)(originalSchema, 'model'), 'handler'), required: undefined, }, }, }, }, links: buildLinks(links), }, 400: components_1.default.responses[400], 422: components_1.default.responses[422], }, }); } exports.encrypt = encrypt; function decrypt(model, links) { const originalSchema = model.getOriginalSchema(); const schema = model.getSchema(); const entityName = getEntityName(model, true); return (0, merge_1.default)({}, defaultSchema(model), { operationId: eventNametoCamelCase(`DECRYPT_${entityName}`), summary: `Decrypt encrypted fields`, description: `Decrypt fields in <code>${entityName}</code>.`, requestBody: { content: { [MIME_APPLICATION_JSON]: { schema: { type: 'array', items: { type: 'object', properties: schema.model.properties, }, }, }, }, }, responses: { 200: { description: 'Decrypted fields', content: { [MIME_APPLICATION_JSON]: { schema: { type: 'array', items: { ...(0, omit_1.default)((0, get_1.default)(originalSchema, 'model'), 'handler'), additionalProperties: true, required: undefined, }, }, }, }, links: buildLinks(links), }, 400: components_1.default.responses[400], 422: components_1.default.responses[422], }, }); } exports.decrypt = decrypt; //# sourceMappingURL=builder.js.map