@yihuangdb/storage-object
Version:
A Node.js storage object layer library using Redis OM
421 lines • 12.3 kB
TypeScript
/**
* @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