UNPKG

@yihuangdb/storage-object

Version:

A Node.js storage object layer library using Redis OM

421 lines 12.3 kB
/** * @module storage-schema * @description Enhanced Object-Oriented schema management for StorageObject. * Provides comprehensive schema definition, validation, migration, and transformation capabilities. * * @since 0.1.0 * @author StorageObject Team */ import { Schema } from 'redis-om'; import { RedisClientType } from 'redis'; /** * Field types supported by the storage system. * Each type maps to a specific Redis data type and indexing strategy. * * @typedef {string} FieldType * @property {'string'} string - Exact match string field * @property {'text'} text - Full-text searchable string field * @property {'number'} number - Numeric field with range queries * @property {'boolean'} boolean - Boolean field (true/false) * @property {'date'} date - Date field stored as timestamp * @property {'point'} point - Geographic point field (lon,lat) * @property {'string[]'} string[] - Array of strings * @property {'number[]'} number[] - Array of numbers */ export type FieldType = 'string' | 'number' | 'boolean' | 'date' | 'point' | 'string[]' | 'number[]' | 'text'; /** * Field configuration options */ export interface Field { /** Data type of the field */ type: FieldType; /** Whether the field should be indexed for searching */ indexed?: boolean; /** Whether the field should be sortable (text fields only) */ sortable?: boolean; /** Whether the field should be normalized (text fields only) */ normalized?: boolean; /** Separator for array fields */ separator?: string; /** Default value for the field */ default?: any; /** Whether the field is required */ required?: boolean; /** Validation function for the field */ validate?: (value: any) => boolean | string; /** Description of the field */ description?: string; } /** * Schema configuration object */ export interface SchemaConfig { [key: string]: Field | FieldType; } /** * Schema validation result */ export interface ValidationResult { /** Whether the data is valid */ valid: boolean; /** List of validation errors */ errors: Array<{ field: string; message: string; value?: any; }>; /** List of validation warnings */ warnings: Array<{ field: string; message: string; }>; } /** * Schema difference result */ export interface SchemaDiff { /** Fields added in the new schema */ added: string[]; /** Fields removed from the old schema */ removed: string[]; /** Fields with modified configurations */ modified: Array<{ field: string; oldConfig: Field | FieldType; newConfig: Field | FieldType; }>; /** Whether schemas are identical */ identical: boolean; } /** * Migration plan for schema changes */ export interface MigrationPlan { /** Steps to migrate from old to new schema */ steps: Array<{ action: 'add' | 'remove' | 'modify' | 'transform'; field?: string; description: string; transform?: (value: any) => any; }>; /** Whether migration is safe (no data loss) */ safe: boolean; /** Potential data loss warnings */ warnings: string[]; } /** * StorageSchema - Enhanced schema management with validation and migration capabilities. * * This class provides a comprehensive API for defining, validating, and transforming storage schemas. * It supports schema evolution through extension, merging, and migration planning. * * @class StorageSchema * @template T - Type of the entities described by this schema * @since 0.1.0 * * @example Basic Schema Definition * ```typescript * // Define a schema using the static factory method * const userSchema = StorageSchema.define({ * name: { type: 'string', indexed: true }, * email: { type: 'string', indexed: true, required: true }, * age: { type: 'number', indexed: true, validate: (v) => v >= 0 || 'Age must be positive' } * }); * * // Create storage with the schema fields * const storage = await StorageSystem.create('users', userSchema.getFields()); * ``` * * @example Schema Validation * ```typescript * // Validate data against schema * const result = userSchema.validate({ * name: 'John Doe', * email: 'john@example.com', * age: 25 * }); * * if (!result.valid) { * console.error('Validation errors:', result.errors); * } * ``` * * @example Schema Evolution * ```typescript * // Extend existing schema * const extendedSchema = userSchema.extend({ * role: { type: 'string', indexed: true, default: 'user' }, * tags: { type: 'string[]', separator: ',', indexed: true } * }); * * // Merge two schemas * const mergedSchema = userSchema.merge(profileSchema); * * // Plan migration between schemas * const migrationPlan = userSchema.migrateTo(newSchema); * console.log('Migration steps:', migrationPlan.steps); * ``` */ export declare class StorageSchema<T = Record<string, any>> { private schema; private fields; private dataStructure; private entityName; private versionManager?; private versionValidator; /** * Create a new StorageSchema instance * * @param entityName - Name of the entity * @param fields - Schema field configuration * @param useJSON - Whether to use JSON or HASH structure (default: true) */ constructor(entityName: string, fields: SchemaConfig, useJSON?: boolean); /** * Define a new schema using a static factory method * * @param config - Schema configuration * @param options - Schema options * @returns New StorageSchema instance * * @example * ```typescript * const schema = StorageSchema.define({ * name: 'string', * age: 'number', * email: { type: 'string', indexed: true } * }); * ``` */ static define<T = Record<string, any>>(config: SchemaConfig, options?: { entityName?: string; useJSON?: boolean; }): StorageSchema<T>; /** * Create a schema from a JSON string or object * * @param json - JSON string or parsed object * @param options - Schema options * @returns New StorageSchema instance * * @example * ```typescript * const schema = StorageSchema.from(jsonString); * ``` */ static from<T = Record<string, any>>(json: string | any, options?: { entityName?: string; useJSON?: boolean; }): StorageSchema<T>; /** * Validate data against the schema * * @param data - Data to validate * @returns Validation result * * @example * ```typescript * const result = schema.validate({ name: 'John', age: 30 }); * if (!result.valid) { * console.error('Validation errors:', result.errors); * } * ``` */ validate(data: any): ValidationResult; /** * Get all fields in the schema * * @returns Schema field configuration */ getFields(): SchemaConfig; /** * Get indexed fields in the schema * * @returns Array of indexed field names * * @example * ```typescript * const indexedFields = schema.getIndexedFields(); * console.log('Indexed fields:', indexedFields); * ``` */ getIndexedFields(): string[]; /** * Extend the schema with additional fields * * @param additionalFields - Fields to add to the schema * @returns New extended StorageSchema instance * * @example * ```typescript * const extendedSchema = schema.extend({ * createdAt: { type: 'date', indexed: true }, * updatedAt: { type: 'date', indexed: true } * }); * ``` */ extend(additionalFields: SchemaConfig): StorageSchema<T>; /** * Merge this schema with another schema * * @param otherSchema - Schema to merge with * @param strategy - Merge strategy ('override' or 'preserve') * @returns New merged StorageSchema instance * * @example * ```typescript * const mergedSchema = schema1.merge(schema2, 'override'); * ``` */ merge(otherSchema: StorageSchema, strategy?: 'override' | 'preserve'): StorageSchema<T>; /** * Convert the schema to a JSON representation * * @returns JSON object representing the schema * * @example * ```typescript * const json = schema.toJSON(); * console.log(JSON.stringify(json, null, 2)); * ``` */ toJSON(): any; /** * Create a deep copy of the schema * * @returns New cloned StorageSchema instance * * @example * ```typescript * const clonedSchema = schema.clone(); * ``` */ clone(): StorageSchema<T>; /** * Check if this schema is equal to another schema * * @param otherSchema - Schema to compare with * @returns True if schemas are equal, false otherwise * * @example * ```typescript * if (schema1.equals(schema2)) { * console.log('Schemas are identical'); * } * ``` */ equals(otherSchema: StorageSchema): boolean; /** * Find differences between this schema and another schema * * @param otherSchema - Schema to compare with * @returns Difference report * * @example * ```typescript * const diff = schema1.diff(schema2); * console.log('Added fields:', diff.added); * console.log('Removed fields:', diff.removed); * console.log('Modified fields:', diff.modified); * ``` */ diff(otherSchema: StorageSchema): SchemaDiff; /** * Create a migration plan to transform from this schema to another schema * * @param newSchema - Target schema to migrate to * @param options - Migration options * @returns Migration plan * * @example * ```typescript * const plan = oldSchema.migrateTo(newSchema, { * transformers: { * fullName: (data) => `${data.firstName} ${data.lastName}` * } * }); * * if (plan.safe) { * console.log('Migration is safe, no data loss'); * } else { * console.warn('Migration warnings:', plan.warnings); * } * ``` */ migrateTo(newSchema: StorageSchema, options?: { transformers?: Record<string, (data: any) => any>; allowDataLoss?: boolean; }): MigrationPlan; /** * Get the underlying Redis-OM schema * * @returns Redis-OM Schema instance */ getSchema(): Schema; /** * Check if the schema uses JSON structure * * @returns True if using JSON, false if using HASH */ isJSON(): boolean; /** * Get the entity name * * @returns Entity name */ getEntityName(): string; private normalizeFields; private getFieldConfig; private buildSchemaDefinition; private createFieldDefinition; private mapFieldType; private validateFieldType; private fieldsEqual; /** * Set the Redis client for version management * * @param client - Redis client instance */ setRedisClient(client: RedisClientType): Promise<void>; /** * Initialize version tracking for this schema * * @param client - Redis client instance */ initializeVersioning(client: RedisClientType): Promise<void>; /** * Track entity creation for versioning * * @param entityId - ID of the created entity */ trackEntityCreation(entityId: string): Promise<void>; /** * Update schema version if structure changed * * @param newFields - New schema fields * @returns True if version was incremented */ updateVersion(newFields: SchemaConfig): Promise<boolean>; /** * Get version metadata * * @returns Schema version metadata */ getVersionMetadata(): Promise<any>; /** * Get entity count from HyperLogLog * * @returns Approximate entity count */ getEntityCount(): Promise<number>; /** * Get version history * * @returns Array of version history entries */ getVersionHistory(): Promise<Array<{ version: number; timestamp: number; }>>; } //# sourceMappingURL=storage-schema.d.ts.map