484 lines
11 KiB
TypeScript
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>;
|
|
}
|