import { ClsService } from "nestjs-cls"; import { DataModelInterface } from "../../../common/interfaces/datamodel.interface"; import { EntityDescriptor, RelationshipDef } from "../../../common/interfaces/entity.schema.interface"; import { AuditService } from "../../../foundations/audit/services/audit.service"; import { JsonApiDataInterface } from "../../jsonapi/interfaces/jsonapi.data.interface"; import { JsonApiService } from "../../jsonapi/services/jsonapi.service"; import { FilterCriterion, SortCriterion } from "../types/filter.criterion"; import { AbstractRepository } from "./abstract.repository"; /** * JSON:API relationship item with optional per-item meta for edge properties */ export interface JsonApiDTORelationshipItem { id: string; type: string; /** Per-item meta for edge properties on MANY relationships */ meta?: Record; } /** * JSON:API DTO data structure for create/update operations */ export interface JsonApiDTOData { id: string; type: string; attributes?: Record; relationships?: Record; }>; } /** * Abstract base service for Neo4j entities * * This class provides generic CRUD operations with JSON:API response formatting. * Works in conjunction with AbstractRepository and EntityDescriptor. * * @template T - The entity type (e.g., Glossary, Article, Topic) * @template R - The relationships record type for autocomplete support * * Usage pattern: * ```typescript * @Injectable() * export class GlossaryService extends AbstractService { * constructor( * jsonApiService: JsonApiService, * glossaryRepository: GlossaryRepository, * clsService: ClsService, * ) { * super(jsonApiService, glossaryRepository, clsService, GlossaryModel); * } * * // Generic methods (find, findById, create, put, patch, delete, findByRelated) are inherited * // Domain-specific methods can be added here * } * ``` */ export declare abstract class AbstractService = Record> { protected readonly jsonApiService: JsonApiService; protected readonly repository: AbstractRepository; protected readonly clsService: ClsService; protected readonly model: DataModelInterface; protected readonly auditService?: AuditService; /** Entity descriptor with field and relationship definitions */ protected abstract readonly descriptor: EntityDescriptor; constructor(jsonApiService: JsonApiService, repository: AbstractRepository, clsService: ClsService, model: DataModelInterface, auditService?: AuditService); /** * Find entities with optional search term, ordering, and pagination * Total count is automatically computed by Neo4jService when {CURSOR} is detected */ find(params: { query: any; term?: string; fetchAll?: boolean; orderBy?: string; }): Promise; /** * Find typed records directly (bypasses JSON:API serialisation). * For internal callers that need raw objects — e.g. the chatbot tool layer. */ findRecords(params: { filters?: FilterCriterion[]; orderByFields?: SortCriterion[]; limit?: number; term?: string; fetchAll?: boolean; }): Promise; /** * Find typed records across a relationship. Delegates to repository.findByRelated. */ findRelatedRecords(params: { relationship: keyof R & string; id: string | string[]; filters?: FilterCriterion[]; orderByFields?: SortCriterion[]; limit?: number; term?: string; }): Promise; /** * Find typed records connected to a related node via an arbitrary Cypher * edge, when the relationship is not declared in this entity's descriptor * (e.g., reverse-only relationships materialised on the catalog). Used by * the chatbot traverse/read-entity tools. Direction is from THIS node's * perspective. */ findRelatedRecordsByEdge(params: { cypherLabel: string; cypherDirection: "out" | "in"; relatedLabel: string; relatedId: string | string[]; filters?: FilterCriterion[]; orderByFields?: SortCriterion[]; limit?: number; }): Promise; /** * Find entity by ID */ findById(params: { id: string; }): Promise; /** * Find a typed record by id (bypasses JSON:API serialisation). * Used by internal agents that need raw objects. * Returns null when not found — does NOT throw like the public findById() does. */ findRecordById(params: { id: string; }): Promise; /** * Create a new entity * Override this method to map DTO fields to repository create params * * @param params - Repository create params derived from the DTO * @param included - Optional JSON:API "included" sidepost resources. Subclass overrides * may use this to create related entities in the same transaction. * The abstract implementation ignores it. */ create(params: { id: string; [key: string]: any; }, _included?: unknown[]): Promise; /** * Update an existing entity (full update) * Override this method to map DTO fields to repository put params * * @param params - Repository put params derived from the DTO * @param included - Optional JSON:API "included" sidepost resources. Subclass overrides * may use this to update related entities in the same transaction. * The abstract implementation ignores it. */ put(params: { id: string; [key: string]: any; }, _included?: unknown[]): Promise; /** * Partial update - only updates fields that are explicitly passed * Override this method to map DTO fields to repository patch params */ patch(params: { id: string; [key: string]: any; }): Promise; /** * Delete an entity * Validates ownership before deletion */ delete(params: { id: string; }): Promise; /** * Map JSON:API DTO data to repository params * Extracts attributes and relationships based on descriptor definitions */ protected mapDTOToParams(data: JsonApiDTOData, operation?: "create" | "put"): { id: string; [key: string]: any; }; /** * Create a new entity from JSON:API DTO * Automatically maps attributes and relationships based on descriptor * * @param params.data - The JSON:API primary data object * @param params.included - Optional JSON:API "included" sidepost resources forwarded * verbatim to {@link create}. Subclass overrides of `create` may consume them; * the abstract path silently ignores them. */ createFromDTO(params: { data: JsonApiDTOData; included?: unknown[]; }): Promise; /** * Update an existing entity from JSON:API DTO (full update) * Automatically maps attributes and relationships based on descriptor * * @param params.data - The JSON:API primary data object * @param params.included - Optional JSON:API "included" sidepost resources forwarded * verbatim to {@link put}. Subclass overrides of `put` may consume them; * the abstract path silently ignores them. */ putFromDTO(params: { data: JsonApiDTOData; included?: unknown[]; }): Promise; /** * Partial update from JSON:API DTO * Only updates fields that are explicitly present in the DTO */ patchFromDTO(params: { data: JsonApiDTOData; }): Promise; /** * Map JSON:API DTO data to patch params (only includes fields present in DTO) * Supports edge-only updates via meta.edgeOnly flag for MANY relationships */ protected mapDTOToPatchParams(data: JsonApiDTOData): { id: string; [key: string]: any; }; /** * Find entities by a related entity * Total count is automatically computed by Neo4jService when {CURSOR} is detected * * @example * ```typescript * // Find all glossaries by a specific author * await service.findByRelated({ relationship: 'author', id: 'author-123', query: req.query }); * * // Find all glossaries related to specific topics * await service.findByRelated({ relationship: 'topic', id: ['topic-1', 'topic-2'], query: req.query }); * ``` */ findByRelated(params: { relationship: keyof R & string; id: string | string[]; query: any; term?: string; fetchAll?: boolean; orderBy?: string; filters?: FilterCriterion[]; }): Promise; /** * Add items to a to-many relationship from JSON:API DTO * * @example * ```typescript * // Add photographs to a contact sheet with edge properties * await service.addToRelationshipFromDTO({ * id: 'contact-sheet-123', * relationship: 'photograph', * data: [ * { id: 'photo-1', type: 'photographs', meta: { position: 1, selected: true } }, * { id: 'photo-2', type: 'photographs', meta: { position: 2 } } * ] * }); * ``` */ addToRelationshipFromDTO(params: { id: string; relationship: keyof R & string; data: JsonApiDTORelationshipItem | JsonApiDTORelationshipItem[]; }): Promise; /** * Remove items from a to-many relationship * * @example * ```typescript * // Remove photographs from a contact sheet * await service.removeFromRelationshipFromDTO({ * id: 'contact-sheet-123', * relationship: 'photograph', * data: [ * { id: 'photo-1', type: 'photographs' }, * { id: 'photo-2', type: 'photographs' } * ] * }); * ``` */ removeFromRelationshipFromDTO(params: { id: string; relationship: keyof R & string; data: { id: string; type: string; }[]; }): Promise; } //# sourceMappingURL=abstract.service.d.ts.map