import { OnModuleInit } from "@nestjs/common"; import { ClsService } from "nestjs-cls"; import { EntityDescriptor, RelationshipDef } from "../../../common/interfaces/entity.schema.interface"; import { JsonApiCursorInterface } from "../../jsonapi/interfaces/jsonapi.cursor.interface"; import { SecurityService } from "../../security/services/security.service"; import { Neo4jService } from "../services/neo4j.service"; import { FilterCriterion, SortCriterion } from "../types/filter.criterion"; /** * Abstract base repository for Neo4j entities * * This class provides generic CRUD operations using the schema-first EntityDescriptor pattern. * Fields and relationships are defined once in the descriptor, and everything else is derived. * * @template T - The entity type (e.g., Glossary, Article, Topic) * @template R - The relationships record type for autocomplete support * * Usage pattern: * ```typescript * export class GlossaryRepository extends AbstractRepository { * protected readonly descriptor = GlossaryDescriptor; * * constructor( * neo4j: Neo4jService, * securityService: SecurityService, * ) { * super(neo4j, securityService); * } * * // Generic methods (find, findById, create, put, patch, delete, findByRelated) are inherited * // Domain-specific methods can be added here * } * ``` */ export declare abstract class AbstractRepository = Record> implements OnModuleInit { protected readonly neo4j: Neo4jService; protected readonly securityService: SecurityService; protected readonly clsService: ClsService; protected abstract readonly descriptor: EntityDescriptor; constructor(neo4j: Neo4jService, securityService: SecurityService, clsService: ClsService); onModuleInit(): Promise; /** * Builds the default MATCH query for the entity */ protected buildDefaultMatch(options?: { searchField?: string; blockCompanyAndUser?: boolean; }): string; /** * Builds the user access validation snippet */ protected buildUserHasAccess(): string; /** * Builds the RETURN statement including all relationships from descriptor * For relationships with fields (edge properties): * - SINGLE relationships: uses aliased columns for edge properties * - MANY relationships: aggregates edge props FIRST, then UNWINDs nodes for inclusion * * This ensures readOne() gets complete edge props collections even with multiple related entities. */ protected buildReturnStatement(): string; /** * Returns the Cypher query parameters that `buildReturnStatement` references * for multi-label polymorphic relationships. Each entry maps * `polyLabels_` → the list of Neo4j labels accepted as * candidates for that relationship's polymorphic target. * * Call sites that issue a query using `buildReturnStatement()` must spread * this into `query.queryParams`. Returns an empty object when no multi-label * polymorphic relationships exist, making it a no-op for every descriptor * that does not use this shape. */ protected getPolyLabelParams(): Record; /** * Validates if the user has access to the entity * Throws Forbidden exception if entity exists but user doesn't have access */ protected _validateForbidden(params: { response: T | null; searchField: string; searchValue: string; }): Promise; /** * Find entities with optional search term, ordering, pagination, and structured filters. * * Backwards-compatible: callers that only pass { term, orderBy, cursor, fetchAll } continue to work. * New callers may pass: * - filters: FilterCriterion[] → appended to WHERE as AND-joined parameterised fragments * - orderByFields: SortCriterion[] → multi-key ORDER BY; overrides legacy orderBy string when present */ find(params: { fetchAll?: boolean; term?: string; orderBy?: string; orderByFields?: SortCriterion[]; filters?: FilterCriterion[]; cursor?: JsonApiCursorInterface; }): Promise; /** * Find entity by ID with security validation */ findById(params: { id: string; }): Promise; /** * Find entities by ID list */ findByIds(params: { ids: string[]; }): Promise; /** * Find entities by a related entity * * @param relationship - The relationship name (e.g., 'author', 'topic') * @param id - Single ID or array of IDs of the related entity * * @example * ```typescript * // Find all glossaries by a specific author * await repository.findByRelated({ relationship: 'author', id: 'author-123' }); * * // Find all glossaries related to specific topics * await repository.findByRelated({ relationship: 'topic', id: ['topic-1', 'topic-2'] }); * ``` */ findByRelated(params: { relationship: keyof R & string; id: string | string[]; term?: string; orderBy?: string; fetchAll?: boolean; cursor?: JsonApiCursorInterface; filters?: FilterCriterion[]; orderByFields?: SortCriterion[]; }): Promise; /** * Find entities connected to a related node by an arbitrary Cypher edge, * without requiring the relationship to be declared in THIS descriptor. * * Necessary for the chatbot traverse/read-entity tools, which walk * relationships using catalog-level metadata. When a relationship is * declared only on the source side via `reverse: {}`, the target's own * descriptor does not list it — so `findByRelated` (which keys off * `this.descriptor.relationships`) fails. This method accepts the raw * edge spec instead. * * Direction is from THIS node's perspective: * - "out": MATCH (this)-[:cypherLabel]->(related) * - "in": MATCH (this)<-[:cypherLabel]-(related) */ findByRelatedEdge(params: { cypherLabel: string; cypherDirection: "out" | "in"; relatedLabel: string; relatedId: string | string[]; cursor?: JsonApiCursorInterface; filters?: FilterCriterion[]; orderByFields?: SortCriterion[]; fetchAll?: boolean; }): Promise; /** * Create a new entity with relationships * Uses descriptor.fieldNames and descriptor.fieldDefaults for properties * Uses descriptor.relationships for creating relationships */ create(params: { id: string; [key: string]: any; }): Promise; /** * Update an existing entity (full update - all fields are set) * Uses descriptor.fieldNames for properties * Uses descriptor.relationships for updating relationships */ put(params: { id: string; [key: string]: any; }): Promise; /** * Partial update - only updates fields and relationships that are explicitly passed * Unlike put(), this method only modifies properties present in params */ patch(params: { id: string; [key: string]: any; }): Promise; /** * Delete an entity and all its relationships */ delete(params: { id: string; }): Promise; /** * Add items to a to-many relationship * * @param id - The parent entity ID * @param relationship - The relationship key (must match a key in descriptor.relationships) * @param items - Array of items to add with optional edge properties */ addToRelationship(params: { id: string; relationship: keyof R & string; items: { id: string; edgeProps?: Record; }[]; }): Promise; /** * Remove items from a to-many relationship * * @param id - The parent entity ID * @param relationship - The relationship key (must match a key in descriptor.relationships) * @param itemIds - Array of item IDs to remove from the relationship */ removeFromRelationship(params: { id: string; relationship: keyof R & string; itemIds: string[]; }): Promise; } //# sourceMappingURL=abstract.repository.d.ts.map