erp-suite/apps/shared-libs/core/interfaces/repository.interface.ts

484 lines
11 KiB
TypeScript

/**
* Repository Interface - Generic repository contract
*
* @module @erp-suite/core/interfaces
*/
import { ServiceContext, QueryOptions } from './base-service.interface';
import { PaginatedResult, PaginationOptions } from '../types/pagination.types';
/**
* Generic repository interface for data access
*
* This interface defines the contract for repository implementations,
* supporting both TypeORM and raw SQL approaches.
*
* @template T - Entity type
*
* @example
* ```typescript
* export class PartnerRepository implements IRepository<Partner> {
* async findById(ctx: ServiceContext, id: string): Promise<Partner | null> {
* // Implementation
* }
* }
* ```
*/
export interface IRepository<T> {
/**
* Find entity by ID
*/
findById(
ctx: ServiceContext,
id: string,
options?: QueryOptions,
): Promise<T | null>;
/**
* Find one entity by criteria
*/
findOne(
ctx: ServiceContext,
criteria: Partial<T>,
options?: QueryOptions,
): Promise<T | null>;
/**
* Find all entities with pagination
*/
findAll(
ctx: ServiceContext,
filters?: PaginationOptions & Partial<T>,
options?: QueryOptions,
): Promise<PaginatedResult<T>>;
/**
* Find multiple entities by criteria
*/
findMany(
ctx: ServiceContext,
criteria: Partial<T>,
options?: QueryOptions,
): Promise<T[]>;
/**
* Create new entity
*/
create(ctx: ServiceContext, data: Partial<T>): Promise<T>;
/**
* Create multiple entities
*/
createMany(ctx: ServiceContext, data: Partial<T>[]): Promise<T[]>;
/**
* Update existing entity
*/
update(ctx: ServiceContext, id: string, data: Partial<T>): Promise<T | null>;
/**
* Update multiple entities by criteria
*/
updateMany(
ctx: ServiceContext,
criteria: Partial<T>,
data: Partial<T>,
): Promise<number>;
/**
* Soft delete entity
*/
softDelete(ctx: ServiceContext, id: string): Promise<boolean>;
/**
* Hard delete entity
*/
hardDelete(ctx: ServiceContext, id: string): Promise<boolean>;
/**
* Delete multiple entities by criteria
*/
deleteMany(ctx: ServiceContext, criteria: Partial<T>): Promise<number>;
/**
* Count entities matching criteria
*/
count(
ctx: ServiceContext,
criteria?: Partial<T>,
options?: QueryOptions,
): Promise<number>;
/**
* Check if entity exists
*/
exists(
ctx: ServiceContext,
id: string,
options?: QueryOptions,
): Promise<boolean>;
/**
* Execute raw SQL query
*/
query<R = unknown>(
ctx: ServiceContext,
sql: string,
params: unknown[],
): Promise<R[]>;
/**
* Execute raw SQL query and return first result
*/
queryOne<R = unknown>(
ctx: ServiceContext,
sql: string,
params: unknown[],
): Promise<R | null>;
}
/**
* Read-only repository interface
*
* For repositories that only need read operations (e.g., views, reports)
*
* @template T - Entity type
*/
export interface IReadOnlyRepository<T> {
findById(
ctx: ServiceContext,
id: string,
options?: QueryOptions,
): Promise<T | null>;
findOne(
ctx: ServiceContext,
criteria: Partial<T>,
options?: QueryOptions,
): Promise<T | null>;
findAll(
ctx: ServiceContext,
filters?: PaginationOptions & Partial<T>,
options?: QueryOptions,
): Promise<PaginatedResult<T>>;
findMany(
ctx: ServiceContext,
criteria: Partial<T>,
options?: QueryOptions,
): Promise<T[]>;
count(
ctx: ServiceContext,
criteria?: Partial<T>,
options?: QueryOptions,
): Promise<number>;
exists(
ctx: ServiceContext,
id: string,
options?: QueryOptions,
): Promise<boolean>;
}
/**
* Write-only repository interface
*
* For repositories that only need write operations (e.g., event stores)
*
* @template T - Entity type
*/
export interface IWriteOnlyRepository<T> {
create(ctx: ServiceContext, data: Partial<T>): Promise<T>;
createMany(ctx: ServiceContext, data: Partial<T>[]): Promise<T[]>;
update(ctx: ServiceContext, id: string, data: Partial<T>): Promise<T | null>;
updateMany(
ctx: ServiceContext,
criteria: Partial<T>,
data: Partial<T>,
): Promise<number>;
softDelete(ctx: ServiceContext, id: string): Promise<boolean>;
hardDelete(ctx: ServiceContext, id: string): Promise<boolean>;
deleteMany(ctx: ServiceContext, criteria: Partial<T>): Promise<number>;
}
// ============================================================================
// Domain-Specific Repository Interfaces
// ============================================================================
/**
* User repository interface
*
* Extends the base repository with user-specific operations
*
* @example
* ```typescript
* export class UserRepository implements IUserRepository {
* async findByEmail(ctx: ServiceContext, email: string): Promise<User | null> {
* return this.findOne(ctx, { email });
* }
* }
* ```
*/
export interface IUserRepository extends IRepository<any> {
/**
* Find user by email address
*/
findByEmail(ctx: ServiceContext, email: string): Promise<any | null>;
/**
* Find users by tenant ID
*/
findByTenantId(ctx: ServiceContext, tenantId: string): Promise<any[]>;
/**
* Find active users only
*/
findActiveUsers(
ctx: ServiceContext,
filters?: PaginationOptions,
): Promise<PaginatedResult<any>>;
/**
* Update last login timestamp
*/
updateLastLogin(ctx: ServiceContext, userId: string): Promise<void>;
/**
* Update user password hash
*/
updatePasswordHash(
ctx: ServiceContext,
userId: string,
passwordHash: string,
): Promise<void>;
}
/**
* Tenant repository interface
*
* Extends the base repository with tenant-specific operations
*
* @example
* ```typescript
* export class TenantRepository implements ITenantRepository {
* async findBySlug(ctx: ServiceContext, slug: string): Promise<Tenant | null> {
* return this.findOne(ctx, { slug });
* }
* }
* ```
*/
export interface ITenantRepository extends IRepository<any> {
/**
* Find tenant by unique slug
*/
findBySlug(ctx: ServiceContext, slug: string): Promise<any | null>;
/**
* Find tenant by domain
*/
findByDomain(ctx: ServiceContext, domain: string): Promise<any | null>;
/**
* Find active tenants only
*/
findActiveTenants(
ctx: ServiceContext,
filters?: PaginationOptions,
): Promise<PaginatedResult<any>>;
/**
* Update tenant settings
*/
updateSettings(
ctx: ServiceContext,
tenantId: string,
settings: Record<string, unknown>,
): Promise<void>;
}
/**
* Audit log entry type
*/
export interface AuditLogEntry {
id?: string;
tenantId: string;
userId: string;
action: string;
entityType: string;
entityId: string;
changes?: Record<string, unknown>;
metadata?: Record<string, unknown>;
ipAddress?: string;
userAgent?: string;
timestamp: Date;
}
/**
* Audit repository interface
*
* Specialized repository for audit logging and compliance
*
* @example
* ```typescript
* export class AuditRepository implements IAuditRepository {
* async logAction(ctx: ServiceContext, entry: AuditLogEntry): Promise<void> {
* await this.create(ctx, entry);
* }
* }
* ```
*/
export interface IAuditRepository {
/**
* Log an audit entry
*/
logAction(ctx: ServiceContext, entry: AuditLogEntry): Promise<void>;
/**
* Find audit logs by entity
*/
findByEntity(
ctx: ServiceContext,
entityType: string,
entityId: string,
filters?: PaginationOptions,
): Promise<PaginatedResult<AuditLogEntry>>;
/**
* Find audit logs by user
*/
findByUser(
ctx: ServiceContext,
userId: string,
filters?: PaginationOptions,
): Promise<PaginatedResult<AuditLogEntry>>;
/**
* Find audit logs by tenant
*/
findByTenant(
ctx: ServiceContext,
tenantId: string,
filters?: PaginationOptions,
): Promise<PaginatedResult<AuditLogEntry>>;
/**
* Find audit logs by action type
*/
findByAction(
ctx: ServiceContext,
action: string,
filters?: PaginationOptions,
): Promise<PaginatedResult<AuditLogEntry>>;
/**
* Find audit logs within date range
*/
findByDateRange(
ctx: ServiceContext,
startDate: Date,
endDate: Date,
filters?: PaginationOptions,
): Promise<PaginatedResult<AuditLogEntry>>;
}
/**
* Configuration entry type
*/
export interface ConfigEntry {
id?: string;
tenantId?: string;
key: string;
value: unknown;
type: 'string' | 'number' | 'boolean' | 'json';
scope: 'system' | 'tenant' | 'module';
module?: string;
description?: string;
isEncrypted?: boolean;
updatedAt?: Date;
}
/**
* Config repository interface
*
* Specialized repository for application configuration
*
* @example
* ```typescript
* export class ConfigRepository implements IConfigRepository {
* async getValue<T>(ctx: ServiceContext, key: string): Promise<T | null> {
* const entry = await this.findByKey(ctx, key);
* return entry ? (entry.value as T) : null;
* }
* }
* ```
*/
export interface IConfigRepository {
/**
* Find configuration by key
*/
findByKey(
ctx: ServiceContext,
key: string,
scope?: 'system' | 'tenant' | 'module',
): Promise<ConfigEntry | null>;
/**
* Get typed configuration value
*/
getValue<T>(
ctx: ServiceContext,
key: string,
defaultValue?: T,
): Promise<T | null>;
/**
* Set configuration value
*/
setValue<T>(ctx: ServiceContext, key: string, value: T): Promise<void>;
/**
* Find all configurations by scope
*/
findByScope(
ctx: ServiceContext,
scope: 'system' | 'tenant' | 'module',
filters?: PaginationOptions,
): Promise<PaginatedResult<ConfigEntry>>;
/**
* Find all configurations by module
*/
findByModule(
ctx: ServiceContext,
module: string,
filters?: PaginationOptions,
): Promise<PaginatedResult<ConfigEntry>>;
/**
* Find all tenant-specific configurations
*/
findByTenant(
ctx: ServiceContext,
tenantId: string,
filters?: PaginationOptions,
): Promise<PaginatedResult<ConfigEntry>>;
/**
* Delete configuration by key
*/
deleteByKey(ctx: ServiceContext, key: string): Promise<boolean>;
/**
* Bulk update configurations
*/
bulkUpdate(ctx: ServiceContext, configs: ConfigEntry[]): Promise<void>;
}