import type { RelationshipContext, RelationshipReadAccess } from "@metis/relationship-contracts"; import { RelationshipReadError } from "@metis/relationship-contracts"; import { Result } from "@repo/rdx-utils"; import type { Sequelize } from "sequelize"; import { QueryTypes } from "sequelize"; import { z } from "zod/v4"; import type { DirectoryDomainOptionsQuery } from "../../../common/directory-domain-options"; import { DirectoryDomainOptionSchema, DirectoryDomainOptionsResponseSchema, } from "../../../common/directory-domain-options"; /** Opciones activas y estructuradas; no descarga el inventario ni sus revisiones. */ export class DirectoryDomainOptionsReader { constructor( private readonly database: Sequelize, private readonly access: RelationshipReadAccess ) {} async list(query: DirectoryDomainOptionsQuery, context: RelationshipContext) { const authorized = await this.access.authorize(context); if (!authorized.isSuccess) { return authorized; } if (query.search.length > 100) { return Result.fail(new RelationshipReadError("INVALID_QUERY")); } const rows = z.array(DirectoryDomainOptionSchema).parse( await this.database.query( `SELECT r.id,r.name,d.normalizedDns FROM resources r JOIN resource_directory_domains d ON d.resourceId=r.id AND d.companyId=r.companyId WHERE r.companyId=:companyId AND r.active=1 AND (:search = '' OR LOCATE(:search,r.name)>0 OR LOCATE(:search,d.normalizedDns)>0) ${query.cursor ? "AND r.id>:cursor" : ""} ORDER BY r.id LIMIT 21`, { type: QueryTypes.SELECT, replacements: { companyId: context.companyId, search: query.search, cursor: query.cursor ?? null, }, } ) ); const items = rows.slice(0, 20); return Result.ok( DirectoryDomainOptionsResponseSchema.parse({ items, nextCursor: rows.length > 20 ? items.at(-1)?.id : null, }) ); } }