UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

116 lines (97 loc) 2.73 kB
import type Ajv from 'ajv'; import type { AnyObject, Event } from '../typings'; import util from 'util'; import assert from 'assert'; import * as telemetry from '@getanthill/telemetry'; /** * Returns available event types * @param {object} schema Event schemas * @returns {string[]} Event type available versions */ export function getEventTypes(events: AnyObject): string[] { return Object.keys(events); } /** * Returns available versions for an event type * @param {object} schema Event schemas * @param {object} event Object for which the type versions must be returned * @returns {integer[]} Event type available versions */ export function getEventTypeVersions(schema: AnyObject, event: Event) { const versions = Object.keys(schema.schema.events[event.type]).sort(); return { v: event.v, all: versions, }; } /** * Validate an event against a JSON Schema contract * @param {object} event The object to validate * @param {object} schema The event schema * @param {object} validator The JSON Schema validator * @throws AssertionError if invalid * @returns {void} - */ export function validate( event: Event, schema: AnyObject, validator: Ajv, throwOnInvalidEvent = true, ) { if (!schema.schema.events[event.type]) { const err = new assert.AssertionError({ message: 'Invalid event type', }); // @ts-ignore err.details = getEventTypes(schema.schema.events); throw err; } const eventSchema = event.v ? schema.schema.events[event.type][event.v] : undefined; if (!eventSchema) { const err = new assert.AssertionError({ message: 'Invalid event type version', }); // @ts-ignore err.details = getEventTypeVersions(schema, event); throw err; } const schemaId = `${event.type}.${event.v}`; let validate = validator.getSchema(schemaId); if (!validate) { validator.addSchema(eventSchema, schemaId); validate = validator.getSchema(schemaId); } const isValid = validate!(event); if (!isValid && throwOnInvalidEvent === true) { telemetry.logger.error('[Events] Validation error', { errors: validate!.errors, }); const assertionErrorPayload = { message: 'Event schema validation error', expected: null, actual: util.inspect( { schema: eventSchema, event, errors: validate!.errors, }, false, null, false, ), }; const err = new assert.AssertionError(assertionErrorPayload); // @ts-ignore err.details = validate.errors; // @ts-ignore err.details.push({ event, }); // @ts-ignore err.event = event; throw err; } return eventSchema; }