Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | 7x 7x 7x 18x 29x 3x 3x 3x 3x 7x 4x 4x 4x 12x 4x | // Pure helpers + constants shared by ProsDal. Extracted from pros.dal.ts to
// keep the class file focused on Drizzle method implementations.
import { sql } from "drizzle-orm";
import * as schema from "../db/schema";
import type { Pro } from "../db/schema";
// Cap each comma-separated multi-select filter. Without this, a caller could
// send `?businessTypeIds=a,b,c,...` with thousands of values, producing a
// WHERE clause that burns Worker CPU and risks D1 binding limits.
export const MAX_MULTI_SELECT = 20;
// D1 caps each statement at 100 bound parameters. We chunk `inArray` lookups
// at 90 (matching `admin/search.routes.ts`) to leave headroom for any other
// parameters on the same WHERE.
export const PRO_ID_CHUNK = 90;
export const parseIdList = (raw: string): string[] =>
raw
.split(",")
.map((id) => id.trim())
.filter(Boolean)
.slice(0, MAX_MULTI_SELECT);
// Build an `EXISTS (SELECT 1 FROM <junction> WHERE pro_id = pros.id AND <col>
// IN (...))` predicate for filtering pros by a junction table. Returns null
// when the input has no usable IDs.
export function buildJunctionExists(
junctionTable: "pro_service_categories" | "pro_material_tags" | "pro_service_areas",
idColumn: string,
ids: string[],
) {
Iif (ids.length === 0) return null;
const placeholders = sql.join(
ids.map((id) => sql`${id}`),
sql`, `,
);
return sql`EXISTS (SELECT 1 FROM ${sql.raw(junctionTable)} j WHERE j.pro_id = ${schema.pros.id} AND j.${sql.raw(idColumn)} IN (${placeholders}))`;
}
// Junction-derived array fields stripped from inserts/updates and applied
// separately. Keeps one list of "these are not real columns" so the strip
// helpers and the write-fanout helpers can't drift apart.
export const JUNCTION_ARRAY_FIELDS = [
"serviceCategoryIds",
"materialTagIds",
"serviceAreaIds",
] as const satisfies readonly (keyof Pro)[];
export type JunctionArrayField = (typeof JUNCTION_ARRAY_FIELDS)[number];
export type JunctionArrays = {
serviceCategoryIds?: string[];
materialTagIds?: string[];
serviceAreaIds?: string[];
};
export function splitJunctionArrays<T extends JunctionArrays>(
input: T,
): { row: Omit<T, JunctionArrayField>; junctions: JunctionArrays } {
const junctions: JunctionArrays = {};
const row = { ...input } as Record<string, unknown>;
for (const field of JUNCTION_ARRAY_FIELDS) {
Iif (field in row) {
const val = row[field];
if (Array.isArray(val)) junctions[field] = val as string[];
delete row[field];
}
}
return {
row: row as Omit<T, JunctionArrayField>,
junctions,
};
}
|