UNPKG

nosql-constraints

Version:

Helpers to manage constrants (i.e. cascade delete) in a NoSQL database

103 lines (102 loc) 3.9 kB
import { ZodAny, ZodArray, ZodBoolean, ZodDate, ZodDefault, ZodDiscriminatedUnion, ZodEffects, ZodEnum, ZodLiteral, ZodNumber, ZodObject, ZodOptional, ZodString, ZodUnion } from 'zod'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const _DocumentSchemaChunkType2ZodType = { string: ZodString, number: ZodNumber, boolean: ZodBoolean, date: ZodDate, any: ZodAny }; export function zod(schema) { return new ZodAdapter(schema); } class ZodAdapter { #schema; constructor(schema) { this.#schema = schema; } extractChunks() { return extractChunks(undefined, undefined, this.#schema)[1]; } } function extractChunks(propertyKey, propertyPath, schema) { // First check primitive types for (const primitiveType of Object.keys(_DocumentSchemaChunkType2ZodType)) { const zodType = _DocumentSchemaChunkType2ZodType[primitiveType]; if (schema instanceof zodType) { return [ propertyKey, [{ path: propertyPath, type: primitiveType }] ]; } } if (schema instanceof ZodUnion || schema instanceof ZodDiscriminatedUnion) { return [ propertyKey, schema.options .map((option) => extractChunks(propertyKey, propertyPath, option)[1]) .flat() ]; } else if (schema instanceof ZodObject) { return [propertyKey, [extractChunkFromObject(propertyPath, schema)]]; } else if (schema instanceof ZodLiteral) { return [propertyKey, [{ path: propertyPath, type: 'literal', value: schema.value }]]; } else if (schema instanceof ZodArray) { return [ propertyKey ? `${propertyKey}[]` : '[]', extractChunksFromArray(propertyKey, propertyPath, schema) ]; } else if (schema instanceof ZodOptional) { const [chunkPropertyKey, chunkPropertyValue] = extractChunks(propertyKey, propertyPath, schema.unwrap()); return [chunkPropertyKey, chunkPropertyValue.map((chunk) => ({ ...chunk, optional: true }))]; } else if (schema instanceof ZodEnum) { return [ propertyKey, [ { path: propertyPath, type: 'enum', value: schema.options } ] ]; } else if (schema instanceof ZodDefault) { const [chunkPropertyKey, chunkPropertyValue] = extractChunks(propertyKey, propertyPath, schema.removeDefault()); return [ chunkPropertyKey, chunkPropertyValue.map((chunk) => ({ ...chunk, default: schema._def.defaultValue() })) ]; } else if (schema instanceof ZodEffects) { const [chunkPropertyKey, chunkPropertyValue] = extractChunks(propertyKey, propertyPath, schema.innerType()); return [chunkPropertyKey, chunkPropertyValue]; } else { throw new Error(`Unsupported schema type: ${schema.constructor.name} at ${propertyPath} with key ${propertyKey}`); } } function extractChunkFromObject(propertyPath, schema) { const properties = {}; for (const [key, value] of Object.entries(schema.shape)) { const _propertyPath = propertyPath ? `${propertyPath}.${key}` : key; const [chunkPropertyKey, chunkPropertyValue] = extractChunks(key, _propertyPath, value); properties[chunkPropertyKey] = chunkPropertyValue; } return { path: propertyPath, type: 'object', properties }; } function extractChunksFromArray(propertyKey, propertyPath, schema) { const _propertyKey = propertyKey ? `${propertyKey}[]` : '[]'; const _propertyPath = propertyPath ? `${propertyPath}[]` : '[]'; const [, chunkPropertyValue] = extractChunks(_propertyKey, _propertyPath, schema.element); return chunkPropertyValue; }