/** * Helpers para construir queries OData que entiende el API de BIND. * * Sintaxis observable en la doc oficial: * /api/Products?$filter=ID eq guid'bbe2cc0c-...'&$skip=0&$top=50&$orderby=Name asc * * Mantengo el builder muy chico — sólo lo que el MVP necesita. */ export type ODataFilter = string; export interface ODataQuery { filter?: ODataFilter; top?: number; skip?: number; orderby?: string; select?: string[]; count?: boolean; } export function buildQueryString(q: ODataQuery): string { const parts: string[] = []; if (q.filter) parts.push(`$filter=${encodeURIComponent(q.filter)}`); if (typeof q.top === "number") parts.push(`$top=${q.top}`); if (typeof q.skip === "number") parts.push(`$skip=${q.skip}`); if (q.orderby) parts.push(`$orderby=${encodeURIComponent(q.orderby)}`); if (q.select?.length) parts.push(`$select=${encodeURIComponent(q.select.join(","))}`); if (q.count) parts.push(`$count=true`); return parts.length ? `?${parts.join("&")}` : ""; } /** * Pequeño helper para escribir filtros legibles. No es un parser OData; * solo escapa comillas simples y envuelve guids. * * Ejemplos: * eq("ID", guid("bbe2...")) -> "ID eq guid'bbe2...'" * eq("Status", "issued") -> "Status eq 'issued'" * and(eq("Status","issued"), gt("Total", 1000)) */ export const guid = (id: string): string => `guid'${id.replaceAll("'", "''")}'`; export const str = (s: string): string => `'${s.replaceAll("'", "''")}'`; export const eq = (field: string, value: string | number | boolean): string => `${field} eq ${formatValue(value)}`; export const ne = (field: string, value: string | number | boolean): string => `${field} ne ${formatValue(value)}`; export const gt = (field: string, value: string | number): string => `${field} gt ${formatValue(value)}`; export const lt = (field: string, value: string | number): string => `${field} lt ${formatValue(value)}`; export const ge = (field: string, value: string | number): string => `${field} ge ${formatValue(value)}`; export const le = (field: string, value: string | number): string => `${field} le ${formatValue(value)}`; export const and = (...parts: string[]): string => parts.join(" and "); export const or = (...parts: string[]): string => `(${parts.join(" or ")})`; function formatValue(v: string | number | boolean): string { if (typeof v === "number" || typeof v === "boolean") return String(v); // Si ya viene formateado como guid'...' o '...' (string OData), respétalo. if (/^(guid'.*'|'.*')$/.test(v)) return v; return str(v); }