All files / adapters interface.ts

100% Statements 16/16
100% Branches 8/8
100% Functions 7/7
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135                                                                                                              11x 8x   8x             8x 8x   7x             8x             11x 11x 14x                   70x                           10x 7x     10x                   15x                 2x      
import { Type } from '../core/types';
 
/**
 * Interface for all database adapters
 */
export interface DatabaseAdapter {
  /**
   * Name of the database type (Neo4j, MongoDB, PostgreSQL, etc.)
   */
  readonly type: string;
  
  /**
   * Executes a query against the database
   * @param entityType The entity class
   * @param criteria Query criteria
   * @returns Promise resolving to entity or null
   */
  query<T>(entityType: Type<T>, criteria: object): Promise<T | null>;
  
  /**
   * Executes a query returning multiple results
   * @param entityType The entity class
   * @param criteria Query criteria
   * @returns Promise resolving to array of entities
   */
  queryMany<T>(entityType: Type<T>, criteria: object): Promise<T[]>;
  
  /**
   * Saves an entity to the database
   * @param entity The entity to save
   * @returns Promise resolving when save is complete
   */
  save<T extends object>(entity: T): Promise<void>;
  
  /**
   * Deletes an entity from the database
   * @param entityType The entity class
   * @param id The entity ID
   * @returns Promise resolving when delete is complete
   */
  delete<T>(entityType: Type<T>, id: string | number): Promise<void>;
  
  /**
   * Executes a native query specific to this database
   * @param query The native query string
   * @param params Parameters to substitute in the query
   * @returns Promise resolving to query results
   */
  runNativeQuery<T>(query: string, params?: any): Promise<T>;
}
 
/**
 * Decorator for specifying which database an entity extension is for
 * @param type Database type name
 */
export function DatabaseAdapter(type: string) {
  return function <T extends { new (...args: any[]): any }>(target: T): T {
    // Store the database type on the class
    Object.defineProperty(target, 'dbType', {
      value: type,
      writable: false
    });
    
    // Automatically register this adapter entity with the shared registry
    // We need to find the base class it extends
    const baseEntity = Object.getPrototypeOf(target);
    if (baseEntity && baseEntity.name) {
      // Register the adapter entity using the shared instance for backward compatibility
      DatabaseAdapterRegistry.getInstance().registerAdapterEntity(
        type,
        baseEntity,
        target
      );
    }
    
    return target;
  };
}
 
/**
 * Registry for database-specific entities
 */
export class DatabaseAdapterRegistry {
  private static sharedInstance: DatabaseAdapterRegistry = new DatabaseAdapterRegistry();
  private adapterEntities = new Map<string, Map<Function, Function>>();
  
  constructor() {}
  
  /**
   * Get the shared instance of the registry.
   * This provides backward compatibility for existing code.
   * New code should prefer direct instantiation when possible.
   */
  static getInstance(): DatabaseAdapterRegistry {
    return DatabaseAdapterRegistry.sharedInstance;
  }
  
  /**
   * Register a database-specific entity extension
   * @param dbType Database type
   * @param baseEntity Base entity class
   * @param adapterEntity Database-specific entity class
   */
  registerAdapterEntity(
    dbType: string,
    baseEntity: Function,
    adapterEntity: Function
  ): void {
    if (!this.adapterEntities.has(dbType)) {
      this.adapterEntities.set(dbType, new Map());
    }
    
    this.adapterEntities.get(dbType)!.set(baseEntity, adapterEntity);
  }
  
  /**
   * Get a database-specific entity extension
   * @param dbType Database type
   * @param baseEntity Base entity class
   * @returns Database-specific entity class or undefined
   */
  getAdapterEntity(dbType: string, baseEntity: Function): Function | undefined {
    return this.adapterEntities.get(dbType)?.get(baseEntity);
  }
  
  /**
   * Get all database-specific entities for a database type
   * @param dbType Database type
   * @returns Map of base entities to adapter entities
   */
  getAllAdapterEntities(dbType: string): Map<Function, Function> | undefined {
    return this.adapterEntities.get(dbType);
  }
}