@standardbeagle/edit-db 0.4.478 → 0.4.494

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/common/fetcher.d.ts +7 -2
  2. package/dist/components/content-panel.d.ts +5 -2
  3. package/dist/components/filters/fk-filter.d.ts +2 -0
  4. package/dist/components/filters/fk-filter.test.d.ts +1 -0
  5. package/dist/components/filters/number-filter.d.ts +1 -0
  6. package/dist/components/filters/number-filter.test.d.ts +1 -0
  7. package/dist/components/filters/use-debounced-commit.d.ts +19 -0
  8. package/dist/components/filters/use-debounced-commit.test.d.ts +1 -0
  9. package/dist/components/fk-cell-popover.d.ts +8 -1
  10. package/dist/components/fk-cell-popover.test.d.ts +1 -0
  11. package/dist/data-data-table.test.d.ts +0 -0
  12. package/dist/data-edit.d.ts +8 -0
  13. package/dist/edit-db.css +1 -1
  14. package/dist/editor.es.js +5726 -15712
  15. package/dist/editor.umd.cjs +33 -69
  16. package/dist/hooks/useCompositeTableRef.d.ts +19 -1
  17. package/dist/hooks/useCompositeTableRef.test.d.ts +1 -0
  18. package/dist/hooks/useDataTable.d.ts +13 -1
  19. package/dist/hooks/usePath.d.ts +1 -5
  20. package/dist/hooks/useTableMutation.test.d.ts +0 -0
  21. package/dist/hooks/useTableRef.d.ts +22 -1
  22. package/dist/hooks/useTableRef.test.d.ts +1 -0
  23. package/dist/hooks/useTableStats.d.ts +7 -0
  24. package/dist/hooks/useToast.d.ts +15 -0
  25. package/dist/lib/content-detect.d.ts +5 -0
  26. package/dist/lib/date-input.d.ts +21 -0
  27. package/dist/lib/date-input.test.d.ts +1 -0
  28. package/dist/lib/fk.d.ts +10 -2
  29. package/dist/lib/invalidate.d.ts +7 -0
  30. package/dist/lib/invalidate.test.d.ts +1 -0
  31. package/dist/lib/label-match.d.ts +13 -0
  32. package/dist/lib/label-match.test.d.ts +1 -0
  33. package/dist/lib/m2m.d.ts +19 -5
  34. package/dist/lib/query-builder.d.ts +24 -2
  35. package/dist/lib/row-id.d.ts +9 -0
  36. package/dist/lib/table-ref.d.ts +45 -0
  37. package/dist/lib/table-ref.test.d.ts +1 -0
  38. package/dist/types/schema.d.ts +12 -6
  39. package/package.json +1 -3
  40. package/dist/error-panel.d.ts +0 -1
@@ -10,10 +10,28 @@ export interface CompositeTableRef {
10
10
  loading: boolean;
11
11
  error: unknown;
12
12
  data: CompositeTableRefValue[];
13
+ /** True when `search` narrows server-side (String label column, `_contains`);
14
+ * false means the caller must filter the fetched window client-side. */
15
+ serverSearch: boolean;
16
+ }
17
+ export interface CompositeTableRefOptions {
18
+ /** Free-text search term. Applied server-side when the label column is String. */
19
+ search?: string;
20
+ /** Defer the list fetch until the dropdown is opened (fetch-on-open). */
21
+ enabled?: boolean;
22
+ /** The currently-selected destination-column values, so the selected parent row
23
+ * can be looked up and shown even when it falls outside the fetched window. */
24
+ currentValues?: Record<string, unknown> | null;
13
25
  }
14
26
  /**
15
27
  * Fetch parent rows for a composite-FK Select widget. Returns one row per parent
16
28
  * with its label plus every destination column value so the caller can write
17
29
  * each composite-FK source column on the child form when a selection is made.
30
+ *
31
+ * Mirrors the single-column FK data source (table-ref.ts / useTableRef +
32
+ * useTableRefValue): the window is sorted by the label column (deterministic),
33
+ * narrowed server-side when a search term is given and the label is String-typed,
34
+ * and the currently-selected row is resolved via a single-row lookup when it lies
35
+ * outside the fetched window so it stays selectable instead of showing blank.
18
36
  */
19
- export declare function useCompositeTableRef(schema: Schema, destTableName: string, destColumnNames: string[]): CompositeTableRef;
37
+ export declare function useCompositeTableRef(schema: Schema, destTableName: string, destColumnNames: string[], options?: CompositeTableRefOptions): CompositeTableRef;
@@ -0,0 +1 @@
1
+ export {};
@@ -7,13 +7,25 @@ interface RowData {
7
7
  id?: number | string;
8
8
  [key: string]: unknown;
9
9
  }
10
+ export declare function getJoinedRowPkValue(row: RowData | undefined, joinSchema: Table | undefined): string;
10
11
  /**
11
12
  * Clamp a page index into the valid [0, pageCount-1] range. Guards against a
12
13
  * stale/out-of-range page (e.g. "page 2 of 1" after switching to a smaller
13
14
  * table or when the row count shrinks).
14
15
  */
15
16
  export declare function clampPageIndex(pageIndex: number, pageCount: number): number;
17
+ /**
18
+ * Reconcile in-memory column-filter state with the URL `cf` param, which is the
19
+ * source of truth. Returns `prev` unchanged when it already serializes to the
20
+ * same string as `cfParam` — this both preserves referential identity (no
21
+ * needless re-render) and stops the setState → syncFiltersToUrl → cfParam →
22
+ * effect cycle from looping on our own writes. Otherwise it deserializes the URL
23
+ * value so browser back/forward and table switches (which drop the query string)
24
+ * drive the filters instead of leaving stale state behind.
25
+ */
26
+ export declare function reconcileColumnFiltersFromUrl(prev: ColumnFiltersState, cfParam: string): ColumnFiltersState;
16
27
  export declare function getMultiJoinRows(row: RowData, join: Join): RowData[];
28
+ export declare function getMultiJoinTotal(row: RowData, join: Join): number;
17
29
  /**
18
30
  * Return type for the useDataTable hook.
19
31
  * @interface UseDataTableResult
@@ -35,7 +47,7 @@ interface UseDataTableResult {
35
47
  pageCount: number;
36
48
  /** Current page data rows */
37
49
  rows: RowData[];
38
- /** Whether data is currently loading */
50
+ /** Whether data is currently loading (no rows to show yet) */
39
51
  loading: boolean;
40
52
  /** Error object if the query failed */
41
53
  error: Error | null;
@@ -23,10 +23,6 @@ interface SearchParamsResult {
23
23
  search: URLSearchParams;
24
24
  hash: string;
25
25
  }
26
- interface RouteError {
27
- message?: string;
28
- status?: number;
29
- }
30
26
  interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
31
27
  to: string;
32
28
  children?: ReactNode;
@@ -41,7 +37,6 @@ export declare function useNavigate(): (url: string) => void;
41
37
  export declare function useNavigation(): NavigationState;
42
38
  export declare function useParams<T extends RouteParams = RouteParams>(): T;
43
39
  export declare function useSearchParams(): SearchParamsResult;
44
- export declare function useRouteError(): RouteError;
45
40
  export declare function PathProvider({ path, children }: {
46
41
  path: string;
47
42
  children: ReactNode;
@@ -68,4 +63,5 @@ export declare function Route({ path, element }: {
68
63
  path: string;
69
64
  element: ReactElement;
70
65
  }): ReactElement;
66
+ export declare const matchPath: (route: string, path: string) => PathMatch;
71
67
  export {};
File without changes
@@ -1,5 +1,4 @@
1
1
  import { Schema } from '../types/schema';
2
- export declare function useTableRef(schema: Schema, tableName: string, columnName: string): TableRef;
3
2
  export interface TableRefValue {
4
3
  key: string;
5
4
  label: string;
@@ -8,4 +7,26 @@ export interface TableRef {
8
7
  loading: boolean;
9
8
  error: unknown;
10
9
  data: TableRefValue[];
10
+ /** True when `search` narrows server-side (String label column, `_contains`);
11
+ * false means the caller must filter the fetched window client-side. */
12
+ serverSearch: boolean;
11
13
  }
14
+ /**
15
+ * Fetch the option rows for an FK dropdown (key + label per parent row).
16
+ * When `search` is non-empty and the parent's label column is String-typed the
17
+ * list is narrowed server-side, so parents beyond the fetch window stay
18
+ * findable; otherwise one window is fetched and the caller filters it.
19
+ */
20
+ export declare function useTableRef(schema: Schema, tableName: string, columnName: string, search?: string, enabled?: boolean): TableRef;
21
+ export interface TableRefLookup {
22
+ loading: boolean;
23
+ error: unknown;
24
+ value: TableRefValue | null;
25
+ }
26
+ /**
27
+ * Resolve key + label for a single parent row by its key value. Used when the
28
+ * currently stored FK value falls outside the fetched dropdown window, so the
29
+ * Select can still display the stored value instead of a misleading
30
+ * placeholder. Pass `key` as null/'' to disable the lookup.
31
+ */
32
+ export declare function useTableRefValue(schema: Schema, tableName: string, columnName: string, key: unknown): TableRefLookup;
@@ -0,0 +1 @@
1
+ export {};
@@ -33,6 +33,13 @@ export interface UseTableStatsResult {
33
33
  message: string;
34
34
  } | null;
35
35
  }
36
+ /**
37
+ * Builds a GraphQL query to fetch row counts for all tables.
38
+ *
39
+ * @param tableNames - Array of table GraphQL names
40
+ * @returns GraphQL query string
41
+ */
42
+ export declare function buildRowCountQuery(tableNames: string[]): string | null;
36
43
  /**
37
44
  * Hook to fetch table statistics including row counts.
38
45
  *
@@ -0,0 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * Minimal dependency-free toast system for transient success/error feedback
4
+ * after mutations (create, save, delete, inline content edits). Kept small and
5
+ * self-contained so the published editor pulls in no extra runtime dependency.
6
+ */
7
+ export type ToastVariant = 'success' | 'error';
8
+ interface ToastApi {
9
+ toast: (message: string, variant?: ToastVariant) => void;
10
+ }
11
+ export declare function ToastProvider({ children }: {
12
+ children: ReactNode;
13
+ }): import("react").JSX.Element;
14
+ export declare function useToast(): ToastApi;
15
+ export {};
@@ -4,6 +4,11 @@ export type ContentKind = 'json' | 'xml' | 'php-serialized' | 'binary' | 'longte
4
4
  export declare function isBinaryDbType(dbType: string): boolean;
5
5
  /** Check if a dbType is a native JSON type (json, jsonb). */
6
6
  export declare function isJsonDbType(dbType: string): boolean;
7
+ /** Column-level JSON check: native JSON dbType or the JSON GraphQL scalar. */
8
+ export declare function isJsonColumn(col: {
9
+ dbType: string;
10
+ paramType?: string;
11
+ }): boolean;
7
12
  /** Check if a dbType is a long text type (text, ntext, varchar(max), xml) */
8
13
  export declare function isLongTextDbType(dbType: string): boolean;
9
14
  /** Detect content kind from a string value and optional dbType hint */
@@ -0,0 +1,21 @@
1
+ import { Column } from '../types/schema';
2
+ /** True for any date-ish column (bare date or datetime). */
3
+ export declare function isDateColumn(column: Column): boolean;
4
+ /** True when a date-ish column carries a time-of-day component (datetime, not a bare date). */
5
+ export declare function isDateTimeColumn(column: Column): boolean;
6
+ /**
7
+ * Normalizes a stored date/datetime string into the value an `<input type="date">`
8
+ * or `<input type="datetime-local">` expects. For datetime columns the time-of-day
9
+ * is preserved (fractional seconds and timezone offset are trimmed) so re-saving an
10
+ * unrelated field does not overwrite the time with midnight. Returns '' for the
11
+ * SQL "zero" date and unparseable input.
12
+ */
13
+ export declare function toDateInputValue(raw: string | undefined, withTime: boolean): string;
14
+ /**
15
+ * Restore the original raw value for every date/datetime field the user did not
16
+ * edit. The form holds `toDateInputValue` projections; a field whose current form
17
+ * value still equals the projection of the original raw value is untouched, so
18
+ * the raw value (offset and fractional seconds intact) is sent instead of the
19
+ * lossy projection. Fields the user actually changed keep the new form value.
20
+ */
21
+ export declare function preserveUntouchedDateValues(formValues: Record<string, unknown>, originalRow: Record<string, unknown>, columns: Column[]): Record<string, unknown>;
@@ -0,0 +1 @@
1
+ export {};
package/dist/lib/fk.d.ts CHANGED
@@ -1,13 +1,21 @@
1
- import { Join, Table } from '../types/schema';
1
+ import { Column, Join, Table } from '../types/schema';
2
2
  export interface FkEqFilterResult {
3
3
  filterText: string;
4
4
  variables: Record<string, unknown>;
5
5
  params: string[];
6
6
  }
7
+ /**
8
+ * Coerce a raw cell/route value to the JS type matching a GraphQL scalar so the
9
+ * variable payload agrees with its declared type (e.g. a Boolean FK is sent as
10
+ * `true`, not `"true"`). Unparseable numerics are passed through untouched so
11
+ * the server reports the real error instead of receiving `NaN`.
12
+ */
13
+ export declare function coerceForGql(value: unknown, gqlType: string): unknown;
14
+ /** The base GraphQL scalar of a column (`paramType` minus non-null marker), defaulting to String. */
15
+ export declare function gqlTypeOf(column: Column | undefined): string;
7
16
  export declare function isFkMember(join: Join, columnName: string): boolean;
8
17
  export declare function isComposite(join: Join): boolean;
9
18
  export declare function findJoinBySource(joins: Join[], columnName: string): Join | undefined;
10
- export declare function findJoinByDestinationTable(joins: Join[], destinationTable: string): Join | undefined;
11
19
  /**
12
20
  * Build a `{_eq}`-per-column composite filter against the destination side of a join,
13
21
  * using values pulled from a source-side row. Single-column joins emit a single
@@ -0,0 +1,7 @@
1
+ import { QueryClient } from '@tanstack/react-query';
2
+ /**
3
+ * Invalidate every query family that can serve rows affected by a write to
4
+ * `tableName`. Returns the refetch promise for callers that want to await it;
5
+ * queries are marked invalidated synchronously either way.
6
+ */
7
+ export declare function invalidateAfterTableWrite(queryClient: QueryClient, tableName: string): Promise<void>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @module lib/label-match
3
+ *
4
+ * Client-side label filter shared by FK dropdowns (`ParentField`) and the
5
+ * many-to-many `TargetPicker` fallback. Used when the label column is not
6
+ * String-typed, so the server-side `_contains` search is unavailable and rows
7
+ * are filtered within the fetched window instead.
8
+ */
9
+ /**
10
+ * Case-insensitive substring match against a row's `label`, falling back to its
11
+ * id field (`idKey`) when no label was fetched.
12
+ */
13
+ export declare function matchesLabel(row: object, idKey: string, term: string): boolean;
@@ -0,0 +1 @@
1
+ export {};
package/dist/lib/m2m.d.ts CHANGED
@@ -32,12 +32,19 @@ export declare function m2mRowsQuery(junction: Table, target: Table, m2m: ManyTo
32
32
  export interface M2mTargetPickerPlan {
33
33
  query: string;
34
34
  idColumn: string;
35
+ /** True when the label column is String-typed and thus supports the
36
+ * server-side `_contains` search; callers fall back to client filtering. */
37
+ serverSearch: boolean;
35
38
  }
36
39
  /**
37
40
  * Build the target-list query used when adding a many-to-many link.
38
41
  * Sort values are BifrostQL enum literals, so they must not be quoted.
42
+ *
43
+ * When `search` is non-empty the list is filtered server-side (a `_contains` on
44
+ * the label column) so a large target table stays findable beyond the fetch
45
+ * limit, instead of searching only within a client-side window.
39
46
  */
40
- export declare function m2mTargetPickerPlan(target: Table, m2m: ManyToManyJoin): M2mTargetPickerPlan;
47
+ export declare function m2mTargetPickerPlan(target: Table, m2m: ManyToManyJoin, search?: string): M2mTargetPickerPlan;
41
48
  /**
42
49
  * Read the target row's id and display label from a junction row's nested target
43
50
  * selection (emitted by {@link m2mRowsQuery}). Returns null when the link has no
@@ -53,9 +60,16 @@ export declare function targetDisplay(junctionRow: Record<string, unknown>, m2m:
53
60
  * the chosen target key on the junction target FK. Any payload columns are left
54
61
  * unset so the database applies its defaults; the user edits them afterwards.
55
62
  *
56
- * Single-column junction FKs only. `parentId`/`targetId` are route-encoded
57
- * strings; for a composite FK they carry multiple values joined by "::", which
58
- * would be written verbatim into one column — silent data corruption. Rather
59
- * than guess a decomposition, fail loudly until composite-FK support is built.
63
+ * Single-column junction FKs only. `parentId` is a route-encoded string
64
+ * (produced by rowIdOf/encodePkRoute); for a composite FK it carries multiple
65
+ * values joined by "::", which would be written verbatim into one column —
66
+ * silent data corruption. Rather than guess a decomposition, fail loudly until
67
+ * composite-FK support is built.
68
+ *
69
+ * The parent value is percent-DECODED before being written: the read side
70
+ * (m2mRowsQuery) decodes the route id before filtering, so writing the encoded
71
+ * form (e.g. 'caf%C3%A9' for a 'café' key) would insert a dangling FK that the
72
+ * panel's filter never matches. `targetId` is NOT route-encoded — it comes raw
73
+ * from the picker row — so it is written as-is.
60
74
  */
61
75
  export declare function attachJunctionDetail(m2m: ManyToManyJoin, parentId: string, targetId: string): Record<string, unknown>;
@@ -1,5 +1,6 @@
1
- import { Table, Schema } from '../types/schema';
1
+ import { Table, Join, Schema } from '../types/schema';
2
2
  import { ColumnFiltersState } from '@tanstack/react-table';
3
+ import { PkEqFilterResult } from './row-id';
3
4
  export interface FilterResult {
4
5
  variables: Record<string, unknown>;
5
6
  param: string;
@@ -22,10 +23,12 @@ interface RowData {
22
23
  id?: number | string | null;
23
24
  [key: string]: unknown;
24
25
  }
26
+ export declare function isGraphQlName(value: unknown): value is string;
27
+ export declare function assertGraphQlName(value: unknown, kind: string): asserts value is string;
25
28
  export declare function getFilterOperators(paramType: string): string[];
26
29
  export declare function getFilterObj(filterString: string): FilterResult;
27
30
  export declare function toLocaleDate(d: string): string;
28
- export declare function getRowPkValue(row: RowData, table: Table): string;
31
+ export declare function getRowPkValue(row: RowData, table: Table, index?: number): string;
29
32
  export declare function getGraphQlType(paramType: string): string;
30
33
  export declare function buildColumnFilters(columnFilters: ColumnFiltersState, table: Table): ColumnFilterResult;
31
34
  export declare function serializeColumnFilters(columnFilters: ColumnFiltersState): string;
@@ -48,13 +51,32 @@ export declare function getPkTypes(table: Table): PkTypeInfo[];
48
51
  * it is a route-encoded string produced by {@link encodePkRoute}.
49
52
  */
50
53
  export declare function buildPkEqVariables(idRoute: string, table: Table): Record<string, unknown>;
54
+ /**
55
+ * Builds a single-row lookup query keyed by a primary-key equality filter
56
+ * (produced by {@link buildPkEqFilter}). The row comes back under the `value`
57
+ * alias: `{ value: { data: [row] } }`. Used by the content panel to re-read a
58
+ * row fresh before echoing it back in an update.
59
+ */
60
+ export declare function buildSingleRowQuery(table: Pick<Table, 'name'>, pkEq: Pick<PkEqFilterResult, 'filterText' | 'params'>, fields: readonly string[]): string;
51
61
  export declare function buildQuery(table: Table, schema: Schema, filterString: string, columnFilters: ColumnFiltersState, id?: string, tableFilter?: string, filterColumn?: string): string | null;
52
62
  export interface DrillDownTarget {
53
63
  /** The parent table whose row owns the child collection. */
54
64
  parentTable: Table;
55
65
  /** The child collection field name on the parent type. */
56
66
  childField: string;
67
+ /** The parent multi-join that owns the child collection. Lets callers
68
+ * decide whether the drill can use a flat FK filter (simple single-column
69
+ * FK) or must keep the MODEL B parent traversal (composite/polymorphic). */
70
+ childJoin: Join;
57
71
  }
72
+ /**
73
+ * A drill can render as a flat root-filtered child grid — `childTable(filter:
74
+ * { fk: { _eq: $id } })`, i.e. a "parent grid with a filter applied" — only for
75
+ * a simple single-column, non-polymorphic FK. Composite FKs have no single
76
+ * filter column and polymorphic links need the server-injected discriminator;
77
+ * both must keep MODEL B's parent traversal.
78
+ */
79
+ export declare function canFlatFilterDrill(childJoin: Join): boolean;
58
80
  /**
59
81
  * Resolve the parent table + child collection field for a parent→child
60
82
  * related-records drill-down. The child is `table`; the parent is `tableFilter`
@@ -6,6 +6,7 @@ export interface PkEqFilterResult {
6
6
  params: string[];
7
7
  }
8
8
  type TableLike = Pick<Table, 'primaryKeys'> & Partial<Pick<Table, 'columns'>>;
9
+ export declare function decodePkPart(raw: string): string | null;
9
10
  /**
10
11
  * Encodes an ordered list of key values into a route string. The single source
11
12
  * of truth for composite-key route encoding — every producer (row lists) and
@@ -13,6 +14,14 @@ type TableLike = Pick<Table, 'primaryKeys'> & Partial<Pick<Table, 'columns'>>;
13
14
  * never drift apart and silently fail to match.
14
15
  */
15
16
  export declare function encodeRouteParts(values: readonly unknown[]): string;
17
+ /**
18
+ * Inverse of {@link encodeRouteParts}: splits a route-encoded id into its ordered
19
+ * values and percent-decodes each. `expectedCount <= 1` treats the whole string as a
20
+ * single value (never split, so a value that itself contains the delimiter survives).
21
+ * Throws when a multi-part id does not carry exactly `expectedCount` parts, so a caller
22
+ * building a composite filter cannot silently under-constrain it.
23
+ */
24
+ export declare function decodeRouteParts(raw: string, expectedCount: number): string[];
16
25
  export declare function rowIdOf(row: Record<string, unknown> | null | undefined, table: TableLike, index: number): string;
17
26
  export declare function pkFilterFor(row: Record<string, unknown> | null | undefined, table: TableLike): PkFilter | null;
18
27
  export declare function buildPkEqFilter(row: Record<string, unknown> | null | undefined, table: Pick<Table, 'primaryKeys' | 'columns'>): PkEqFilterResult | null;
@@ -0,0 +1,45 @@
1
+ import { Table } from '../types/schema';
2
+ export declare const TABLE_REF_LIMIT = 1000;
3
+ export declare const TABLE_REF_SEARCH_LIMIT = 50;
4
+ /**
5
+ * The column used as the display label for a table's FK dropdown rows.
6
+ * Falls back to schema-derived names only — never a guessed literal like `id`,
7
+ * which is a server error on tables without such a column: first primary-key
8
+ * column, then the first column. (Taking the first PK column here is a label
9
+ * fallback for display, not a composite-key shortcut — one column is all a
10
+ * label can show.) `||` (not `??`) so an empty-string labelColumn falls
11
+ * through instead of emitting `label: ` (a GraphQL syntax error).
12
+ */
13
+ export declare function refLabelColumn(table: Table): string;
14
+ export interface TableRefPlan {
15
+ query: string;
16
+ labelColumn: string;
17
+ /** True when the label column is String-typed and thus supports the
18
+ * server-side `_contains` search; callers fall back to client filtering. */
19
+ serverSearch: boolean;
20
+ }
21
+ /**
22
+ * Build the FK-dropdown list query. Sorted by the label column so the fetched
23
+ * window is deterministic. When `search` is non-empty and the label column is
24
+ * String-typed, the list is narrowed server-side (`_contains` on the label
25
+ * column) so parents beyond the fetch limit stay findable; otherwise the caller
26
+ * filters client-side over the fetched window.
27
+ */
28
+ export declare function tableRefPlan(table: Table, keyColumn: string, search?: string): TableRefPlan;
29
+ export interface TableRefLookupPlan {
30
+ query: string;
31
+ /** GraphQL type of the key column (non-null suffix stripped), for coercion. */
32
+ keyType: string;
33
+ }
34
+ /**
35
+ * Build the single-row lookup that resolves the label of the currently stored
36
+ * FK value when it falls outside the fetched dropdown window, so the Select can
37
+ * display it instead of a misleading placeholder.
38
+ */
39
+ export declare function tableRefLookupPlan(table: Table, keyColumn: string): TableRefLookupPlan;
40
+ /**
41
+ * Coerce a stored/route FK value to what the lookup's `$key` variable expects.
42
+ * Delegates to the shared coerceForGql so BigInt keys stay strings (Number()
43
+ * loses precision past 2^53) and Boolean keys stay booleans.
44
+ */
45
+ export declare function coerceKeyValue(keyType: string, value: unknown): unknown;
@@ -0,0 +1 @@
1
+ export {};
@@ -10,12 +10,9 @@
10
10
  */
11
11
  export interface TableMetadata {
12
12
  /** Lookup configuration for reference tables */
13
- type?: {
14
- type: 'lookup';
15
- id: string;
16
- label: string;
17
- };
18
- [key: string]: any;
13
+ type?: LookupMetadata;
14
+ /** Other free-form metadata entries keyed by metadata name (parsed from key/value pairs). */
15
+ [key: string]: string | LookupMetadata | undefined;
19
16
  }
20
17
  /**
21
18
  * Lookup table metadata defining ID and label columns.
@@ -98,6 +95,15 @@ export interface Join {
98
95
  destinationTable: string;
99
96
  /** Column names in the target table */
100
97
  destinationColumnNames: string[];
98
+ /** True for a polymorphic child link — the relation carries a server-side
99
+ * discriminator predicate (entity_type) rather than a plain FK. Such drills
100
+ * must keep the MODEL B parent traversal so the server injects the
101
+ * discriminator; a flat FK filter would leak sibling-type rows. */
102
+ isPolymorphic?: boolean;
103
+ /** Discriminator column backing a polymorphic link (when isPolymorphic). */
104
+ polymorphicTypeColumn?: string;
105
+ /** Discriminator value backing a polymorphic link (when isPolymorphic). */
106
+ polymorphicTypeValue?: string;
101
107
  }
102
108
  /**
103
109
  * Many-to-many bridge between this entity and a target entity through a
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@standardbeagle/edit-db",
3
3
  "private": false,
4
- "version": "0.4.478",
4
+ "version": "0.4.494",
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "@radix-ui/react-slot": "^1.2.4",
@@ -14,7 +14,6 @@
14
14
  "radix-ui": "^1.4.3",
15
15
  "react": "^18.3.1",
16
16
  "react-dom": "^18.3.1",
17
- "redux-actions": "^3.0.3",
18
17
  "tailwind-merge": "^3.6.0"
19
18
  },
20
19
  "devDependencies": {
@@ -27,7 +26,6 @@
27
26
  "@testing-library/react": "^16.3.2",
28
27
  "@types/react": "^18.3.29",
29
28
  "@types/react-dom": "^18.3.7",
30
- "@types/redux-actions": "^2.6.5",
31
29
  "@typescript-eslint/eslint-plugin": "^7.18.0",
32
30
  "@typescript-eslint/parser": "^7.18.0",
33
31
  "@vitejs/plugin-react-swc": "^4.3.1",
@@ -1 +0,0 @@
1
- export default function ErrorPage(): import("react").JSX.Element;