import type { ActionFieldDef, ColumnDefinition, TableMetadata } from './types'; export type DynamicRelationKind = 'one_to_many' | 'many_to_many'; export declare function objectLabel(value: unknown): string | undefined; export declare function formatRelationCell(row: Record, col: ColumnDefinition): string; export interface PivotRowLike { id?: string | number | null; [k: string]: unknown; } export interface TargetRowLike { id?: string | number | null; [k: string]: unknown; } /** * Builds the query params used by `` to * scope a child list to a single parent record. Mirrors the * `f_=eq:` convention enforced by `query/params.go` in the * kernel. */ export declare function buildRelationFilterParams(foreignKey: string, parentId: string | number, extraFilters?: Record | null): Record; /** * Builds the POST body for creating a child row. The foreign key is forced to * `parentId` regardless of what the form returned — the inline form hides the * FK input but a misbehaving caller (or a manual override) should not be able * to redirect the row to a different parent. */ export declare function buildCreatePayload(foreignKey: string, parentId: string | number, formValues: Record): Record; /** * Maps a `TableMetadata.columns` shape into `ActionFieldDef[]` so the inline * form can be rendered with ``. Excludes the foreign-key column * (already fixed to parentId) and any column flagged `hidden`. Falls back to * sensible widget hints derived from `ColumnDefinition.type`. */ export declare function deriveRelationFormFields(metadata: Pick | null | undefined, foreignKey: string): ActionFieldDef[]; /** * Stable id for relation rows. Falls back to a synthetic * `__rel--` when the row has no id — keeps React keys * stable and lets optimistic creates render before the backend assigns an id. */ export declare function relationRowKey(row: { id?: string | number | null; } | undefined, index: number, foreignKey: string): string; /** * Builds the POST body for attaching a target row to the parent through the * pivot table. Both FKs are required: `foreignKey -> parentId` (pivot side) * and `referencesKey -> targetId` (target side). Extra pivot fields can be * passed via `extra` (e.g. `role`, `position`); never override the two FKs. */ export declare function buildPivotAttachPayload(foreignKey: string, parentId: string | number, referencesKey: string, targetId: string | number, extra?: Record): Record; /** * From a list of pivot rows, returns the set of currently-attached target ids * coerced to string (the form expected by `` `selected`). * Skips rows missing the FK (defensive — the kernel should never return them). */ export declare function extractSelectedTargetIds(pivotRows: ReadonlyArray | null | undefined, referencesKey: string): string[]; /** * Builds a `targetId -> pivotRowId` lookup so detach can DELETE the pivot row * by its own id without re-fetching. When several pivot rows point at the * same target (shouldn't happen with a unique constraint but the kernel does * not guarantee it), the *last* one wins — detach will only drop one at a * time, the next render will surface the leftover. */ export declare function buildPivotRowIndex(pivotRows: ReadonlyArray | null | undefined, referencesKey: string): Map; /** * Diffs the previous selection against the next one and returns the work to * apply: target ids that need a POST (toAdd) and ids that need a DELETE * (toRemove). Both arrays are deduped and order-stable to make tests * deterministic. */ export declare function diffSelection(prev: ReadonlyArray, next: ReadonlyArray): { toAdd: string[]; toRemove: string[]; }; /** * Picks a human-readable label for a target row. Tries `displayKey` first, * then walks the metadata columns in order looking for the first non-id / * non-FK string-ish value. Falls back to the row id, then to '—'. */ export declare function pickOptionLabel(row: TargetRowLike | null | undefined, displayKey: string | undefined, columns: ReadonlyArray | null | undefined): string; //# sourceMappingURL=dynamic-relation-helpers.d.ts.map