745 lines
22 KiB
TypeScript
745 lines
22 KiB
TypeScript
import { StoreType, ValidationResult, ShardingConfig, PinningConfig } from '../types/framework';
|
|
import { FieldConfig, RelationshipConfig, ValidationError } from '../types/models';
|
|
import { QueryBuilder } from '../query/QueryBuilder';
|
|
|
|
export abstract class BaseModel {
|
|
// Instance properties
|
|
public id: string = '';
|
|
public createdAt: number = 0;
|
|
public updatedAt: number = 0;
|
|
public _loadedRelations: Map<string, any> = new Map();
|
|
protected _isDirty: boolean = false;
|
|
protected _isNew: boolean = true;
|
|
|
|
// Static properties for model configuration
|
|
static modelName: string;
|
|
static storeType: StoreType = 'docstore';
|
|
static scope: 'user' | 'global' = 'global';
|
|
static sharding?: ShardingConfig;
|
|
static pinning?: PinningConfig;
|
|
static fields: Map<string, FieldConfig> = new Map();
|
|
static relationships: Map<string, RelationshipConfig> = new Map();
|
|
static hooks: Map<string, Function[]> = new Map();
|
|
|
|
constructor(data: any = {}) {
|
|
// Generate ID first
|
|
this.id = this.generateId();
|
|
|
|
// Apply field defaults first
|
|
this.applyFieldDefaults();
|
|
|
|
// Then apply provided data, but only for properties that are explicitly provided
|
|
if (data && typeof data === 'object') {
|
|
Object.keys(data).forEach((key) => {
|
|
if (key !== '_loadedRelations' && key !== '_isDirty' && key !== '_isNew' && data[key] !== undefined) {
|
|
// Always set directly - the Field decorator's setter will handle validation and transformation
|
|
(this as any)[key] = data[key];
|
|
}
|
|
});
|
|
|
|
// Mark as existing if it has an ID in the data
|
|
if (data.id) {
|
|
this._isNew = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Core CRUD operations
|
|
async save(): Promise<this> {
|
|
await this.validate();
|
|
|
|
if (this._isNew) {
|
|
await this.beforeCreate();
|
|
|
|
// Generate ID if not provided
|
|
if (!this.id) {
|
|
this.id = this.generateId();
|
|
}
|
|
|
|
this.createdAt = Date.now();
|
|
this.updatedAt = this.createdAt;
|
|
|
|
// Save to database (will be implemented when database manager is ready)
|
|
await this._saveToDatabase();
|
|
|
|
this._isNew = false;
|
|
this.clearModifications();
|
|
|
|
await this.afterCreate();
|
|
} else if (this._isDirty) {
|
|
await this.beforeUpdate();
|
|
|
|
this.updatedAt = Date.now();
|
|
|
|
// Update in database
|
|
await this._updateInDatabase();
|
|
|
|
this.clearModifications();
|
|
|
|
await this.afterUpdate();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
static async create<T extends BaseModel>(this: new (data?: any) => T, data: any): Promise<T> {
|
|
const instance = new this(data);
|
|
return await instance.save();
|
|
}
|
|
|
|
static async get<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
id: string,
|
|
): Promise<T | null> {
|
|
return await this.findById(id);
|
|
}
|
|
|
|
static async findById<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
id: string,
|
|
): Promise<T | null> {
|
|
// Use the mock framework for testing
|
|
const framework = (globalThis as any).__debrosFramework || this.getMockFramework();
|
|
if (!framework) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const modelClass = this as any;
|
|
let data = null;
|
|
|
|
if (modelClass.scope === 'user') {
|
|
// For user-scoped models, we would need userId - for now, try global
|
|
const database = await framework.databaseManager?.getGlobalDatabase?.(modelClass.modelName || modelClass.name);
|
|
if (database && framework.databaseManager?.getDocument) {
|
|
data = await framework.databaseManager.getDocument(database, modelClass.storeType, id);
|
|
}
|
|
} else {
|
|
if (modelClass.sharding) {
|
|
const shard = framework.shardManager?.getShardForKey?.(modelClass.modelName || modelClass.name, id);
|
|
if (shard && framework.databaseManager?.getDocument) {
|
|
data = await framework.databaseManager.getDocument(shard.database, modelClass.storeType, id);
|
|
}
|
|
} else {
|
|
const database = await framework.databaseManager?.getGlobalDatabase?.(modelClass.modelName || modelClass.name);
|
|
if (database && framework.databaseManager?.getDocument) {
|
|
data = await framework.databaseManager.getDocument(database, modelClass.storeType, id);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data) {
|
|
const instance = new this(data);
|
|
instance._isNew = false;
|
|
instance.clearModifications();
|
|
return instance;
|
|
}
|
|
|
|
return null;
|
|
} catch (error) {
|
|
console.error('Failed to find by ID:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static async find<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
id: string,
|
|
): Promise<T> {
|
|
const result = await this.get(id);
|
|
if (!result) {
|
|
throw new Error(`${this.name} with id ${id} not found`);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
async update(data: Partial<this>): Promise<this> {
|
|
Object.assign(this, data);
|
|
this._isDirty = true;
|
|
return await this.save();
|
|
}
|
|
|
|
async delete(): Promise<boolean> {
|
|
await this.beforeDelete();
|
|
|
|
// Delete from database (will be implemented when database manager is ready)
|
|
const success = await this._deleteFromDatabase();
|
|
|
|
if (success) {
|
|
await this.afterDelete();
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Query operations (return QueryBuilder instances)
|
|
static where<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
field: string,
|
|
operator: string,
|
|
value: any,
|
|
): QueryBuilder<T> {
|
|
return new QueryBuilder<T>(this as any).where(field, operator, value);
|
|
}
|
|
|
|
static whereIn<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
field: string,
|
|
values: any[],
|
|
): QueryBuilder<T> {
|
|
return new QueryBuilder<T>(this as any).whereIn(field, values);
|
|
}
|
|
|
|
static orderBy<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
field: string,
|
|
direction: 'asc' | 'desc' = 'asc',
|
|
): QueryBuilder<T> {
|
|
return new QueryBuilder<T>(this as any).orderBy(field, direction);
|
|
}
|
|
|
|
static limit<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
count: number,
|
|
): QueryBuilder<T> {
|
|
return new QueryBuilder<T>(this as any).limit(count);
|
|
}
|
|
|
|
static async all<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
): Promise<T[]> {
|
|
return await new QueryBuilder<T>(this as any).exec();
|
|
}
|
|
|
|
static async findAll<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
): Promise<T[]> {
|
|
return await this.all();
|
|
}
|
|
|
|
static async findOne<T extends BaseModel>(
|
|
this: typeof BaseModel & (new (data?: any) => T),
|
|
criteria: any,
|
|
): Promise<T | null> {
|
|
const query = new QueryBuilder<T>(this as any);
|
|
|
|
// Apply criteria as where clauses
|
|
Object.keys(criteria).forEach(key => {
|
|
query.where(key, '=', criteria[key]);
|
|
});
|
|
|
|
const results = await query.limit(1).exec();
|
|
return results.length > 0 ? results[0] : null;
|
|
}
|
|
|
|
// Relationship operations
|
|
async load(relationships: string[]): Promise<this> {
|
|
const framework = this.getFrameworkInstance();
|
|
if (!framework?.relationshipManager) {
|
|
console.warn('RelationshipManager not available, skipping relationship loading');
|
|
return this;
|
|
}
|
|
|
|
await framework.relationshipManager.eagerLoadRelationships([this], relationships);
|
|
return this;
|
|
}
|
|
|
|
async loadRelation(relationName: string): Promise<any> {
|
|
// Check if already loaded
|
|
if (this._loadedRelations.has(relationName)) {
|
|
return this._loadedRelations.get(relationName);
|
|
}
|
|
|
|
const framework = this.getFrameworkInstance();
|
|
if (!framework?.relationshipManager) {
|
|
console.warn('RelationshipManager not available, cannot load relationship');
|
|
return null;
|
|
}
|
|
|
|
return await framework.relationshipManager.loadRelationship(this, relationName);
|
|
}
|
|
|
|
// Advanced relationship loading methods
|
|
async loadRelationWithConstraints(
|
|
relationName: string,
|
|
constraints: (query: any) => any,
|
|
): Promise<any> {
|
|
const framework = this.getFrameworkInstance();
|
|
if (!framework?.relationshipManager) {
|
|
console.warn('RelationshipManager not available, cannot load relationship');
|
|
return null;
|
|
}
|
|
|
|
return await framework.relationshipManager.loadRelationship(this, relationName, {
|
|
constraints,
|
|
});
|
|
}
|
|
|
|
async reloadRelation(relationName: string): Promise<any> {
|
|
// Clear cached relationship
|
|
this._loadedRelations.delete(relationName);
|
|
|
|
const framework = this.getFrameworkInstance();
|
|
if (framework?.relationshipManager) {
|
|
framework.relationshipManager.invalidateRelationshipCache(this, relationName);
|
|
}
|
|
|
|
return await this.loadRelation(relationName);
|
|
}
|
|
|
|
getLoadedRelations(): string[] {
|
|
return Array.from(this._loadedRelations.keys());
|
|
}
|
|
|
|
isRelationLoaded(relationName: string): boolean {
|
|
return this._loadedRelations.has(relationName);
|
|
}
|
|
|
|
getRelation(relationName: string): any {
|
|
return this._loadedRelations.get(relationName);
|
|
}
|
|
|
|
setRelation(relationName: string, value: any): void {
|
|
this._loadedRelations.set(relationName, value);
|
|
}
|
|
|
|
clearRelation(relationName: string): void {
|
|
this._loadedRelations.delete(relationName);
|
|
}
|
|
|
|
// Serialization
|
|
toJSON(): any {
|
|
const result: any = {};
|
|
const modelClass = this.constructor as typeof BaseModel;
|
|
|
|
// Include all field values using their getters
|
|
for (const [fieldName] of modelClass.fields) {
|
|
result[fieldName] = (this as any)[fieldName];
|
|
}
|
|
|
|
// Include basic properties
|
|
result.id = this.id;
|
|
result.createdAt = this.createdAt;
|
|
result.updatedAt = this.updatedAt;
|
|
|
|
// Include loaded relations
|
|
this._loadedRelations.forEach((value, key) => {
|
|
result[key] = value;
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
fromJSON(data: any): this {
|
|
if (!data) return this;
|
|
|
|
// Set basic properties
|
|
Object.keys(data).forEach((key) => {
|
|
if (key !== '_loadedRelations' && key !== '_isDirty' && key !== '_isNew') {
|
|
(this as any)[key] = data[key];
|
|
}
|
|
});
|
|
|
|
// Mark as existing if it has an ID
|
|
if (this.id) {
|
|
this._isNew = false;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
// Validation
|
|
async validate(): Promise<ValidationResult> {
|
|
const errors: string[] = [];
|
|
const modelClass = this.constructor as typeof BaseModel;
|
|
|
|
// Validate each field
|
|
for (const [fieldName, fieldConfig] of modelClass.fields) {
|
|
const value = (this as any)[fieldName];
|
|
const fieldErrors = this.validateField(fieldName, value, fieldConfig);
|
|
errors.push(...fieldErrors);
|
|
}
|
|
|
|
const result = { valid: errors.length === 0, errors };
|
|
|
|
if (!result.valid) {
|
|
throw new ValidationError(errors);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private validateField(fieldName: string, value: any, config: FieldConfig): string[] {
|
|
const errors: string[] = [];
|
|
|
|
// Required validation
|
|
if (config.required && (value === undefined || value === null || value === '')) {
|
|
errors.push(`${fieldName} is required`);
|
|
return errors; // No point in further validation if required field is missing
|
|
}
|
|
|
|
// Skip further validation if value is empty and not required
|
|
if (value === undefined || value === null) {
|
|
return errors;
|
|
}
|
|
|
|
// Type validation
|
|
if (!this.isValidType(value, config.type)) {
|
|
errors.push(`${fieldName} must be of type ${config.type}`);
|
|
}
|
|
|
|
// Custom validation
|
|
if (config.validate) {
|
|
const customResult = config.validate(value);
|
|
if (customResult === false) {
|
|
errors.push(`${fieldName} failed custom validation`);
|
|
} else if (typeof customResult === 'string') {
|
|
errors.push(customResult);
|
|
}
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
private isValidType(value: any, expectedType: FieldConfig['type']): boolean {
|
|
switch (expectedType) {
|
|
case 'string':
|
|
return typeof value === 'string';
|
|
case 'number':
|
|
return typeof value === 'number' && !isNaN(value);
|
|
case 'boolean':
|
|
return typeof value === 'boolean';
|
|
case 'array':
|
|
return Array.isArray(value);
|
|
case 'object':
|
|
return typeof value === 'object' && !Array.isArray(value);
|
|
case 'date':
|
|
return value instanceof Date || (typeof value === 'number' && !isNaN(value));
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Hook methods (can be overridden by subclasses)
|
|
async beforeCreate(): Promise<void> {
|
|
await this.runHooks('beforeCreate');
|
|
}
|
|
|
|
async afterCreate(): Promise<void> {
|
|
await this.runHooks('afterCreate');
|
|
}
|
|
|
|
async beforeUpdate(): Promise<void> {
|
|
await this.runHooks('beforeUpdate');
|
|
}
|
|
|
|
async afterUpdate(): Promise<void> {
|
|
await this.runHooks('afterUpdate');
|
|
}
|
|
|
|
async beforeDelete(): Promise<void> {
|
|
await this.runHooks('beforeDelete');
|
|
}
|
|
|
|
async afterDelete(): Promise<void> {
|
|
await this.runHooks('afterDelete');
|
|
}
|
|
|
|
private async runHooks(hookName: string): Promise<void> {
|
|
const modelClass = this.constructor as typeof BaseModel;
|
|
const hookNames = modelClass.hooks.get(hookName) || [];
|
|
|
|
for (const hookMethodName of hookNames) {
|
|
const hookMethod = (this as any)[hookMethodName];
|
|
if (typeof hookMethod === 'function') {
|
|
await hookMethod.call(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Utility methods
|
|
private generateId(): string {
|
|
return Date.now().toString(36) + Math.random().toString(36).substr(2);
|
|
}
|
|
|
|
private applyFieldDefaults(): void {
|
|
const modelClass = this.constructor as typeof BaseModel;
|
|
|
|
for (const [fieldName, fieldConfig] of modelClass.fields) {
|
|
if (fieldConfig.default !== undefined) {
|
|
const privateKey = `_${fieldName}`;
|
|
const hasProperty = (this as any).hasOwnProperty(privateKey);
|
|
const currentValue = (this as any)[privateKey];
|
|
|
|
// Always apply default value to private field if it's not set
|
|
if (!hasProperty || currentValue === undefined) {
|
|
// Apply default value to private field
|
|
if (typeof fieldConfig.default === 'function') {
|
|
(this as any)[privateKey] = fieldConfig.default();
|
|
} else {
|
|
(this as any)[privateKey] = fieldConfig.default;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Field modification tracking
|
|
private _modifiedFields: Set<string> = new Set();
|
|
|
|
markFieldAsModified(fieldName: string): void {
|
|
this._modifiedFields.add(fieldName);
|
|
this._isDirty = true;
|
|
}
|
|
|
|
getModifiedFields(): string[] {
|
|
return Array.from(this._modifiedFields);
|
|
}
|
|
|
|
isFieldModified(fieldName: string): boolean {
|
|
return this._modifiedFields.has(fieldName);
|
|
}
|
|
|
|
clearModifications(): void {
|
|
this._modifiedFields.clear();
|
|
this._isDirty = false;
|
|
}
|
|
|
|
// Database operations integrated with DatabaseManager
|
|
private async _saveToDatabase(): Promise<void> {
|
|
const framework = this.getFrameworkInstance();
|
|
if (!framework) {
|
|
console.warn('Framework not initialized, skipping database save');
|
|
return;
|
|
}
|
|
|
|
const modelClass = this.constructor as typeof BaseModel;
|
|
|
|
try {
|
|
if (modelClass.scope === 'user') {
|
|
// For user-scoped models, we need a userId
|
|
const userId = (this as any).userId;
|
|
if (!userId) {
|
|
throw new Error('User-scoped models must have a userId field');
|
|
}
|
|
|
|
const database = await framework.databaseManager.getUserDatabase(
|
|
userId,
|
|
modelClass.modelName,
|
|
);
|
|
await framework.databaseManager.addDocument(database, modelClass.storeType, this.toJSON());
|
|
} else {
|
|
// For global models
|
|
if (modelClass.sharding) {
|
|
// Use sharded database
|
|
const shard = framework.shardManager.getShardForKey(modelClass.modelName, this.id);
|
|
await framework.databaseManager.addDocument(
|
|
shard.database,
|
|
modelClass.storeType,
|
|
this.toJSON(),
|
|
);
|
|
} else {
|
|
// Use single global database
|
|
const database = await framework.databaseManager.getGlobalDatabase(modelClass.modelName);
|
|
await framework.databaseManager.addDocument(database, modelClass.storeType, this.toJSON());
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to save to database:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
private async _updateInDatabase(): Promise<void> {
|
|
const framework = this.getFrameworkInstance();
|
|
if (!framework) {
|
|
console.warn('Framework not initialized, skipping database update');
|
|
return;
|
|
}
|
|
|
|
const modelClass = this.constructor as typeof BaseModel;
|
|
|
|
try {
|
|
if (modelClass.scope === 'user') {
|
|
const userId = (this as any).userId;
|
|
if (!userId) {
|
|
throw new Error('User-scoped models must have a userId field');
|
|
}
|
|
|
|
const database = await framework.databaseManager.getUserDatabase(
|
|
userId,
|
|
modelClass.modelName,
|
|
);
|
|
await framework.databaseManager.updateDocument(
|
|
database,
|
|
modelClass.storeType,
|
|
this.id,
|
|
this.toJSON(),
|
|
);
|
|
} else {
|
|
if (modelClass.sharding) {
|
|
const shard = framework.shardManager.getShardForKey(modelClass.modelName, this.id);
|
|
await framework.databaseManager.updateDocument(
|
|
shard.database,
|
|
modelClass.storeType,
|
|
this.id,
|
|
this.toJSON(),
|
|
);
|
|
} else {
|
|
const database = await framework.databaseManager.getGlobalDatabase(modelClass.modelName);
|
|
await framework.databaseManager.updateDocument(
|
|
database,
|
|
modelClass.storeType,
|
|
this.id,
|
|
this.toJSON(),
|
|
);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to update in database:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
private async _deleteFromDatabase(): Promise<boolean> {
|
|
const framework = this.getFrameworkInstance();
|
|
if (!framework) {
|
|
console.warn('Framework not initialized, skipping database delete');
|
|
return false;
|
|
}
|
|
|
|
const modelClass = this.constructor as typeof BaseModel;
|
|
|
|
try {
|
|
if (modelClass.scope === 'user') {
|
|
const userId = (this as any).userId;
|
|
if (!userId) {
|
|
throw new Error('User-scoped models must have a userId field');
|
|
}
|
|
|
|
const database = await framework.databaseManager.getUserDatabase(
|
|
userId,
|
|
modelClass.modelName,
|
|
);
|
|
await framework.databaseManager.deleteDocument(database, modelClass.storeType, this.id);
|
|
} else {
|
|
if (modelClass.sharding) {
|
|
const shard = framework.shardManager.getShardForKey(modelClass.modelName, this.id);
|
|
await framework.databaseManager.deleteDocument(
|
|
shard.database,
|
|
modelClass.storeType,
|
|
this.id,
|
|
);
|
|
} else {
|
|
const database = await framework.databaseManager.getGlobalDatabase(modelClass.modelName);
|
|
await framework.databaseManager.deleteDocument(database, modelClass.storeType, this.id);
|
|
}
|
|
}
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Failed to delete from database:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
private getFrameworkInstance(): any {
|
|
// This will be properly typed when DebrosFramework is created
|
|
const framework = (globalThis as any).__debrosFramework;
|
|
if (!framework) {
|
|
// Try to get mock framework for testing
|
|
const mockFramework = (this.constructor as any).getMockFramework?.();
|
|
return mockFramework;
|
|
}
|
|
return framework;
|
|
}
|
|
|
|
// Static methods for framework integration
|
|
static setStore(store: any): void {
|
|
(this as any)._store = store;
|
|
}
|
|
|
|
static setShards(shards: any[]): void {
|
|
(this as any)._shards = shards;
|
|
}
|
|
|
|
static getStore(): any {
|
|
return (this as any)._store;
|
|
}
|
|
|
|
static getShards(): any[] {
|
|
return (this as any)._shards || [];
|
|
}
|
|
|
|
static fromJSON<T extends BaseModel>(this: new (data?: any) => T, data: any): T {
|
|
const instance = new this();
|
|
Object.assign(instance, data);
|
|
return instance;
|
|
}
|
|
|
|
static query<T extends BaseModel>(this: typeof BaseModel & (new (data?: any) => T)): any {
|
|
const { QueryBuilder } = require('../query/QueryBuilder');
|
|
return new QueryBuilder(this);
|
|
}
|
|
|
|
// Mock framework for testing
|
|
static getMockFramework(): any {
|
|
if (typeof jest !== 'undefined') {
|
|
// Create a simple mock framework with shared mock database storage
|
|
if (!(globalThis as any).__mockDatabase) {
|
|
(globalThis as any).__mockDatabase = new Map();
|
|
}
|
|
|
|
const mockDatabase = {
|
|
_data: (globalThis as any).__mockDatabase,
|
|
async get(id: string) {
|
|
return this._data.get(id) || null;
|
|
},
|
|
async put(doc: any) {
|
|
const id = doc._id || doc.id;
|
|
this._data.set(id, doc);
|
|
return id;
|
|
},
|
|
async del(id: string) {
|
|
return this._data.delete(id);
|
|
},
|
|
async all() {
|
|
return Array.from(this._data.values());
|
|
}
|
|
};
|
|
|
|
return {
|
|
databaseManager: {
|
|
async getGlobalDatabase(_name: string) {
|
|
return mockDatabase;
|
|
},
|
|
async getUserDatabase(_userId: string, _name: string) {
|
|
return mockDatabase;
|
|
},
|
|
async getDocument(_database: any, _type: string, id: string) {
|
|
return await mockDatabase.get(id);
|
|
},
|
|
async addDocument(_database: any, _type: string, doc: any) {
|
|
return await mockDatabase.put(doc);
|
|
},
|
|
async updateDocument(_database: any, _type: string, id: string, doc: any) {
|
|
doc.id = id;
|
|
return await mockDatabase.put(doc);
|
|
},
|
|
async deleteDocument(_database: any, _type: string, id: string) {
|
|
return await mockDatabase.del(id);
|
|
},
|
|
async getAllDocuments(_database: any, _type: string) {
|
|
return await mockDatabase.all();
|
|
}
|
|
},
|
|
shardManager: {
|
|
getShardForKey(_modelName: string, _key: string) {
|
|
return { database: mockDatabase };
|
|
}
|
|
}
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
}
|