@metaobjectsdev/codegen-ts-tanstack 0.9.0 → 0.11.0-rc.1
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.
- package/README.md +5 -1
- package/dist/tanstack-grid-hook.d.ts.map +1 -1
- package/dist/tanstack-grid-hook.js +2 -2
- package/dist/tanstack-grid-hook.js.map +1 -1
- package/dist/tanstack-grid.d.ts.map +1 -1
- package/dist/tanstack-grid.js +8 -3
- package/dist/tanstack-grid.js.map +1 -1
- package/dist/tanstack-query.d.ts.map +1 -1
- package/dist/tanstack-query.js +4 -2
- package/dist/tanstack-query.js.map +1 -1
- package/dist/templates/columns-file.d.ts.map +1 -1
- package/dist/templates/columns-file.js +35 -7
- package/dist/templates/columns-file.js.map +1 -1
- package/dist/templates/hooks-file.d.ts.map +1 -1
- package/dist/templates/hooks-file.js +261 -10
- package/dist/templates/hooks-file.js.map +1 -1
- package/package.json +37 -26
- package/src/tanstack-grid-hook.ts +2 -2
- package/src/tanstack-grid.ts +8 -3
- package/src/tanstack-query.ts +4 -2
- package/src/templates/columns-file.ts +47 -6
- package/src/templates/hooks-file.ts +309 -11
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# @metaobjectsdev/codegen-ts-tanstack
|
|
2
2
|
|
|
3
|
-
TanStack codegen for MetaObjects. Provides `tanstackQuery()` (per-entity `<Entity>.hooks.ts` — 5 React Query hooks), `tanstackGrid()` (`<Entity>.columns.tsx` for `@tanstack/react-table`), and `tanstackGridHook()`.
|
|
3
|
+
TanStack codegen for MetaObjects. Provides `tanstackQuery()` (per-entity `<Entity>.hooks.ts` — 5 React Query hooks, plus a `use<Source><Relation>(sourceId, opts?)` collection hook per many-to-many relationship), `tanstackGrid()` (`<Entity>.columns.tsx` for `@tanstack/react-table`), and `tanstackGridHook()`.
|
|
4
|
+
|
|
5
|
+
### M:N collection hooks (FR-018)
|
|
6
|
+
|
|
7
|
+
For each many-to-many relationship a source entity declares (`@cardinality: "many"` + `@through`), `tanstackQuery()` emits a `use<Source><Relation>(sourceId, opts?)` hook. It is a `useQuery` that fetches the REST sub-resource `GET /<source-plural>/{sourceId}/<relationName>` (the exact URL the generated route serves) and returns the typed target collection (`<Target>[]`). The query is enabled only when `sourceId` is present, so it is safe to call before the parent row loads. A symmetric self-join still produces a single collection hook (the server unions both junction columns on read).
|
|
4
8
|
|
|
5
9
|
## Install
|
|
6
10
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack-grid-hook.d.ts","sourceRoot":"","sources":["../src/tanstack-grid-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,EAA6B,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"tanstack-grid-hook.d.ts","sourceRoot":"","sources":["../src/tanstack-grid-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,EAA6B,KAAK,gBAAgB,EAAkF,MAAM,4BAA4B,CAAC;AAG9K,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EA6BxB,gBAAgB,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LAYOUT_SUBTYPE_DATA_GRID } from "@metaobjectsdev/metadata";
|
|
2
|
-
import { perEntity, formatTs, entityOutputPath, emitsInstanceArtifacts } from "@metaobjectsdev/codegen-ts";
|
|
2
|
+
import { perEntity, formatTs, entityOutputPath, emitsInstanceArtifacts, CODEGEN_ATTR_EMIT_TANSTACK } from "@metaobjectsdev/codegen-ts";
|
|
3
3
|
import { renderGridHookFile } from "./templates/grid-hook-file.js";
|
|
4
4
|
function hasDataGridLayout(entity) {
|
|
5
5
|
// layouts() is effective — own + inherited layouts (from extends:/super:).
|
|
@@ -19,7 +19,7 @@ export const tanstackGridHook = function tanstackGridHook(opts) {
|
|
|
19
19
|
// AND-composes the framework instance-artifact guard (skips abstract types),
|
|
20
20
|
// opt-out, user filter, and dataGrid layout presence.
|
|
21
21
|
filter: (e) => emitsInstanceArtifacts(e)
|
|
22
|
-
&& e.ownAttr(
|
|
22
|
+
&& e.ownAttr(CODEGEN_ATTR_EMIT_TANSTACK) !== false
|
|
23
23
|
&& userFilter(e)
|
|
24
24
|
&& hasDataGridLayout(e),
|
|
25
25
|
generate: perEntity(async (entity, ctx) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack-grid-hook.js","sourceRoot":"","sources":["../src/tanstack-grid-hook.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAyC,QAAQ,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"tanstack-grid-hook.js","sourceRoot":"","sources":["../src/tanstack-grid-hook.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAyC,QAAQ,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC9K,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAOnE,SAAS,iBAAiB,CAAC,MAAkB;IAC3C,2EAA2E;IAC3E,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,wBAAwB,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,gBAAgB,CAAC,IAA2B;IACnF,MAAM,UAAU,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,SAAS,GAAc;QAC3B,IAAI,EAAE,oBAAoB;QAC1B,6EAA6E;QAC7E,sDAAsD;QACtD,MAAM,EAAE,CAAC,CAAa,EAAE,EAAE,CACxB,sBAAsB,CAAC,CAAC,CAAC;eACtB,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC,KAAK,KAAK;eAC/C,UAAU,CAAC,CAAC,CAAC;eACb,iBAAiB,CAAC,CAAC,CAAC;QACzB,QAAQ,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;YACxC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;YACxF,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,gBAAgB,CACpB,GAAG,CAAC,aAAa,CAAC,YAAY,EAC9B,MAAM,CAAC,OAAO,EACd,GAAG,MAAM,CAAC,IAAI,UAAU,CACzB;gBACD,OAAO,EAAE,MAAM,QAAQ,CAAC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;aACvE,CAAC;QACJ,CAAC,CAAC;KACH,CAAC;IACF,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAkD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack-grid.d.ts","sourceRoot":"","sources":["../src/tanstack-grid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,EAA6B,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"tanstack-grid.d.ts","sourceRoot":"","sources":["../src/tanstack-grid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,EAA6B,KAAK,gBAAgB,EAAwH,MAAM,4BAA4B,CAAC;AAGpN,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD;;;;GAIG;AACH,eAAO,MAAM,YAAY,EA8BpB,gBAAgB,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC"}
|
package/dist/tanstack-grid.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LAYOUT_SUBTYPE_DATA_GRID } from "@metaobjectsdev/metadata";
|
|
2
|
-
import { perEntity, formatTs, entityOutputPath, emitsInstanceArtifacts } from "@metaobjectsdev/codegen-ts";
|
|
2
|
+
import { perEntity, formatTs, entityOutputPath, emitsInstanceArtifacts, isTphSubtype, CODEGEN_ATTR_EMIT_TANSTACK, CODEGEN_ATTR_EMIT_GRID } from "@metaobjectsdev/codegen-ts";
|
|
3
3
|
import { renderColumnsFile } from "./templates/columns-file.js";
|
|
4
4
|
function hasDataGridLayout(entity) {
|
|
5
5
|
// layouts() is effective — own + inherited layouts (from extends:/super:).
|
|
@@ -16,10 +16,15 @@ export const tanstackGrid = function tanstackGrid(opts) {
|
|
|
16
16
|
name: "tanstack-grid",
|
|
17
17
|
// Always set: AND-composes the framework instance-artifact guard (skips
|
|
18
18
|
// abstract types), opt-out, user filter, and dataGrid layout presence.
|
|
19
|
+
// FR-017 Tier 3: a TPH discriminator base emits ONE polymorphic grid. Its
|
|
20
|
+
// subtypes inherit the base's dataGrid layout via extends, but per-subtype
|
|
21
|
+
// grids are opt-IN only (own `@emitGrid: true`) — otherwise the polymorphic
|
|
22
|
+
// grid is the single source of truth.
|
|
19
23
|
filter: (e) => emitsInstanceArtifacts(e)
|
|
20
|
-
&& e.ownAttr(
|
|
24
|
+
&& e.ownAttr(CODEGEN_ATTR_EMIT_TANSTACK) !== false
|
|
21
25
|
&& userFilter(e)
|
|
22
|
-
&& hasDataGridLayout(e)
|
|
26
|
+
&& hasDataGridLayout(e)
|
|
27
|
+
&& (!isTphSubtype(e) || e.ownAttr(CODEGEN_ATTR_EMIT_GRID) === true),
|
|
23
28
|
generate: perEntity(async (entity, ctx) => {
|
|
24
29
|
if (!ctx.renderContext) {
|
|
25
30
|
throw new Error("tanstack-grid: renderContext is required (provided by runGen)");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack-grid.js","sourceRoot":"","sources":["../src/tanstack-grid.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAyC,QAAQ,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"tanstack-grid.js","sourceRoot":"","sources":["../src/tanstack-grid.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAyC,QAAQ,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,YAAY,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpN,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAOhE,SAAS,iBAAiB,CAAC,MAAkB;IAC3C,2EAA2E;IAC3E,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,wBAAwB,CAAC,CAAC;AAC9E,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,YAAY,CAAC,IAAuB;IACvE,MAAM,UAAU,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,SAAS,GAAc;QAC3B,IAAI,EAAE,eAAe;QACrB,wEAAwE;QACxE,uEAAuE;QACvE,0EAA0E;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,sCAAsC;QACtC,MAAM,EAAE,CAAC,CAAa,EAAE,EAAE,CACxB,sBAAsB,CAAC,CAAC,CAAC;eACtB,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC,KAAK,KAAK;eAC/C,UAAU,CAAC,CAAC,CAAC;eACb,iBAAiB,CAAC,CAAC,CAAC;eACpB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,KAAK,IAAI,CAAC;QACrE,QAAQ,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;YACxC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;YACnF,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,gBAAgB,CAAC,GAAG,CAAC,aAAa,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,IAAI,cAAc,CAAC;gBACpG,OAAO,EAAE,MAAM,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;aACtE,CAAC;QACJ,CAAC,CAAC;KACH,CAAC;IACF,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAA8C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack-query.d.ts","sourceRoot":"","sources":["../src/tanstack-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAA6B,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"tanstack-query.d.ts","sourceRoot":"","sources":["../src/tanstack-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAA6B,KAAK,gBAAgB,EAAgG,MAAM,4BAA4B,CAAC;AAG5L,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EA2BrB,gBAAgB,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC"}
|
package/dist/tanstack-query.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { perEntity, formatTs, entityOutputPath, emitsInstanceArtifacts } from "@metaobjectsdev/codegen-ts";
|
|
1
|
+
import { perEntity, formatTs, entityOutputPath, emitsInstanceArtifacts, isTphSubtype, CODEGEN_ATTR_EMIT_TANSTACK } from "@metaobjectsdev/codegen-ts";
|
|
2
2
|
import { renderHooksFile } from "./templates/hooks-file.js";
|
|
3
3
|
/**
|
|
4
4
|
* Per-entity generator that emits <Entity>.hooks.ts — a query-key factory
|
|
@@ -15,7 +15,9 @@ export const tanstackQuery = function tanstackQuery(opts) {
|
|
|
15
15
|
// they contribute shape via inheritance only and have no instance to query),
|
|
16
16
|
// the metadata opt-out, and the optional user filter. Projections still pass
|
|
17
17
|
// here and get read-only hooks via renderHooksFile's isProjection branch.
|
|
18
|
-
|
|
18
|
+
// FR-017 Tier 3: TPH subtypes get no standalone hooks file — their per-subtype
|
|
19
|
+
// hooks live in the discriminator base's hooks file (polymorphic + per-subtype).
|
|
20
|
+
filter: (e) => emitsInstanceArtifacts(e) && e.ownAttr(CODEGEN_ATTR_EMIT_TANSTACK) !== false && !isTphSubtype(e) && userFilter(e),
|
|
19
21
|
generate: perEntity(async (entity, ctx) => {
|
|
20
22
|
if (!ctx.renderContext) {
|
|
21
23
|
throw new Error("tanstack-query: renderContext is required (provided by runGen)");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstack-query.js","sourceRoot":"","sources":["../src/tanstack-query.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAyC,QAAQ,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"tanstack-query.js","sourceRoot":"","sources":["../src/tanstack-query.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAyC,QAAQ,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC5L,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAO5D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,aAAa,CAAC,IAAwB;IAC1E,MAAM,UAAU,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,SAAS,GAAc;QAC3B,IAAI,EAAE,gBAAgB;QACtB,6EAA6E;QAC7E,6EAA6E;QAC7E,6EAA6E;QAC7E,0EAA0E;QAC1E,+EAA+E;QAC/E,iFAAiF;QACjF,MAAM,EAAE,CAAC,CAAa,EAAE,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC,KAAK,KAAK,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC;QAC5I,QAAQ,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;YACxC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,gBAAgB,CAAC,GAAG,CAAC,aAAa,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,IAAI,WAAW,CAAC;gBACjG,OAAO,EAAE,MAAM,QAAQ,CAAC,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;aACpE,CAAC;QACJ,CAAC,CAAC;KACH,CAAC;IACF,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAA+C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"columns-file.d.ts","sourceRoot":"","sources":["../../src/templates/columns-file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"columns-file.d.ts","sourceRoot":"","sources":["../../src/templates/columns-file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,0BAA0B,CAAC;AAWtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAwIhE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAgFhF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { code, imp, joinCode } from "ts-poet";
|
|
2
|
-
import { LAYOUT_SUBTYPE_DATA_GRID, LAYOUT_DATA_GRID_ATTR_PAGE_SIZE, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER, LAYOUT_DATA_GRID_ATTR_FILTERABLE, LAYOUT_DATA_GRID_ATTR_FILTER, LAYOUT_DATA_GRID_ATTR_COLUMNS, } from "@metaobjectsdev/metadata";
|
|
3
|
-
import { GENERATED_HEADER, entityModuleSpecifier } from "@metaobjectsdev/codegen-ts";
|
|
2
|
+
import { LAYOUT_SUBTYPE_DATA_GRID, LAYOUT_DATA_GRID_ATTR_PAGE_SIZE, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER, LAYOUT_DATA_GRID_ATTR_FILTERABLE, LAYOUT_DATA_GRID_ATTR_FILTER, LAYOUT_DATA_GRID_ATTR_COLUMNS, OBJECT_ATTR_DISCRIMINATOR, } from "@metaobjectsdev/metadata";
|
|
3
|
+
import { GENERATED_HEADER, entityModuleSpecifier, isTphDiscriminatorBase, collectTphSubtypeFields, } from "@metaobjectsdev/codegen-ts";
|
|
4
4
|
function humanize(s) {
|
|
5
5
|
return s
|
|
6
6
|
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
@@ -25,9 +25,11 @@ function fieldLabel(field) {
|
|
|
25
25
|
* fall back to all fields on the entity (pre-E-T2 behaviour, kept for
|
|
26
26
|
* backwards compat with metadata not yet migrated by E-T4).
|
|
27
27
|
*/
|
|
28
|
-
function extractGrids(entity) {
|
|
28
|
+
function extractGrids(entity, tph) {
|
|
29
29
|
// fields() and layouts() are both effective (own + inherited via extends:/super:).
|
|
30
|
-
|
|
30
|
+
// For a TPH base, also index the subtype-only fields so they can be folded
|
|
31
|
+
// into the polymorphic grid's column set.
|
|
32
|
+
const fieldsByName = new Map([...entity.fields(), ...(tph?.subtypeFields ?? [])].map((f) => [f.name, f]));
|
|
31
33
|
const grids = [];
|
|
32
34
|
for (const layout of entity.layouts()) {
|
|
33
35
|
if (layout.subType !== LAYOUT_SUBTYPE_DATA_GRID)
|
|
@@ -38,6 +40,16 @@ function extractGrids(entity) {
|
|
|
38
40
|
const columnNames = Array.isArray(columnsAttr)
|
|
39
41
|
? columnsAttr.filter((x) => typeof x === "string")
|
|
40
42
|
: [...fieldsByName.keys()];
|
|
43
|
+
// FR-017: a polymorphic (TPH base) grid folds in every subtype-only column
|
|
44
|
+
// so mixed rows can render their subtype fields (the runtime grid renders a
|
|
45
|
+
// null cell as an em-dash for rows of other subtypes). Appended after the
|
|
46
|
+
// declared columns, deduped.
|
|
47
|
+
if (tph) {
|
|
48
|
+
for (const f of tph.subtypeFields) {
|
|
49
|
+
if (!columnNames.includes(f.name))
|
|
50
|
+
columnNames.push(f.name);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
41
53
|
const columns = columnNames.flatMap((name) => {
|
|
42
54
|
const field = fieldsByName.get(name);
|
|
43
55
|
if (!field)
|
|
@@ -47,6 +59,9 @@ function extractGrids(entity) {
|
|
|
47
59
|
header: fieldLabel(field),
|
|
48
60
|
viewKind: fieldViewKind(field),
|
|
49
61
|
};
|
|
62
|
+
// FR-017: the discriminator column renders as a subtype badge.
|
|
63
|
+
if (tph && name === tph.discField)
|
|
64
|
+
spec.renderer = "badge";
|
|
50
65
|
return [spec];
|
|
51
66
|
});
|
|
52
67
|
const sortField = layout.ownAttr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD);
|
|
@@ -87,7 +102,17 @@ function renderColumnDef(col) {
|
|
|
87
102
|
export function renderColumnsFile(entity, ctx) {
|
|
88
103
|
const entityName = entity.name;
|
|
89
104
|
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
90
|
-
|
|
105
|
+
// FR-017: a TPH discriminator base emits a polymorphic grid typed against the
|
|
106
|
+
// raw single-table row (<Base>Row — all columns, subtype-only nullable),
|
|
107
|
+
// NOT the discriminated union (whose members lack the other subtypes' fields).
|
|
108
|
+
const tphBase = isTphDiscriminatorBase(entity, ctx.loadedRoot);
|
|
109
|
+
const tph = tphBase
|
|
110
|
+
? {
|
|
111
|
+
discField: entity.ownAttr(OBJECT_ATTR_DISCRIMINATOR) ?? "",
|
|
112
|
+
subtypeFields: collectTphSubtypeFields(entity, ctx.loadedRoot),
|
|
113
|
+
}
|
|
114
|
+
: undefined;
|
|
115
|
+
const grids = extractGrids(entity, tph);
|
|
91
116
|
const ColumnDefSym = imp("t:ColumnDef@@tanstack/react-table");
|
|
92
117
|
// Track whether any grid emits a filter const so we know to import <Entity>Filter.
|
|
93
118
|
let hasFilterConst = false;
|
|
@@ -130,9 +155,12 @@ export const ${filterConstName}: ${entityName}Filter = ${JSON.stringify(grid.fil
|
|
|
130
155
|
// target → importBase-qualified package path.
|
|
131
156
|
const entityModule = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, entity.package, entityName, ctx.extStyle);
|
|
132
157
|
// Import <Entity>Row always; import <Entity>Filter only when a filter const is emitted.
|
|
158
|
+
// TPH base: <Base>Row is a distinct export (the all-columns row); import it
|
|
159
|
+
// directly. Non-TPH: the entity type IS the row, imported under the Row alias.
|
|
160
|
+
const rowImport = tphBase ? `${entityName}Row` : `${entityName} as ${entityName}Row`;
|
|
133
161
|
const entityImportCode = hasFilterConst
|
|
134
|
-
? code `import type { ${
|
|
135
|
-
: code `import type { ${
|
|
162
|
+
? code `import type { ${rowImport}, ${entityName}Filter } from ${JSON.stringify(entityModule)};`
|
|
163
|
+
: code `import type { ${rowImport} } from ${JSON.stringify(entityModule)};`;
|
|
136
164
|
const body = joinCode(sections, { on: "\n" });
|
|
137
165
|
return header + entityImportCode.toString() + "\n" + body.toString();
|
|
138
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"columns-file.js","sourceRoot":"","sources":["../../src/templates/columns-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAa,MAAM,SAAS,CAAC;AAEzD,OAAO,EACL,wBAAwB,EACxB,+BAA+B,EAC/B,wCAAwC,EACxC,wCAAwC,EACxC,gCAAgC,EAChC,4BAA4B,EAC5B,6BAA6B,
|
|
1
|
+
{"version":3,"file":"columns-file.js","sourceRoot":"","sources":["../../src/templates/columns-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-file.d.ts","sourceRoot":"","sources":["../../src/templates/hooks-file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"hooks-file.d.ts","sourceRoot":"","sources":["../../src/templates/hooks-file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,4BAA4B,CAAC;AAU/E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAmB9E"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { code, imp, joinCode } from "ts-poet";
|
|
2
|
-
import { GENERATED_HEADER, isProjection, pluralize, entityModuleSpecifier } from "@metaobjectsdev/codegen-ts";
|
|
1
|
+
import { code, imp, joinCode, Import } from "ts-poet";
|
|
2
|
+
import { GENERATED_HEADER, isProjection, pluralize, entityModuleSpecifier, isTphDiscriminatorBase, tphPlan, } from "@metaobjectsdev/codegen-ts";
|
|
3
3
|
/**
|
|
4
4
|
* Render <Entity>.hooks.ts — query-key factory + 2 query hooks + (for non-projections) 3 mutation hooks.
|
|
5
5
|
*
|
|
@@ -20,19 +20,97 @@ export function renderHooksFile(entity, ctx) {
|
|
|
20
20
|
// Import the entity's own file. Same target → relative "./Entity"; cross
|
|
21
21
|
// target → importBase-qualified package path.
|
|
22
22
|
const entityModule = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, entity.package, entity.name, ctx.extStyle);
|
|
23
|
+
// FR-017 Tier 3: a TPH discriminator base gets a polymorphic + per-subtype
|
|
24
|
+
// hooks file (the subtype entities are filtered out of this generator).
|
|
25
|
+
if (isTphDiscriminatorBase(entity, ctx.loadedRoot)) {
|
|
26
|
+
return renderTphHooksFile(entity, ctx, entityModule);
|
|
27
|
+
}
|
|
23
28
|
if (isProjection(entity)) {
|
|
24
|
-
return renderReadOnlyHooksFile(entity, entityModule);
|
|
29
|
+
return renderReadOnlyHooksFile(entity, entityModule, ctx);
|
|
25
30
|
}
|
|
26
|
-
return renderFullHooksFile(entity, entityModule);
|
|
31
|
+
return renderFullHooksFile(entity, entityModule, ctx);
|
|
32
|
+
}
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// FR-018 — M:N collection hook(s).
|
|
35
|
+
//
|
|
36
|
+
// For each many-to-many relationship the source declares (`@cardinality: "many"`
|
|
37
|
+
// + `@through`), emit `use<Source><Relation>(sourceId, opts?)` — a useQuery that
|
|
38
|
+
// fetches the REST sub-resource `GET /<source-plural>/{sourceId}/<relationName>`
|
|
39
|
+
// (the exact URL mountM2mRoute serves) and returns the typed target collection
|
|
40
|
+
// (`Target[]`). The query is enabled only when sourceId is present, so callers
|
|
41
|
+
// can pass `undefined` before the parent row loads. A symmetric self-join is
|
|
42
|
+
// still ONE collection hook (the server unions both junction columns on read).
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
/** The M:N relation entries for an entity (cardinality 'many' + a junction). */
|
|
45
|
+
function m2mEntriesFor(entity, ctx) {
|
|
46
|
+
return (ctx.relationMap.get(entity.name) ?? []).filter((e) => e.cardinality === "many" && e.junctionEntity !== undefined);
|
|
47
|
+
}
|
|
48
|
+
/** The `relation: (relation, sourceId) => ...` query-key factory line, included
|
|
49
|
+
* in the keys factory ONLY when the entity has M:N relationships. */
|
|
50
|
+
function m2mKeyLine(keysVar) {
|
|
51
|
+
return (` relation: (relation: string, sourceId: number | undefined) =>\n` +
|
|
52
|
+
` [...${keysVar}.all(), "relation", relation, sourceId ?? null] as const,`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Render `use<Source><Relation>(sourceId, opts?)` per M:N relationship. Returns
|
|
56
|
+
* null when the entity has no M:N relationships (no extra hooks emitted).
|
|
57
|
+
*/
|
|
58
|
+
function renderM2mHooks(entity, ctx, keysVar, entries) {
|
|
59
|
+
if (entries.length === 0)
|
|
60
|
+
return null;
|
|
61
|
+
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
62
|
+
const useQueryOptionsSym = imp("t:UseQueryOptions@@tanstack/react-query");
|
|
63
|
+
const useQueryResultSym = imp("t:UseQueryResult@@tanstack/react-query");
|
|
64
|
+
const useEntityFetcherSym = imp("useEntityFetcher@@metaobjectsdev/tanstack");
|
|
65
|
+
const source = entity.name;
|
|
66
|
+
// Distinct target row types, imported (aliased) from each target's entity
|
|
67
|
+
// module. ts-poet's imp() tracks + hoists these into the import block. The
|
|
68
|
+
// <Target>RelRow alias avoids colliding with the source file's own
|
|
69
|
+
// `type <Source> as <Source>Row` import on a self-join (source === target).
|
|
70
|
+
const targetTypeSym = new Map();
|
|
71
|
+
for (const e of entries) {
|
|
72
|
+
if (targetTypeSym.has(e.targetEntity))
|
|
73
|
+
continue;
|
|
74
|
+
const mod = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, ctx.packageOf.get(e.targetEntity), e.targetEntity, ctx.extStyle);
|
|
75
|
+
// `import { type <Target> as <Target>RelRow } from "<mod>"` — the RelRow
|
|
76
|
+
// alias avoids colliding with the source file's own `type <Source> as
|
|
77
|
+
// <Source>Row` import on a self-join (source === target).
|
|
78
|
+
targetTypeSym.set(e.targetEntity, Import.importsName(`${e.targetEntity}RelRow`, mod, true, e.targetEntity));
|
|
79
|
+
}
|
|
80
|
+
const hooks = entries.map((e) => {
|
|
81
|
+
const targetSym = targetTypeSym.get(e.targetEntity);
|
|
82
|
+
const hookName = `use${source}${capitalize(e.name)}`;
|
|
83
|
+
const relLit = JSON.stringify(e.name);
|
|
84
|
+
return code `
|
|
85
|
+
export function ${hookName}(
|
|
86
|
+
sourceId: number | undefined,
|
|
87
|
+
opts?: Omit<${useQueryOptionsSym}<${targetSym}[]>, "queryKey" | "queryFn">,
|
|
88
|
+
): ${useQueryResultSym}<${targetSym}[]> {
|
|
89
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
90
|
+
return ${useQuerySym}<${targetSym}[]>({
|
|
91
|
+
queryKey: ${keysVar}.relation(${relLit}, sourceId),
|
|
92
|
+
queryFn: () => fetcher<${targetSym}[]>(\`\${${source}.$apiPrefix}\${${source}.$path}/\${sourceId}/${e.name}\`),
|
|
93
|
+
enabled: sourceId != null && (opts?.enabled ?? true),
|
|
94
|
+
...opts,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
});
|
|
99
|
+
return joinCode(hooks, { on: "\n" });
|
|
100
|
+
}
|
|
101
|
+
function capitalize(s) {
|
|
102
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
27
103
|
}
|
|
28
104
|
// ---------------------------------------------------------------------------
|
|
29
105
|
// Read-only path (projections)
|
|
30
106
|
// ---------------------------------------------------------------------------
|
|
31
|
-
function renderReadOnlyHooksFile(entity, entityModule) {
|
|
107
|
+
function renderReadOnlyHooksFile(entity, entityModule, ctx) {
|
|
32
108
|
const entityName = entity.name;
|
|
33
109
|
const entityNamePlural = pluralize(entityName);
|
|
34
110
|
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
35
111
|
const keysVar = `${lcEntity}Keys`;
|
|
112
|
+
const m2mEntries = m2mEntriesFor(entity, ctx);
|
|
113
|
+
const relationKeyLine = m2mEntries.length > 0 ? `\n${m2mKeyLine(keysVar)}` : "";
|
|
36
114
|
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
37
115
|
const useQueryOptionsSym = imp("t:UseQueryOptions@@tanstack/react-query");
|
|
38
116
|
const useQueryResultSym = imp("t:UseQueryResult@@tanstack/react-query");
|
|
@@ -51,7 +129,7 @@ export const ${keysVar} = {
|
|
|
51
129
|
lists: () => [...${keysVar}.all(), "list"] as const,
|
|
52
130
|
list: (filter?: ${entityName}Filter) => [...${keysVar}.lists(), filter ?? {}] as const,
|
|
53
131
|
details: () => [...${keysVar}.all(), "detail"] as const,
|
|
54
|
-
detail: (id: number) => [...${keysVar}.details(), id] as const
|
|
132
|
+
detail: (id: number) => [...${keysVar}.details(), id] as const,${relationKeyLine}
|
|
55
133
|
};
|
|
56
134
|
`;
|
|
57
135
|
const queries = code `
|
|
@@ -80,7 +158,8 @@ export function use${entityNamePlural}(
|
|
|
80
158
|
});
|
|
81
159
|
}
|
|
82
160
|
`;
|
|
83
|
-
const
|
|
161
|
+
const m2mHooks = renderM2mHooks(entity, ctx, keysVar, m2mEntries);
|
|
162
|
+
const body = joinCode(m2mHooks ? [queryKeys, queries, m2mHooks] : [queryKeys, queries], { on: "\n" });
|
|
84
163
|
const header = `// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
85
164
|
`// Source metadata: ${entityName} (${entity.fqn()})\n`;
|
|
86
165
|
return header + entityImports.toString() + body.toString();
|
|
@@ -88,11 +167,13 @@ export function use${entityNamePlural}(
|
|
|
88
167
|
// ---------------------------------------------------------------------------
|
|
89
168
|
// Full path (writable entities — table-backed or write-through)
|
|
90
169
|
// ---------------------------------------------------------------------------
|
|
91
|
-
function renderFullHooksFile(entity, entityModule) {
|
|
170
|
+
function renderFullHooksFile(entity, entityModule, ctx) {
|
|
92
171
|
const entityName = entity.name;
|
|
93
172
|
const entityNamePlural = pluralize(entityName);
|
|
94
173
|
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
95
174
|
const keysVar = `${lcEntity}Keys`;
|
|
175
|
+
const m2mEntries = m2mEntriesFor(entity, ctx);
|
|
176
|
+
const relationKeyLine = m2mEntries.length > 0 ? `\n${m2mKeyLine(keysVar)}` : "";
|
|
96
177
|
const useMutationSym = imp("useMutation@@tanstack/react-query");
|
|
97
178
|
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
98
179
|
const useQueryClientSym = imp("useQueryClient@@tanstack/react-query");
|
|
@@ -117,7 +198,7 @@ export const ${keysVar} = {
|
|
|
117
198
|
lists: () => [...${keysVar}.all(), "list"] as const,
|
|
118
199
|
list: (filter?: ${entityName}Filter) => [...${keysVar}.lists(), filter ?? {}] as const,
|
|
119
200
|
details: () => [...${keysVar}.all(), "detail"] as const,
|
|
120
|
-
detail: (id: number) => [...${keysVar}.details(), id] as const
|
|
201
|
+
detail: (id: number) => [...${keysVar}.details(), id] as const,${relationKeyLine}
|
|
121
202
|
};
|
|
122
203
|
`;
|
|
123
204
|
const queries = code `
|
|
@@ -146,6 +227,7 @@ export function use${entityNamePlural}(
|
|
|
146
227
|
});
|
|
147
228
|
}
|
|
148
229
|
`;
|
|
230
|
+
const m2mHooks = renderM2mHooks(entity, ctx, keysVar, m2mEntries);
|
|
149
231
|
const mutations = code `
|
|
150
232
|
export function useCreate${entityName}(
|
|
151
233
|
opts?: Omit<${useMutationOptionsSym}<${entityName}Row, Error, ${entityName}Insert>, "mutationFn">,
|
|
@@ -200,9 +282,178 @@ export function useDelete${entityName}(
|
|
|
200
282
|
});
|
|
201
283
|
}
|
|
202
284
|
`;
|
|
203
|
-
const body = joinCode([queryKeys, queries, mutations], { on: "\n" });
|
|
285
|
+
const body = joinCode(m2mHooks ? [queryKeys, queries, m2mHooks, mutations] : [queryKeys, queries, mutations], { on: "\n" });
|
|
204
286
|
const header = `// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
205
287
|
`// Source metadata: ${entityName} (${entity.fqn()})\n`;
|
|
206
288
|
return header + entityImports.toString() + body.toString();
|
|
207
289
|
}
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
// FR-017 Tier 3 — TPH discriminator base: polymorphic + per-subtype hooks.
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
function renderTphHooksFile(base, ctx, baseModule) {
|
|
294
|
+
const baseName = base.name;
|
|
295
|
+
const lcBase = baseName.charAt(0).toLowerCase() + baseName.slice(1);
|
|
296
|
+
const keysVar = `${lcBase}Keys`;
|
|
297
|
+
// Single source of truth for discriminator field + subtypes + route segments.
|
|
298
|
+
const plan = tphPlan(base, ctx.loadedRoot);
|
|
299
|
+
const discField = plan.discriminatorField;
|
|
300
|
+
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
301
|
+
const useMutationSym = imp("useMutation@@tanstack/react-query");
|
|
302
|
+
const useQueryClientSym = imp("useQueryClient@@tanstack/react-query");
|
|
303
|
+
const useQueryOptionsSym = imp("t:UseQueryOptions@@tanstack/react-query");
|
|
304
|
+
const useMutationOptionsSym = imp("t:UseMutationOptions@@tanstack/react-query");
|
|
305
|
+
const useQueryResultSym = imp("t:UseQueryResult@@tanstack/react-query");
|
|
306
|
+
const useMutationResultSym = imp("t:UseMutationResult@@tanstack/react-query");
|
|
307
|
+
const useEntityFetcherSym = imp("useEntityFetcher@@metaobjectsdev/tanstack");
|
|
308
|
+
const buildFilterQsSym = imp("buildFilterQs@@metaobjectsdev/runtime-web");
|
|
309
|
+
const subtypes = plan.subtypes;
|
|
310
|
+
// `${baseName}` imports BOTH the constants value (for $path/$apiPrefix) and the
|
|
311
|
+
// discriminated-union type (declaration merge). Each subtype contributes its
|
|
312
|
+
// interface type AND its own filter type (discriminator-excluded — the route
|
|
313
|
+
// pins it), so per-subtype hooks filter on the fields the per-subtype
|
|
314
|
+
// allowlist actually permits.
|
|
315
|
+
const subImportLines = subtypes
|
|
316
|
+
.map((s) => {
|
|
317
|
+
const m = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, s.entity.package, s.entity.name, ctx.extStyle);
|
|
318
|
+
return `import { type ${s.entity.name}, type ${s.entity.name}Filter } from ${JSON.stringify(m)};`;
|
|
319
|
+
})
|
|
320
|
+
.join("\n");
|
|
321
|
+
const entityImports = code `
|
|
322
|
+
import { ${baseName}, type ${baseName}Filter } from ${JSON.stringify(baseModule)};
|
|
323
|
+
${subImportLines}
|
|
324
|
+
`;
|
|
325
|
+
const queryKeys = code `
|
|
326
|
+
export const ${keysVar} = {
|
|
327
|
+
all: () => [${JSON.stringify(lcBase)}] as const,
|
|
328
|
+
lists: () => [...${keysVar}.all(), "list"] as const,
|
|
329
|
+
list: (filter?: ${baseName}Filter) => [...${keysVar}.lists(), filter ?? {}] as const,
|
|
330
|
+
details: () => [...${keysVar}.all(), "detail"] as const,
|
|
331
|
+
detail: (id: number) => [...${keysVar}.details(), id] as const,
|
|
332
|
+
subtypeLists: (sub: string) => [...${keysVar}.all(), sub, "list"] as const,
|
|
333
|
+
// filter is loosely typed here (cache-key identity only); the per-subtype
|
|
334
|
+
// hooks below type it precisely as <Sub>Filter.
|
|
335
|
+
subtypeList: (sub: string, filter?: unknown) => [...${keysVar}.subtypeLists(sub), filter ?? {}] as const,
|
|
336
|
+
subtypeDetails:(sub: string) => [...${keysVar}.all(), sub, "detail"] as const,
|
|
337
|
+
subtypeDetail: (sub: string, id: number) => [...${keysVar}.subtypeDetails(sub), id] as const,
|
|
338
|
+
};
|
|
339
|
+
`;
|
|
340
|
+
// Polymorphic reads — return the discriminated union.
|
|
341
|
+
const polymorphic = code `
|
|
342
|
+
export function use${baseName}(
|
|
343
|
+
id: number,
|
|
344
|
+
opts?: Omit<${useQueryOptionsSym}<${baseName}>, "queryKey" | "queryFn">,
|
|
345
|
+
): ${useQueryResultSym}<${baseName}> {
|
|
346
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
347
|
+
return ${useQuerySym}<${baseName}>({
|
|
348
|
+
queryKey: ${keysVar}.detail(id),
|
|
349
|
+
queryFn: () => fetcher<${baseName}>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/\${id}\`),
|
|
350
|
+
...opts,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function use${pluralize(baseName)}(
|
|
355
|
+
filter?: ${baseName}Filter,
|
|
356
|
+
opts?: Omit<${useQueryOptionsSym}<${baseName}[]>, "queryKey" | "queryFn">,
|
|
357
|
+
): ${useQueryResultSym}<${baseName}[]> {
|
|
358
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
359
|
+
const qs = filter ? "?" + ${buildFilterQsSym}(filter as Record<string, unknown>) : "";
|
|
360
|
+
return ${useQuerySym}<${baseName}[]>({
|
|
361
|
+
queryKey: ${keysVar}.list(filter),
|
|
362
|
+
queryFn: () => fetcher<${baseName}[]>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}\${qs}\`),
|
|
363
|
+
...opts,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
`;
|
|
367
|
+
// Per-subtype hooks — scoped to each discriminator value's REST sub-path.
|
|
368
|
+
const subtypeSections = subtypes.map(({ entity: subEntity, value, routeSegment: seg }) => {
|
|
369
|
+
const subName = subEntity.name;
|
|
370
|
+
const valueLit = JSON.stringify(value);
|
|
371
|
+
const createInput = `Omit<${subName}, ${JSON.stringify(discField)}>`;
|
|
372
|
+
const updateInput = `Partial<${createInput}>`;
|
|
373
|
+
const subPath = `\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}\``;
|
|
374
|
+
return code `
|
|
375
|
+
export function use${pluralize(subName)}(
|
|
376
|
+
filter?: ${subName}Filter,
|
|
377
|
+
opts?: Omit<${useQueryOptionsSym}<${subName}[]>, "queryKey" | "queryFn">,
|
|
378
|
+
): ${useQueryResultSym}<${subName}[]> {
|
|
379
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
380
|
+
const qs = filter ? "?" + ${buildFilterQsSym}(filter as Record<string, unknown>) : "";
|
|
381
|
+
return ${useQuerySym}<${subName}[]>({
|
|
382
|
+
queryKey: ${keysVar}.subtypeList(${valueLit}, filter),
|
|
383
|
+
queryFn: () => fetcher<${subName}[]>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}\${qs}\`),
|
|
384
|
+
...opts,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export function use${subName}(
|
|
389
|
+
id: number,
|
|
390
|
+
opts?: Omit<${useQueryOptionsSym}<${subName}>, "queryKey" | "queryFn">,
|
|
391
|
+
): ${useQueryResultSym}<${subName}> {
|
|
392
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
393
|
+
return ${useQuerySym}<${subName}>({
|
|
394
|
+
queryKey: ${keysVar}.subtypeDetail(${valueLit}, id),
|
|
395
|
+
queryFn: () => fetcher<${subName}>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}/\${id}\`),
|
|
396
|
+
...opts,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function useCreate${subName}(
|
|
401
|
+
opts?: Omit<${useMutationOptionsSym}<${subName}, Error, ${createInput}>, "mutationFn">,
|
|
402
|
+
): ${useMutationResultSym}<${subName}, Error, ${createInput}> {
|
|
403
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
404
|
+
const qc = ${useQueryClientSym}();
|
|
405
|
+
return ${useMutationSym}<${subName}, Error, ${createInput}>({
|
|
406
|
+
mutationFn: (input) => fetcher<${subName}>(${subPath}, {
|
|
407
|
+
method: "POST",
|
|
408
|
+
headers: { "Content-Type": "application/json" },
|
|
409
|
+
body: JSON.stringify(input),
|
|
410
|
+
}),
|
|
411
|
+
...opts,
|
|
412
|
+
onSuccess: (...args) => {
|
|
413
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
414
|
+
opts?.onSuccess?.(...args);
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export function useUpdate${subName}(
|
|
420
|
+
opts?: Omit<${useMutationOptionsSym}<${subName}, Error, { id: number; input: ${updateInput} }>, "mutationFn">,
|
|
421
|
+
): ${useMutationResultSym}<${subName}, Error, { id: number; input: ${updateInput} }> {
|
|
422
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
423
|
+
const qc = ${useQueryClientSym}();
|
|
424
|
+
return ${useMutationSym}({
|
|
425
|
+
mutationFn: ({ id, input }) => fetcher<${subName}>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}/\${id}\`, {
|
|
426
|
+
method: "PATCH",
|
|
427
|
+
headers: { "Content-Type": "application/json" },
|
|
428
|
+
body: JSON.stringify(input),
|
|
429
|
+
}),
|
|
430
|
+
...opts,
|
|
431
|
+
onSuccess: (...args) => {
|
|
432
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
433
|
+
opts?.onSuccess?.(...args);
|
|
434
|
+
},
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
export function useDelete${subName}(
|
|
439
|
+
opts?: Omit<${useMutationOptionsSym}<void, Error, number>, "mutationFn">,
|
|
440
|
+
): ${useMutationResultSym}<void, Error, number> {
|
|
441
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
442
|
+
const qc = ${useQueryClientSym}();
|
|
443
|
+
return ${useMutationSym}({
|
|
444
|
+
mutationFn: (id) => fetcher<void>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}/\${id}\`, { method: "DELETE" }),
|
|
445
|
+
...opts,
|
|
446
|
+
onSuccess: (...args) => {
|
|
447
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
448
|
+
opts?.onSuccess?.(...args);
|
|
449
|
+
},
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
`;
|
|
453
|
+
});
|
|
454
|
+
const body = joinCode([queryKeys, polymorphic, ...subtypeSections], { on: "\n" });
|
|
455
|
+
const header = `// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
456
|
+
`// Source metadata: ${baseName} (${base.fqn()}) — TPH discriminator base\n`;
|
|
457
|
+
return header + entityImports.toString() + body.toString();
|
|
458
|
+
}
|
|
208
459
|
//# sourceMappingURL=hooks-file.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-file.js","sourceRoot":"","sources":["../../src/templates/hooks-file.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hooks-file.js","sourceRoot":"","sources":["../../src/templates/hooks-file.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/codegen-ts-tanstack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0-rc.1",
|
|
4
4
|
"description": "TanStack codegen for metaobjects — emits hooks and column definitions for TanStack Query and Table.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
"default": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"files": [
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
16
21
|
"scripts": {
|
|
17
22
|
"build": "tsc -p .",
|
|
18
23
|
"typecheck": "tsc -p tsconfig.typecheck.json"
|
|
@@ -21,28 +26,34 @@
|
|
|
21
26
|
"author": "Doug Mealing <doug@dougmealing.com>",
|
|
22
27
|
"homepage": "https://metaobjects.dev",
|
|
23
28
|
"bugs": {
|
|
24
|
-
|
|
25
|
-
},
|
|
26
|
-
"repository": {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
},
|
|
31
|
-
"keywords": [
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
29
|
+
"url": "https://github.com/metaobjectsdev/metaobjects/issues"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/metaobjectsdev/metaobjects.git",
|
|
34
|
+
"directory": "server/typescript/packages/codegen-ts-tanstack"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"metaobjects",
|
|
38
|
+
"codegen",
|
|
39
|
+
"tanstack",
|
|
40
|
+
"react-query",
|
|
41
|
+
"react-table"
|
|
42
|
+
],
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@metaobjectsdev/metadata": "0.11.0-rc.1",
|
|
48
|
+
"@metaobjectsdev/codegen-ts": "0.11.0-rc.1",
|
|
49
|
+
"ts-poet": "^6.10.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@biomejs/biome": ">=1.9.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@biomejs/biome": "^1.9.0",
|
|
56
|
+
"bun-types": "latest",
|
|
57
|
+
"typescript": "^5.6.0"
|
|
58
|
+
}
|
|
48
59
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
2
2
|
import { LAYOUT_SUBTYPE_DATA_GRID } from "@metaobjectsdev/metadata";
|
|
3
|
-
import { perEntity, type Generator, type GeneratorFactory, formatTs, entityOutputPath, emitsInstanceArtifacts } from "@metaobjectsdev/codegen-ts";
|
|
3
|
+
import { perEntity, type Generator, type GeneratorFactory, formatTs, entityOutputPath, emitsInstanceArtifacts, CODEGEN_ATTR_EMIT_TANSTACK } from "@metaobjectsdev/codegen-ts";
|
|
4
4
|
import { renderGridHookFile } from "./templates/grid-hook-file.js";
|
|
5
5
|
|
|
6
6
|
export interface TanstackGridHookOpts {
|
|
@@ -28,7 +28,7 @@ export const tanstackGridHook = function tanstackGridHook(opts?: TanstackGridHoo
|
|
|
28
28
|
// opt-out, user filter, and dataGrid layout presence.
|
|
29
29
|
filter: (e: MetaObject) =>
|
|
30
30
|
emitsInstanceArtifacts(e)
|
|
31
|
-
&& e.ownAttr(
|
|
31
|
+
&& e.ownAttr(CODEGEN_ATTR_EMIT_TANSTACK) !== false
|
|
32
32
|
&& userFilter(e)
|
|
33
33
|
&& hasDataGridLayout(e),
|
|
34
34
|
generate: perEntity(async (entity, ctx) => {
|
package/src/tanstack-grid.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
2
2
|
import { LAYOUT_SUBTYPE_DATA_GRID } from "@metaobjectsdev/metadata";
|
|
3
|
-
import { perEntity, type Generator, type GeneratorFactory, formatTs, entityOutputPath, emitsInstanceArtifacts } from "@metaobjectsdev/codegen-ts";
|
|
3
|
+
import { perEntity, type Generator, type GeneratorFactory, formatTs, entityOutputPath, emitsInstanceArtifacts, isTphSubtype, CODEGEN_ATTR_EMIT_TANSTACK, CODEGEN_ATTR_EMIT_GRID } from "@metaobjectsdev/codegen-ts";
|
|
4
4
|
import { renderColumnsFile } from "./templates/columns-file.js";
|
|
5
5
|
|
|
6
6
|
export interface TanstackGridOpts {
|
|
@@ -24,11 +24,16 @@ export const tanstackGrid = function tanstackGrid(opts?: TanstackGridOpts): Gene
|
|
|
24
24
|
name: "tanstack-grid",
|
|
25
25
|
// Always set: AND-composes the framework instance-artifact guard (skips
|
|
26
26
|
// abstract types), opt-out, user filter, and dataGrid layout presence.
|
|
27
|
+
// FR-017 Tier 3: a TPH discriminator base emits ONE polymorphic grid. Its
|
|
28
|
+
// subtypes inherit the base's dataGrid layout via extends, but per-subtype
|
|
29
|
+
// grids are opt-IN only (own `@emitGrid: true`) — otherwise the polymorphic
|
|
30
|
+
// grid is the single source of truth.
|
|
27
31
|
filter: (e: MetaObject) =>
|
|
28
32
|
emitsInstanceArtifacts(e)
|
|
29
|
-
&& e.ownAttr(
|
|
33
|
+
&& e.ownAttr(CODEGEN_ATTR_EMIT_TANSTACK) !== false
|
|
30
34
|
&& userFilter(e)
|
|
31
|
-
&& hasDataGridLayout(e)
|
|
35
|
+
&& hasDataGridLayout(e)
|
|
36
|
+
&& (!isTphSubtype(e) || e.ownAttr(CODEGEN_ATTR_EMIT_GRID) === true),
|
|
32
37
|
generate: perEntity(async (entity, ctx) => {
|
|
33
38
|
if (!ctx.renderContext) {
|
|
34
39
|
throw new Error("tanstack-grid: renderContext is required (provided by runGen)");
|
package/src/tanstack-query.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
2
|
-
import { perEntity, type Generator, type GeneratorFactory, formatTs, entityOutputPath, emitsInstanceArtifacts } from "@metaobjectsdev/codegen-ts";
|
|
2
|
+
import { perEntity, type Generator, type GeneratorFactory, formatTs, entityOutputPath, emitsInstanceArtifacts, isTphSubtype, CODEGEN_ATTR_EMIT_TANSTACK } from "@metaobjectsdev/codegen-ts";
|
|
3
3
|
import { renderHooksFile } from "./templates/hooks-file.js";
|
|
4
4
|
|
|
5
5
|
export interface TanstackQueryOpts {
|
|
@@ -22,7 +22,9 @@ export const tanstackQuery = function tanstackQuery(opts?: TanstackQueryOpts): G
|
|
|
22
22
|
// they contribute shape via inheritance only and have no instance to query),
|
|
23
23
|
// the metadata opt-out, and the optional user filter. Projections still pass
|
|
24
24
|
// here and get read-only hooks via renderHooksFile's isProjection branch.
|
|
25
|
-
|
|
25
|
+
// FR-017 Tier 3: TPH subtypes get no standalone hooks file — their per-subtype
|
|
26
|
+
// hooks live in the discriminator base's hooks file (polymorphic + per-subtype).
|
|
27
|
+
filter: (e: MetaObject) => emitsInstanceArtifacts(e) && e.ownAttr(CODEGEN_ATTR_EMIT_TANSTACK) !== false && !isTphSubtype(e) && userFilter(e),
|
|
26
28
|
generate: perEntity(async (entity, ctx) => {
|
|
27
29
|
if (!ctx.renderContext) {
|
|
28
30
|
throw new Error(
|
|
@@ -8,9 +8,23 @@ import {
|
|
|
8
8
|
LAYOUT_DATA_GRID_ATTR_FILTERABLE,
|
|
9
9
|
LAYOUT_DATA_GRID_ATTR_FILTER,
|
|
10
10
|
LAYOUT_DATA_GRID_ATTR_COLUMNS,
|
|
11
|
+
OBJECT_ATTR_DISCRIMINATOR,
|
|
11
12
|
} from "@metaobjectsdev/metadata";
|
|
12
13
|
import type { RenderContext } from "@metaobjectsdev/codegen-ts";
|
|
13
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
GENERATED_HEADER,
|
|
16
|
+
entityModuleSpecifier,
|
|
17
|
+
isTphDiscriminatorBase,
|
|
18
|
+
collectTphSubtypeFields,
|
|
19
|
+
} from "@metaobjectsdev/codegen-ts";
|
|
20
|
+
|
|
21
|
+
/** FR-017 TPH grid context, threaded into extractGrids when the entity is a
|
|
22
|
+
* discriminator base: the discriminator field name (badged in the polymorphic
|
|
23
|
+
* grid) and the subtype-only fields folded in as extra columns. */
|
|
24
|
+
interface TphGridInfo {
|
|
25
|
+
discField: string;
|
|
26
|
+
subtypeFields: MetaField[];
|
|
27
|
+
}
|
|
14
28
|
|
|
15
29
|
interface ColumnSpec {
|
|
16
30
|
id: string;
|
|
@@ -57,10 +71,12 @@ function fieldLabel(field: MetaField): string {
|
|
|
57
71
|
* fall back to all fields on the entity (pre-E-T2 behaviour, kept for
|
|
58
72
|
* backwards compat with metadata not yet migrated by E-T4).
|
|
59
73
|
*/
|
|
60
|
-
function extractGrids(entity: MetaObject): GridSpec[] {
|
|
74
|
+
function extractGrids(entity: MetaObject, tph?: TphGridInfo): GridSpec[] {
|
|
61
75
|
// fields() and layouts() are both effective (own + inherited via extends:/super:).
|
|
76
|
+
// For a TPH base, also index the subtype-only fields so they can be folded
|
|
77
|
+
// into the polymorphic grid's column set.
|
|
62
78
|
const fieldsByName = new Map(
|
|
63
|
-
entity.fields().map((f) => [f.name, f] as const),
|
|
79
|
+
[...entity.fields(), ...(tph?.subtypeFields ?? [])].map((f) => [f.name, f] as const),
|
|
64
80
|
);
|
|
65
81
|
|
|
66
82
|
const grids: GridSpec[] = [];
|
|
@@ -74,6 +90,16 @@ function extractGrids(entity: MetaObject): GridSpec[] {
|
|
|
74
90
|
? (columnsAttr as unknown[]).filter((x): x is string => typeof x === "string")
|
|
75
91
|
: [...fieldsByName.keys()];
|
|
76
92
|
|
|
93
|
+
// FR-017: a polymorphic (TPH base) grid folds in every subtype-only column
|
|
94
|
+
// so mixed rows can render their subtype fields (the runtime grid renders a
|
|
95
|
+
// null cell as an em-dash for rows of other subtypes). Appended after the
|
|
96
|
+
// declared columns, deduped.
|
|
97
|
+
if (tph) {
|
|
98
|
+
for (const f of tph.subtypeFields) {
|
|
99
|
+
if (!columnNames.includes(f.name)) columnNames.push(f.name);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
77
103
|
const columns: ColumnSpec[] = columnNames.flatMap((name) => {
|
|
78
104
|
const field = fieldsByName.get(name);
|
|
79
105
|
if (!field) return []; // columns ref that doesn't exist on entity; defensive skip
|
|
@@ -82,6 +108,8 @@ function extractGrids(entity: MetaObject): GridSpec[] {
|
|
|
82
108
|
header: fieldLabel(field),
|
|
83
109
|
viewKind: fieldViewKind(field),
|
|
84
110
|
};
|
|
111
|
+
// FR-017: the discriminator column renders as a subtype badge.
|
|
112
|
+
if (tph && name === tph.discField) spec.renderer = "badge";
|
|
85
113
|
return [spec];
|
|
86
114
|
});
|
|
87
115
|
|
|
@@ -121,7 +149,17 @@ function renderColumnDef(col: ColumnSpec): string {
|
|
|
121
149
|
export function renderColumnsFile(entity: MetaObject, ctx: RenderContext): string {
|
|
122
150
|
const entityName = entity.name;
|
|
123
151
|
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
124
|
-
|
|
152
|
+
// FR-017: a TPH discriminator base emits a polymorphic grid typed against the
|
|
153
|
+
// raw single-table row (<Base>Row — all columns, subtype-only nullable),
|
|
154
|
+
// NOT the discriminated union (whose members lack the other subtypes' fields).
|
|
155
|
+
const tphBase = isTphDiscriminatorBase(entity, ctx.loadedRoot);
|
|
156
|
+
const tph: TphGridInfo | undefined = tphBase
|
|
157
|
+
? {
|
|
158
|
+
discField: (entity.ownAttr(OBJECT_ATTR_DISCRIMINATOR) as string) ?? "",
|
|
159
|
+
subtypeFields: collectTphSubtypeFields(entity, ctx.loadedRoot),
|
|
160
|
+
}
|
|
161
|
+
: undefined;
|
|
162
|
+
const grids = extractGrids(entity, tph);
|
|
125
163
|
|
|
126
164
|
const ColumnDefSym = imp("t:ColumnDef@@tanstack/react-table");
|
|
127
165
|
|
|
@@ -179,9 +217,12 @@ export const ${filterConstName}: ${entityName}Filter = ${JSON.stringify(grid.fil
|
|
|
179
217
|
ctx.extStyle,
|
|
180
218
|
);
|
|
181
219
|
// Import <Entity>Row always; import <Entity>Filter only when a filter const is emitted.
|
|
220
|
+
// TPH base: <Base>Row is a distinct export (the all-columns row); import it
|
|
221
|
+
// directly. Non-TPH: the entity type IS the row, imported under the Row alias.
|
|
222
|
+
const rowImport = tphBase ? `${entityName}Row` : `${entityName} as ${entityName}Row`;
|
|
182
223
|
const entityImportCode = hasFilterConst
|
|
183
|
-
? code`import type { ${
|
|
184
|
-
: code`import type { ${
|
|
224
|
+
? code`import type { ${rowImport}, ${entityName}Filter } from ${JSON.stringify(entityModule)};`
|
|
225
|
+
: code`import type { ${rowImport} } from ${JSON.stringify(entityModule)};`;
|
|
185
226
|
|
|
186
227
|
const body: Code = joinCode(sections, { on: "\n" });
|
|
187
228
|
return header + entityImportCode.toString() + "\n" + body.toString();
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import { code, imp, joinCode, type Code } from "ts-poet";
|
|
1
|
+
import { code, imp, joinCode, Import, type Code } from "ts-poet";
|
|
2
2
|
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
3
|
-
import type { RenderContext } from "@metaobjectsdev/codegen-ts";
|
|
4
|
-
import {
|
|
3
|
+
import type { RenderContext, RelationEntry } from "@metaobjectsdev/codegen-ts";
|
|
4
|
+
import {
|
|
5
|
+
GENERATED_HEADER,
|
|
6
|
+
isProjection,
|
|
7
|
+
pluralize,
|
|
8
|
+
entityModuleSpecifier,
|
|
9
|
+
isTphDiscriminatorBase,
|
|
10
|
+
tphPlan,
|
|
11
|
+
} from "@metaobjectsdev/codegen-ts";
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
14
|
* Render <Entity>.hooks.ts — query-key factory + 2 query hooks + (for non-projections) 3 mutation hooks.
|
|
@@ -29,21 +36,125 @@ export function renderHooksFile(entity: MetaObject, ctx: RenderContext): string
|
|
|
29
36
|
entity.name,
|
|
30
37
|
ctx.extStyle,
|
|
31
38
|
);
|
|
39
|
+
// FR-017 Tier 3: a TPH discriminator base gets a polymorphic + per-subtype
|
|
40
|
+
// hooks file (the subtype entities are filtered out of this generator).
|
|
41
|
+
if (isTphDiscriminatorBase(entity, ctx.loadedRoot)) {
|
|
42
|
+
return renderTphHooksFile(entity, ctx, entityModule);
|
|
43
|
+
}
|
|
32
44
|
if (isProjection(entity)) {
|
|
33
|
-
return renderReadOnlyHooksFile(entity, entityModule);
|
|
45
|
+
return renderReadOnlyHooksFile(entity, entityModule, ctx);
|
|
46
|
+
}
|
|
47
|
+
return renderFullHooksFile(entity, entityModule, ctx);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// FR-018 — M:N collection hook(s).
|
|
52
|
+
//
|
|
53
|
+
// For each many-to-many relationship the source declares (`@cardinality: "many"`
|
|
54
|
+
// + `@through`), emit `use<Source><Relation>(sourceId, opts?)` — a useQuery that
|
|
55
|
+
// fetches the REST sub-resource `GET /<source-plural>/{sourceId}/<relationName>`
|
|
56
|
+
// (the exact URL mountM2mRoute serves) and returns the typed target collection
|
|
57
|
+
// (`Target[]`). The query is enabled only when sourceId is present, so callers
|
|
58
|
+
// can pass `undefined` before the parent row loads. A symmetric self-join is
|
|
59
|
+
// still ONE collection hook (the server unions both junction columns on read).
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
/** The M:N relation entries for an entity (cardinality 'many' + a junction). */
|
|
63
|
+
function m2mEntriesFor(entity: MetaObject, ctx: RenderContext): RelationEntry[] {
|
|
64
|
+
return (ctx.relationMap.get(entity.name) ?? []).filter(
|
|
65
|
+
(e) => e.cardinality === "many" && e.junctionEntity !== undefined,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** The `relation: (relation, sourceId) => ...` query-key factory line, included
|
|
70
|
+
* in the keys factory ONLY when the entity has M:N relationships. */
|
|
71
|
+
function m2mKeyLine(keysVar: string): string {
|
|
72
|
+
return (
|
|
73
|
+
` relation: (relation: string, sourceId: number | undefined) =>\n` +
|
|
74
|
+
` [...${keysVar}.all(), "relation", relation, sourceId ?? null] as const,`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Render `use<Source><Relation>(sourceId, opts?)` per M:N relationship. Returns
|
|
80
|
+
* null when the entity has no M:N relationships (no extra hooks emitted).
|
|
81
|
+
*/
|
|
82
|
+
function renderM2mHooks(
|
|
83
|
+
entity: MetaObject,
|
|
84
|
+
ctx: RenderContext,
|
|
85
|
+
keysVar: string,
|
|
86
|
+
entries: RelationEntry[],
|
|
87
|
+
): Code | null {
|
|
88
|
+
if (entries.length === 0) return null;
|
|
89
|
+
|
|
90
|
+
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
91
|
+
const useQueryOptionsSym = imp("t:UseQueryOptions@@tanstack/react-query");
|
|
92
|
+
const useQueryResultSym = imp("t:UseQueryResult@@tanstack/react-query");
|
|
93
|
+
const useEntityFetcherSym = imp("useEntityFetcher@@metaobjectsdev/tanstack");
|
|
94
|
+
|
|
95
|
+
const source = entity.name;
|
|
96
|
+
|
|
97
|
+
// Distinct target row types, imported (aliased) from each target's entity
|
|
98
|
+
// module. ts-poet's imp() tracks + hoists these into the import block. The
|
|
99
|
+
// <Target>RelRow alias avoids colliding with the source file's own
|
|
100
|
+
// `type <Source> as <Source>Row` import on a self-join (source === target).
|
|
101
|
+
const targetTypeSym = new Map<string, Import>();
|
|
102
|
+
for (const e of entries) {
|
|
103
|
+
if (targetTypeSym.has(e.targetEntity)) continue;
|
|
104
|
+
const mod = entityModuleSpecifier(
|
|
105
|
+
ctx.selfTarget,
|
|
106
|
+
ctx.entityModuleTarget,
|
|
107
|
+
ctx.packageOf.get(e.targetEntity),
|
|
108
|
+
e.targetEntity,
|
|
109
|
+
ctx.extStyle,
|
|
110
|
+
);
|
|
111
|
+
// `import { type <Target> as <Target>RelRow } from "<mod>"` — the RelRow
|
|
112
|
+
// alias avoids colliding with the source file's own `type <Source> as
|
|
113
|
+
// <Source>Row` import on a self-join (source === target).
|
|
114
|
+
targetTypeSym.set(
|
|
115
|
+
e.targetEntity,
|
|
116
|
+
Import.importsName(`${e.targetEntity}RelRow`, mod, true, e.targetEntity),
|
|
117
|
+
);
|
|
34
118
|
}
|
|
35
|
-
|
|
119
|
+
|
|
120
|
+
const hooks = entries.map((e) => {
|
|
121
|
+
const targetSym = targetTypeSym.get(e.targetEntity)!;
|
|
122
|
+
const hookName = `use${source}${capitalize(e.name)}`;
|
|
123
|
+
const relLit = JSON.stringify(e.name);
|
|
124
|
+
return code`
|
|
125
|
+
export function ${hookName}(
|
|
126
|
+
sourceId: number | undefined,
|
|
127
|
+
opts?: Omit<${useQueryOptionsSym}<${targetSym}[]>, "queryKey" | "queryFn">,
|
|
128
|
+
): ${useQueryResultSym}<${targetSym}[]> {
|
|
129
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
130
|
+
return ${useQuerySym}<${targetSym}[]>({
|
|
131
|
+
queryKey: ${keysVar}.relation(${relLit}, sourceId),
|
|
132
|
+
queryFn: () => fetcher<${targetSym}[]>(\`\${${source}.$apiPrefix}\${${source}.$path}/\${sourceId}/${e.name}\`),
|
|
133
|
+
enabled: sourceId != null && (opts?.enabled ?? true),
|
|
134
|
+
...opts,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
`;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return joinCode(hooks, { on: "\n" });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function capitalize(s: string): string {
|
|
144
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
36
145
|
}
|
|
37
146
|
|
|
38
147
|
// ---------------------------------------------------------------------------
|
|
39
148
|
// Read-only path (projections)
|
|
40
149
|
// ---------------------------------------------------------------------------
|
|
41
150
|
|
|
42
|
-
function renderReadOnlyHooksFile(entity: MetaObject, entityModule: string): string {
|
|
151
|
+
function renderReadOnlyHooksFile(entity: MetaObject, entityModule: string, ctx: RenderContext): string {
|
|
43
152
|
const entityName = entity.name;
|
|
44
153
|
const entityNamePlural = pluralize(entityName);
|
|
45
154
|
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
46
155
|
const keysVar = `${lcEntity}Keys`;
|
|
156
|
+
const m2mEntries = m2mEntriesFor(entity, ctx);
|
|
157
|
+
const relationKeyLine = m2mEntries.length > 0 ? `\n${m2mKeyLine(keysVar)}` : "";
|
|
47
158
|
|
|
48
159
|
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
49
160
|
const useQueryOptionsSym = imp("t:UseQueryOptions@@tanstack/react-query");
|
|
@@ -65,7 +176,7 @@ export const ${keysVar} = {
|
|
|
65
176
|
lists: () => [...${keysVar}.all(), "list"] as const,
|
|
66
177
|
list: (filter?: ${entityName}Filter) => [...${keysVar}.lists(), filter ?? {}] as const,
|
|
67
178
|
details: () => [...${keysVar}.all(), "detail"] as const,
|
|
68
|
-
detail: (id: number) => [...${keysVar}.details(), id] as const
|
|
179
|
+
detail: (id: number) => [...${keysVar}.details(), id] as const,${relationKeyLine}
|
|
69
180
|
};
|
|
70
181
|
`;
|
|
71
182
|
|
|
@@ -96,7 +207,8 @@ export function use${entityNamePlural}(
|
|
|
96
207
|
}
|
|
97
208
|
`;
|
|
98
209
|
|
|
99
|
-
const
|
|
210
|
+
const m2mHooks = renderM2mHooks(entity, ctx, keysVar, m2mEntries);
|
|
211
|
+
const body: Code = joinCode(m2mHooks ? [queryKeys, queries, m2mHooks] : [queryKeys, queries], { on: "\n" });
|
|
100
212
|
|
|
101
213
|
const header =
|
|
102
214
|
`// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
@@ -108,11 +220,13 @@ export function use${entityNamePlural}(
|
|
|
108
220
|
// Full path (writable entities — table-backed or write-through)
|
|
109
221
|
// ---------------------------------------------------------------------------
|
|
110
222
|
|
|
111
|
-
function renderFullHooksFile(entity: MetaObject, entityModule: string): string {
|
|
223
|
+
function renderFullHooksFile(entity: MetaObject, entityModule: string, ctx: RenderContext): string {
|
|
112
224
|
const entityName = entity.name;
|
|
113
225
|
const entityNamePlural = pluralize(entityName);
|
|
114
226
|
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
115
227
|
const keysVar = `${lcEntity}Keys`;
|
|
228
|
+
const m2mEntries = m2mEntriesFor(entity, ctx);
|
|
229
|
+
const relationKeyLine = m2mEntries.length > 0 ? `\n${m2mKeyLine(keysVar)}` : "";
|
|
116
230
|
|
|
117
231
|
const useMutationSym = imp("useMutation@@tanstack/react-query");
|
|
118
232
|
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
@@ -140,7 +254,7 @@ export const ${keysVar} = {
|
|
|
140
254
|
lists: () => [...${keysVar}.all(), "list"] as const,
|
|
141
255
|
list: (filter?: ${entityName}Filter) => [...${keysVar}.lists(), filter ?? {}] as const,
|
|
142
256
|
details: () => [...${keysVar}.all(), "detail"] as const,
|
|
143
|
-
detail: (id: number) => [...${keysVar}.details(), id] as const
|
|
257
|
+
detail: (id: number) => [...${keysVar}.details(), id] as const,${relationKeyLine}
|
|
144
258
|
};
|
|
145
259
|
`;
|
|
146
260
|
|
|
@@ -171,6 +285,8 @@ export function use${entityNamePlural}(
|
|
|
171
285
|
}
|
|
172
286
|
`;
|
|
173
287
|
|
|
288
|
+
const m2mHooks = renderM2mHooks(entity, ctx, keysVar, m2mEntries);
|
|
289
|
+
|
|
174
290
|
const mutations: Code = code`
|
|
175
291
|
export function useCreate${entityName}(
|
|
176
292
|
opts?: Omit<${useMutationOptionsSym}<${entityName}Row, Error, ${entityName}Insert>, "mutationFn">,
|
|
@@ -226,10 +342,192 @@ export function useDelete${entityName}(
|
|
|
226
342
|
}
|
|
227
343
|
`;
|
|
228
344
|
|
|
229
|
-
const body: Code = joinCode(
|
|
345
|
+
const body: Code = joinCode(
|
|
346
|
+
m2mHooks ? [queryKeys, queries, m2mHooks, mutations] : [queryKeys, queries, mutations],
|
|
347
|
+
{ on: "\n" },
|
|
348
|
+
);
|
|
230
349
|
|
|
231
350
|
const header =
|
|
232
351
|
`// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
233
352
|
`// Source metadata: ${entityName} (${entity.fqn()})\n`;
|
|
234
353
|
return header + entityImports.toString() + body.toString();
|
|
235
354
|
}
|
|
355
|
+
|
|
356
|
+
// ---------------------------------------------------------------------------
|
|
357
|
+
// FR-017 Tier 3 — TPH discriminator base: polymorphic + per-subtype hooks.
|
|
358
|
+
// ---------------------------------------------------------------------------
|
|
359
|
+
|
|
360
|
+
function renderTphHooksFile(base: MetaObject, ctx: RenderContext, baseModule: string): string {
|
|
361
|
+
const baseName = base.name;
|
|
362
|
+
const lcBase = baseName.charAt(0).toLowerCase() + baseName.slice(1);
|
|
363
|
+
const keysVar = `${lcBase}Keys`;
|
|
364
|
+
// Single source of truth for discriminator field + subtypes + route segments.
|
|
365
|
+
const plan = tphPlan(base, ctx.loadedRoot)!;
|
|
366
|
+
const discField = plan.discriminatorField;
|
|
367
|
+
|
|
368
|
+
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
369
|
+
const useMutationSym = imp("useMutation@@tanstack/react-query");
|
|
370
|
+
const useQueryClientSym = imp("useQueryClient@@tanstack/react-query");
|
|
371
|
+
const useQueryOptionsSym = imp("t:UseQueryOptions@@tanstack/react-query");
|
|
372
|
+
const useMutationOptionsSym = imp("t:UseMutationOptions@@tanstack/react-query");
|
|
373
|
+
const useQueryResultSym = imp("t:UseQueryResult@@tanstack/react-query");
|
|
374
|
+
const useMutationResultSym = imp("t:UseMutationResult@@tanstack/react-query");
|
|
375
|
+
const useEntityFetcherSym = imp("useEntityFetcher@@metaobjectsdev/tanstack");
|
|
376
|
+
const buildFilterQsSym = imp("buildFilterQs@@metaobjectsdev/runtime-web");
|
|
377
|
+
|
|
378
|
+
const subtypes = plan.subtypes;
|
|
379
|
+
|
|
380
|
+
// `${baseName}` imports BOTH the constants value (for $path/$apiPrefix) and the
|
|
381
|
+
// discriminated-union type (declaration merge). Each subtype contributes its
|
|
382
|
+
// interface type AND its own filter type (discriminator-excluded — the route
|
|
383
|
+
// pins it), so per-subtype hooks filter on the fields the per-subtype
|
|
384
|
+
// allowlist actually permits.
|
|
385
|
+
const subImportLines = subtypes
|
|
386
|
+
.map((s) => {
|
|
387
|
+
const m = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, s.entity.package, s.entity.name, ctx.extStyle);
|
|
388
|
+
return `import { type ${s.entity.name}, type ${s.entity.name}Filter } from ${JSON.stringify(m)};`;
|
|
389
|
+
})
|
|
390
|
+
.join("\n");
|
|
391
|
+
const entityImports: Code = code`
|
|
392
|
+
import { ${baseName}, type ${baseName}Filter } from ${JSON.stringify(baseModule)};
|
|
393
|
+
${subImportLines}
|
|
394
|
+
`;
|
|
395
|
+
|
|
396
|
+
const queryKeys: Code = code`
|
|
397
|
+
export const ${keysVar} = {
|
|
398
|
+
all: () => [${JSON.stringify(lcBase)}] as const,
|
|
399
|
+
lists: () => [...${keysVar}.all(), "list"] as const,
|
|
400
|
+
list: (filter?: ${baseName}Filter) => [...${keysVar}.lists(), filter ?? {}] as const,
|
|
401
|
+
details: () => [...${keysVar}.all(), "detail"] as const,
|
|
402
|
+
detail: (id: number) => [...${keysVar}.details(), id] as const,
|
|
403
|
+
subtypeLists: (sub: string) => [...${keysVar}.all(), sub, "list"] as const,
|
|
404
|
+
// filter is loosely typed here (cache-key identity only); the per-subtype
|
|
405
|
+
// hooks below type it precisely as <Sub>Filter.
|
|
406
|
+
subtypeList: (sub: string, filter?: unknown) => [...${keysVar}.subtypeLists(sub), filter ?? {}] as const,
|
|
407
|
+
subtypeDetails:(sub: string) => [...${keysVar}.all(), sub, "detail"] as const,
|
|
408
|
+
subtypeDetail: (sub: string, id: number) => [...${keysVar}.subtypeDetails(sub), id] as const,
|
|
409
|
+
};
|
|
410
|
+
`;
|
|
411
|
+
|
|
412
|
+
// Polymorphic reads — return the discriminated union.
|
|
413
|
+
const polymorphic: Code = code`
|
|
414
|
+
export function use${baseName}(
|
|
415
|
+
id: number,
|
|
416
|
+
opts?: Omit<${useQueryOptionsSym}<${baseName}>, "queryKey" | "queryFn">,
|
|
417
|
+
): ${useQueryResultSym}<${baseName}> {
|
|
418
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
419
|
+
return ${useQuerySym}<${baseName}>({
|
|
420
|
+
queryKey: ${keysVar}.detail(id),
|
|
421
|
+
queryFn: () => fetcher<${baseName}>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/\${id}\`),
|
|
422
|
+
...opts,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export function use${pluralize(baseName)}(
|
|
427
|
+
filter?: ${baseName}Filter,
|
|
428
|
+
opts?: Omit<${useQueryOptionsSym}<${baseName}[]>, "queryKey" | "queryFn">,
|
|
429
|
+
): ${useQueryResultSym}<${baseName}[]> {
|
|
430
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
431
|
+
const qs = filter ? "?" + ${buildFilterQsSym}(filter as Record<string, unknown>) : "";
|
|
432
|
+
return ${useQuerySym}<${baseName}[]>({
|
|
433
|
+
queryKey: ${keysVar}.list(filter),
|
|
434
|
+
queryFn: () => fetcher<${baseName}[]>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}\${qs}\`),
|
|
435
|
+
...opts,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
`;
|
|
439
|
+
|
|
440
|
+
// Per-subtype hooks — scoped to each discriminator value's REST sub-path.
|
|
441
|
+
const subtypeSections: Code[] = subtypes.map(({ entity: subEntity, value, routeSegment: seg }) => {
|
|
442
|
+
const subName = subEntity.name;
|
|
443
|
+
const valueLit = JSON.stringify(value);
|
|
444
|
+
const createInput = `Omit<${subName}, ${JSON.stringify(discField)}>`;
|
|
445
|
+
const updateInput = `Partial<${createInput}>`;
|
|
446
|
+
const subPath = `\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}\``;
|
|
447
|
+
return code`
|
|
448
|
+
export function use${pluralize(subName)}(
|
|
449
|
+
filter?: ${subName}Filter,
|
|
450
|
+
opts?: Omit<${useQueryOptionsSym}<${subName}[]>, "queryKey" | "queryFn">,
|
|
451
|
+
): ${useQueryResultSym}<${subName}[]> {
|
|
452
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
453
|
+
const qs = filter ? "?" + ${buildFilterQsSym}(filter as Record<string, unknown>) : "";
|
|
454
|
+
return ${useQuerySym}<${subName}[]>({
|
|
455
|
+
queryKey: ${keysVar}.subtypeList(${valueLit}, filter),
|
|
456
|
+
queryFn: () => fetcher<${subName}[]>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}\${qs}\`),
|
|
457
|
+
...opts,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export function use${subName}(
|
|
462
|
+
id: number,
|
|
463
|
+
opts?: Omit<${useQueryOptionsSym}<${subName}>, "queryKey" | "queryFn">,
|
|
464
|
+
): ${useQueryResultSym}<${subName}> {
|
|
465
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
466
|
+
return ${useQuerySym}<${subName}>({
|
|
467
|
+
queryKey: ${keysVar}.subtypeDetail(${valueLit}, id),
|
|
468
|
+
queryFn: () => fetcher<${subName}>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}/\${id}\`),
|
|
469
|
+
...opts,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export function useCreate${subName}(
|
|
474
|
+
opts?: Omit<${useMutationOptionsSym}<${subName}, Error, ${createInput}>, "mutationFn">,
|
|
475
|
+
): ${useMutationResultSym}<${subName}, Error, ${createInput}> {
|
|
476
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
477
|
+
const qc = ${useQueryClientSym}();
|
|
478
|
+
return ${useMutationSym}<${subName}, Error, ${createInput}>({
|
|
479
|
+
mutationFn: (input) => fetcher<${subName}>(${subPath}, {
|
|
480
|
+
method: "POST",
|
|
481
|
+
headers: { "Content-Type": "application/json" },
|
|
482
|
+
body: JSON.stringify(input),
|
|
483
|
+
}),
|
|
484
|
+
...opts,
|
|
485
|
+
onSuccess: (...args) => {
|
|
486
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
487
|
+
opts?.onSuccess?.(...args);
|
|
488
|
+
},
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export function useUpdate${subName}(
|
|
493
|
+
opts?: Omit<${useMutationOptionsSym}<${subName}, Error, { id: number; input: ${updateInput} }>, "mutationFn">,
|
|
494
|
+
): ${useMutationResultSym}<${subName}, Error, { id: number; input: ${updateInput} }> {
|
|
495
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
496
|
+
const qc = ${useQueryClientSym}();
|
|
497
|
+
return ${useMutationSym}({
|
|
498
|
+
mutationFn: ({ id, input }) => fetcher<${subName}>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}/\${id}\`, {
|
|
499
|
+
method: "PATCH",
|
|
500
|
+
headers: { "Content-Type": "application/json" },
|
|
501
|
+
body: JSON.stringify(input),
|
|
502
|
+
}),
|
|
503
|
+
...opts,
|
|
504
|
+
onSuccess: (...args) => {
|
|
505
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
506
|
+
opts?.onSuccess?.(...args);
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
export function useDelete${subName}(
|
|
512
|
+
opts?: Omit<${useMutationOptionsSym}<void, Error, number>, "mutationFn">,
|
|
513
|
+
): ${useMutationResultSym}<void, Error, number> {
|
|
514
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
515
|
+
const qc = ${useQueryClientSym}();
|
|
516
|
+
return ${useMutationSym}({
|
|
517
|
+
mutationFn: (id) => fetcher<void>(\`\${${baseName}.$apiPrefix}\${${baseName}.$path}/${seg}/\${id}\`, { method: "DELETE" }),
|
|
518
|
+
...opts,
|
|
519
|
+
onSuccess: (...args) => {
|
|
520
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
521
|
+
opts?.onSuccess?.(...args);
|
|
522
|
+
},
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
`;
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
const body: Code = joinCode([queryKeys, polymorphic, ...subtypeSections], { on: "\n" });
|
|
529
|
+
const header =
|
|
530
|
+
`// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
531
|
+
`// Source metadata: ${baseName} (${base.fqn()}) — TPH discriminator base\n`;
|
|
532
|
+
return header + entityImports.toString() + body.toString();
|
|
533
|
+
}
|