import type { EntityReference, EntitySummaryResolver, RelationshipContext, RelationshipReadAccess, SummaryResolution, } from "@metis/relationship-contracts"; import { EntityReferenceSchema, EntitySummarySchema, RelationshipContextSchema, 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"; const RowSchema = z.object({ id: z.uuid(), name: z.string().min(1), active: z.union([z.boolean(), z.literal(0), z.literal(1)]).transform(Boolean), normalizedAddress: z.string().min(1), }); /** Una proyección por lote, sin hidratar inventarios ni cargar sus historiales. */ export class NetworkShareSummaryResolver implements EntitySummaryResolver { readonly providerId = "resources"; readonly entityTypes = Object.freeze(["resources:resource"] as const); constructor( private readonly database: Sequelize, private readonly access: RelationshipReadAccess ) {} async resolveMany( references: readonly EntityReference[], context: RelationshipContext ): Promise> { if (!RelationshipContextSchema.safeParse(context).success) { return Result.fail(new RelationshipReadError("FORBIDDEN")); } const authorized = await this.access.authorize(context); if (!authorized.isSuccess) { return authorized; } const parsed = z.array(EntityReferenceSchema).max(100).safeParse(references); if (!parsed.success) { return Result.fail(new RelationshipReadError("INVALID_QUERY")); } const accepted = parsed.data.filter( (reference) => reference.companyId === context.companyId && reference.providerId === this.providerId && reference.entityType === "resources:resource" ); const ids = [...new Set(accepted.map((reference) => reference.id))]; const rows = ids.length === 0 ? [] : z .array(RowSchema) .parse( await this.database.query( "SELECT r.id,r.name,r.active,d.normalizedAddress FROM resources r JOIN resource_network_shares d ON d.resourceId=r.id AND d.companyId=r.companyId WHERE r.companyId=:companyId AND r.id IN (:ids)", { type: QueryTypes.SELECT, replacements: { companyId: context.companyId, ids } } ) ); const byId = new Map(rows.map((row) => [row.id, row])); return Result.ok( Object.freeze( parsed.data.map((reference): SummaryResolution => { const row = reference.companyId === context.companyId && reference.providerId === this.providerId && reference.entityType === "resources:resource" ? byId.get(reference.id) : undefined; return row ? Object.freeze({ status: "resolved", summary: EntitySummarySchema.parse({ reference, name: row.name, subtitle: row.normalizedAddress, state: { code: row.active ? "active" : "inactive", labelKey: row.active ? "resources:active" : "resources:inactive", }, }), }) : Object.freeze({ status: "unavailable", reference }); }) ) ); } }