UNPKG

mvom

Version:

Multivalue Object Mapper

134 lines (133 loc) 9.41 kB
import type { RequiredModelMeta } from './compileModel'; import type { BaseSchemaType, SchemaTypeDefinitionBoolean, SchemaTypeDefinitionISOCalendarDate, SchemaTypeDefinitionISOCalendarDateTime, SchemaTypeDefinitionISOTime, SchemaTypeDefinitionNumber, SchemaTypeDefinitionScalar, SchemaTypeDefinitionString, SchemaTypePath } from './schemaType'; import type { DataTransformer, DecryptFn, EncryptFn, FlattenObject, ISOCalendarDate, ISOCalendarDateTime, ISOTime, MarkRequired, MvRecord, Remap } from './types'; export type SchemaTypeDefinition = Schema | SchemaTypeDefinitionScalar | SchemaDefinition | SchemaTypeDefinitionArray; type SchemaTypeDefinitionArray = readonly [Schema] | readonly [SchemaTypeDefinitionScalar] | readonly [[SchemaTypeDefinitionScalar]] | readonly [SchemaDefinition]; export interface SchemaDefinition { [x: string]: SchemaTypeDefinition; } export interface SchemaForeignKeyDefinition { file: string | string[]; keysToIgnore?: string[]; entityName: string; } export interface SchemaCompoundForeignKeyDefinition { [key: number]: SchemaForeignKeyDefinition; splitCharacter: string; } type PickAndMark<T extends SchemaTypeDefinitionScalar, K extends keyof T = never> = MarkRequired<Pick<T, 'dictionary' | 'type' | K>, 'dictionary'>; export type DictionaryTypeDefinitionString = Remap<PickAndMark<SchemaTypeDefinitionString>>; export type DictionaryTypeDefinitionNumber = Remap<PickAndMark<SchemaTypeDefinitionNumber>>; export type DictionaryTypeDefinitionBoolean = Remap<PickAndMark<SchemaTypeDefinitionBoolean>>; export type DictionaryTypeDefinitionISOCalendarDate = Remap<PickAndMark<SchemaTypeDefinitionISOCalendarDate>>; export type DictionaryTypeDefinitionISOCalendarDateTime = Remap<PickAndMark<SchemaTypeDefinitionISOCalendarDateTime, 'dbFormat'>>; export type DictionaryTypeDefinitionISOTime = Remap<PickAndMark<SchemaTypeDefinitionISOTime, 'dbFormat'>>; export type DictionaryTypeDefinition = DictionaryTypeDefinitionString | DictionaryTypeDefinitionNumber | DictionaryTypeDefinitionBoolean | DictionaryTypeDefinitionISOCalendarDate | DictionaryTypeDefinitionISOCalendarDateTime | DictionaryTypeDefinitionISOTime; export type DictionaryDefinition = string | DictionaryTypeDefinition; export type DictionariesOption = Record<string, DictionaryDefinition>; export interface SchemaConstructorOptions<TDictionaries extends DictionariesOption> { dictionaries?: TDictionaries; idMatch?: RegExp; idForeignKey?: SchemaForeignKeyDefinition | SchemaCompoundForeignKeyDefinition; encrypt?: EncryptFn; decrypt?: DecryptFn; } interface DictionaryTypeDetail { dictionary: string; dataTransformer: DataTransformer; } /** Infer whether a schema type definition is required and union the result with null if it is not */ type InferRequiredType<TScalar, TType> = TScalar extends { required: true; } ? TType : TType | null; /** * Infer the output of a string type definition with specific handling for enumerations * If an enumeration is a readonly array, the return type of the definition will be a union * of the array elements. Otherwise, the return type will be a string. */ type InferStringType<TString extends SchemaTypeDefinitionString> = TString['enum'] extends readonly (infer E)[] ? E : string; /** * Infer the output type of an array schema definition * * Allows a constraint to be specified to filter the output to only include scalar arrays of a specific type */ type InferArraySchemaType<TSchemaTypeDefinition extends SchemaTypeDefinitionArray, TConstraint> = TSchemaTypeDefinition extends [infer TArrayDefinition] ? TArrayDefinition extends SchemaTypeDefinitionScalar ? TArrayDefinition extends TConstraint ? InferSchemaType<TArrayDefinition, TConstraint>[] : never : InferSchemaType<TArrayDefinition, TConstraint>[] : never; /** Infer the output type of a schema type definition */ type InferSchemaType<TSchemaTypeDefinition, TConstraint> = TSchemaTypeDefinition extends SchemaTypeDefinitionBoolean ? InferRequiredType<TSchemaTypeDefinition, boolean> : TSchemaTypeDefinition extends SchemaTypeDefinitionString ? InferRequiredType<TSchemaTypeDefinition, InferStringType<TSchemaTypeDefinition>> : TSchemaTypeDefinition extends SchemaTypeDefinitionNumber ? InferRequiredType<TSchemaTypeDefinition, number> : TSchemaTypeDefinition extends SchemaTypeDefinitionISOCalendarDate ? InferRequiredType<TSchemaTypeDefinition, ISOCalendarDate> : TSchemaTypeDefinition extends SchemaTypeDefinitionISOCalendarDateTime ? InferRequiredType<TSchemaTypeDefinition, ISOCalendarDateTime> : TSchemaTypeDefinition extends SchemaTypeDefinitionISOTime ? InferRequiredType<TSchemaTypeDefinition, ISOTime> : TSchemaTypeDefinition extends Schema<infer TSubSchemaDefinition> ? InferDocumentObject<Schema<TSubSchemaDefinition>, TConstraint> : TSchemaTypeDefinition extends SchemaTypeDefinitionArray ? InferArraySchemaType<TSchemaTypeDefinition, TConstraint> : TSchemaTypeDefinition extends SchemaDefinition ? InferDocumentObject<Schema<TSchemaTypeDefinition>, TConstraint> : never; /** * Infer the shape of a `Document` instance based upon the Schema it was instantiated with * * Allows a constraint to be specified to filter the output to only include properties of a specific type */ export type InferDocumentObject<TSchema extends Schema | null, TConstraint = SchemaTypeDefinition> = TSchema extends Schema<infer TSchemaDefinition> ? { [K in keyof TSchemaDefinition as TSchemaDefinition[K] extends TConstraint ? K : never]: InferSchemaType<TSchemaDefinition[K], TConstraint>; } : { _raw: MvRecord; }; /** Infer the shape of a `Model` instance based upon the Schema it was instantiated with */ export type InferModelObject<TSchema extends Schema | null> = Remap<InferDocumentObject<TSchema> & RequiredModelMeta>; /** * Flatten a document to string keyPath (i.e. { "foo.bar.baz": number }) * * Allows a constraint to be specified to filter the output to only include properties of a specific type */ export type FlattenDocument<TSchema extends Schema, TConstraint = SchemaTypeDefinition> = InferDocumentObject<TSchema, TConstraint> extends infer O extends Record<string, unknown> ? FlattenObject<O> : never; /** Infer the string keyPaths of a schema */ export type InferSchemaPaths<TSchema extends Schema> = Extract<keyof FlattenDocument<TSchema>, string>; /** Schema constructor */ declare class Schema<TSchemaDefinition extends SchemaDefinition = SchemaDefinition, TDictionaries extends DictionariesOption = Record<never, never>> { /** Key/value pairs of schema object path structure and associated multivalue dictionary ids */ dictPaths: Map<string, DictionaryTypeDetail>; /** The compiled schema object path structure */ readonly paths: Map<string, BaseSchemaType>; /** Foreign key definition for the record id */ readonly idForeignKey?: SchemaForeignKeyDefinition | SchemaCompoundForeignKeyDefinition; /** Regular expression to validate the record id against */ readonly idMatch?: RegExp; /** The schema definition passed to the constructor */ private readonly definition; /** Map of the compiled schema object position paths */ private readonly positionPaths; /** Map of all subdocument schemas represented in this Schema with parentPath as key */ private readonly subdocumentSchemas; /** Optional function to use for encryption of sensitive data */ private readonly encrypt?; /** Optional function to use for decryption of sensitive data */ private readonly decrypt?; constructor(definition: TSchemaDefinition, { dictionaries, idForeignKey, idMatch, encrypt, decrypt, }?: SchemaConstructorOptions<TDictionaries>); /** Get all multivalue data paths in this schema and its subdocument schemas */ getMvPaths(): SchemaTypePath[]; /** Transform the paths to positions */ transformPathsToDbPositions(paths: readonly string[]): number[]; /** * Transform the path to its ordinal position. Returning a '.' delimited string. Ex. "1.2.3" * @throws {Error} Invalid path provided */ transformPathToOrdinalPosition(path: InferSchemaPaths<Schema<TSchemaDefinition, TDictionaries>>): `${number}.${number}.${number}`; /** Build the dictionary path map for additional dictionaries provided as schema options */ private buildDictionaryPaths; /** * Get all positionPaths with path as key and position array as value including children schemas * e.g. parent field 'foo' has a child schema which has ["bar",[2]], the returned positionPath will be ["foo.bar",[2]]. */ private getPositionPaths; /** Construct instance member paths */ private buildPaths; /** * Cast an array to a schemaType * @throws {@link InvalidParameterError} An invalid parameter was passed to the function */ private castArray; /** * Cast a scalar definition to a scalar schemaType * @throws {@link InvalidParameterError} An invalid parameter was passed to the function */ private castScalar; /** Perform ancillary updates needed when a subdocument is in the Schema definition */ private handleSubDocumentSchemas; /** Determine if an object matches the structure of a scalar definition */ private isScalarDefinition; /** Merge subdocument schema dictionaries with the parent schema's dictionaries */ private mergeSchemaDictionaries; } export default Schema;