@metaobjectsdev/runtime-ts 1.0.5-rc.2 → 1.0.5-rc.3
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.
|
@@ -30,6 +30,21 @@ export interface M2mRouteOptions {
|
|
|
30
30
|
column: string;
|
|
31
31
|
value: string;
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* The SOURCE is a TPH subtype: this route is mounted under the subtype's path segment,
|
|
35
|
+
* but the junction FK addresses the shared base table, so an id belonging to a SIBLING
|
|
36
|
+
* subtype would traverse it successfully and return that sibling's relations. Stage 0
|
|
37
|
+
* reads the source row's discriminator from `table` (the base table the row lives in)
|
|
38
|
+
* and yields an empty list when it is not `value` — the id names no row of THIS
|
|
39
|
+
* subtype, so it has no relations, which is a 200 with `[]` rather than an error.
|
|
40
|
+
* Absent → no source check, behaviour unchanged.
|
|
41
|
+
*/
|
|
42
|
+
sourceDiscriminator?: {
|
|
43
|
+
table: AnyTable;
|
|
44
|
+
pkColumn: string;
|
|
45
|
+
column: string;
|
|
46
|
+
value: string;
|
|
47
|
+
};
|
|
33
48
|
/** Fastify route-level hooks (auth, etc.). */
|
|
34
49
|
routeOptions?: RouteShorthandOptions;
|
|
35
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount-m2m.d.ts","sourceRoot":"","sources":["../../src/drizzle-fastify/mount-m2m.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mount-m2m.d.ts","sourceRoot":"","sources":["../../src/drizzle-fastify/mount-m2m.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAMtE,KAAK,UAAU,GAAG,GAAG,CAAC;AAEtB,KAAK,QAAQ,GAAG,GAAG,CAAC;AAEpB,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,eAAe,CAAC;IACzB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,EAAE,EAAE,UAAU,CAAC;IACf,wDAAwD;IACxD,aAAa,EAAE,QAAQ,CAAC;IACxB,kDAAkD;IAClD,WAAW,EAAE,QAAQ,CAAC;IACtB,wFAAwF;IACxF,YAAY,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,YAAY,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE;QAAE,KAAK,EAAE,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3F,8CAA8C;IAC9C,YAAY,CAAC,EAAE,qBAAqB,CAAC;CACtC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAyEzD"}
|
|
@@ -23,6 +23,12 @@
|
|
|
23
23
|
// junction FK can only point at that base table — so it can hold the id of a row of
|
|
24
24
|
// another subtype. `targetDiscriminator` ANDs the subtype predicate into stage 2 so
|
|
25
25
|
// only rows of the declared target come back.
|
|
26
|
+
//
|
|
27
|
+
// The SOURCE has the mirror problem. An M:N declared ON a subtype mounts under that
|
|
28
|
+
// subtype's segment (`/auths/bridge/:id/linkedAuths`), but the junction FK still points
|
|
29
|
+
// at the shared base table, so a SIBLING subtype's id traverses it just as well and the
|
|
30
|
+
// subtype segment in the path would be decorative. `sourceDiscriminator` adds a stage 0
|
|
31
|
+
// that checks the source row's own discriminator first.
|
|
26
32
|
import { and, eq, or, inArray } from "drizzle-orm";
|
|
27
33
|
import { coerceIdForColumn } from "./util.js";
|
|
28
34
|
export function mountM2mRoute(opts) {
|
|
@@ -40,6 +46,24 @@ export function mountM2mRoute(opts) {
|
|
|
40
46
|
if (sourceId === undefined) {
|
|
41
47
|
return reply.code(400).send({ error: "invalid_id" });
|
|
42
48
|
}
|
|
49
|
+
// Stage 0 — the source id must name a row of THIS subtype. Skipping it would let
|
|
50
|
+
// `/auths/bridge/{a Copay's id}/linkedAuths` return that Copay's relations, because
|
|
51
|
+
// the junction FK cannot tell the subtypes apart: it points at the shared base table.
|
|
52
|
+
const srcDisc = opts.sourceDiscriminator;
|
|
53
|
+
if (srcDisc !== undefined) {
|
|
54
|
+
const srcPk = columnRef(srcDisc.table, srcDisc.pkColumn);
|
|
55
|
+
const ownId = coerceIdForColumn(srcPk, id);
|
|
56
|
+
if (ownId === undefined) {
|
|
57
|
+
return reply.code(400).send({ error: "invalid_id" });
|
|
58
|
+
}
|
|
59
|
+
const owner = await opts.db
|
|
60
|
+
.select({ d: columnRef(srcDisc.table, srcDisc.column) })
|
|
61
|
+
.from(srcDisc.table)
|
|
62
|
+
.where(eq(srcPk, ownId))
|
|
63
|
+
.limit(1);
|
|
64
|
+
if (owner.length === 0 || String(owner[0]?.d) !== srcDisc.value)
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
43
67
|
// Stage 1 — junction rows for this source id.
|
|
44
68
|
const joinWhere = opts.symmetric
|
|
45
69
|
? or(eq(srcCol, sourceId), eq(tgtCol, sourceId))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount-m2m.js","sourceRoot":"","sources":["../../src/drizzle-fastify/mount-m2m.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wDAAwD;AACxD,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,gFAAgF;AAChF,+EAA+E;AAC/E,iFAAiF;AACjF,4EAA4E;AAC5E,6EAA6E;AAC7E,8EAA8E;AAC9E,0CAA0C;AAC1C,EAAE;AACF,kDAAkD;AAClD,+EAA+E;AAC/E,oDAAoD;AACpD,+EAA+E;AAC/E,0EAA0E;AAC1E,+EAA+E;AAC/E,wEAAwE;AACxE,EAAE;AACF,kFAAkF;AAClF,oFAAoF;AACpF,oFAAoF;AACpF,8CAA8C;
|
|
1
|
+
{"version":3,"file":"mount-m2m.js","sourceRoot":"","sources":["../../src/drizzle-fastify/mount-m2m.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/runtime-ts",
|
|
3
|
-
"version": "1.0.5-rc.
|
|
3
|
+
"version": "1.0.5-rc.3",
|
|
4
4
|
"description": "Node-side runtime helpers for MetaObjects: Fastify route builders, Drizzle filter/sort integration, Kysely drivers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"access": "public"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@metaobjectsdev/metadata": "1.0.5-rc.
|
|
68
|
-
"@metaobjectsdev/render": "1.0.5-rc.
|
|
67
|
+
"@metaobjectsdev/metadata": "1.0.5-rc.3",
|
|
68
|
+
"@metaobjectsdev/render": "1.0.5-rc.3",
|
|
69
69
|
"qs": "^6.13.0"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
@@ -23,6 +23,12 @@
|
|
|
23
23
|
// junction FK can only point at that base table — so it can hold the id of a row of
|
|
24
24
|
// another subtype. `targetDiscriminator` ANDs the subtype predicate into stage 2 so
|
|
25
25
|
// only rows of the declared target come back.
|
|
26
|
+
//
|
|
27
|
+
// The SOURCE has the mirror problem. An M:N declared ON a subtype mounts under that
|
|
28
|
+
// subtype's segment (`/auths/bridge/:id/linkedAuths`), but the junction FK still points
|
|
29
|
+
// at the shared base table, so a SIBLING subtype's id traverses it just as well and the
|
|
30
|
+
// subtype segment in the path would be decorative. `sourceDiscriminator` adds a stage 0
|
|
31
|
+
// that checks the source row's own discriminator first.
|
|
26
32
|
|
|
27
33
|
import type { FastifyInstance, RouteShorthandOptions } from "fastify";
|
|
28
34
|
import { and, eq, or, inArray } from "drizzle-orm";
|
|
@@ -60,6 +66,16 @@ export interface M2mRouteOptions {
|
|
|
60
66
|
* Absent → every related row is returned, behaviour unchanged.
|
|
61
67
|
*/
|
|
62
68
|
targetDiscriminator?: { column: string; value: string };
|
|
69
|
+
/**
|
|
70
|
+
* The SOURCE is a TPH subtype: this route is mounted under the subtype's path segment,
|
|
71
|
+
* but the junction FK addresses the shared base table, so an id belonging to a SIBLING
|
|
72
|
+
* subtype would traverse it successfully and return that sibling's relations. Stage 0
|
|
73
|
+
* reads the source row's discriminator from `table` (the base table the row lives in)
|
|
74
|
+
* and yields an empty list when it is not `value` — the id names no row of THIS
|
|
75
|
+
* subtype, so it has no relations, which is a 200 with `[]` rather than an error.
|
|
76
|
+
* Absent → no source check, behaviour unchanged.
|
|
77
|
+
*/
|
|
78
|
+
sourceDiscriminator?: { table: AnyTable; pkColumn: string; column: string; value: string };
|
|
63
79
|
/** Fastify route-level hooks (auth, etc.). */
|
|
64
80
|
routeOptions?: RouteShorthandOptions;
|
|
65
81
|
}
|
|
@@ -83,6 +99,24 @@ export function mountM2mRoute(opts: M2mRouteOptions): void {
|
|
|
83
99
|
return reply.code(400).send({ error: "invalid_id" });
|
|
84
100
|
}
|
|
85
101
|
|
|
102
|
+
// Stage 0 — the source id must name a row of THIS subtype. Skipping it would let
|
|
103
|
+
// `/auths/bridge/{a Copay's id}/linkedAuths` return that Copay's relations, because
|
|
104
|
+
// the junction FK cannot tell the subtypes apart: it points at the shared base table.
|
|
105
|
+
const srcDisc = opts.sourceDiscriminator;
|
|
106
|
+
if (srcDisc !== undefined) {
|
|
107
|
+
const srcPk = columnRef(srcDisc.table, srcDisc.pkColumn);
|
|
108
|
+
const ownId = coerceIdForColumn(srcPk, id);
|
|
109
|
+
if (ownId === undefined) {
|
|
110
|
+
return reply.code(400).send({ error: "invalid_id" });
|
|
111
|
+
}
|
|
112
|
+
const owner = await opts.db
|
|
113
|
+
.select({ d: columnRef(srcDisc.table, srcDisc.column) })
|
|
114
|
+
.from(srcDisc.table)
|
|
115
|
+
.where(eq(srcPk, ownId))
|
|
116
|
+
.limit(1);
|
|
117
|
+
if (owner.length === 0 || String(owner[0]?.d) !== srcDisc.value) return [];
|
|
118
|
+
}
|
|
119
|
+
|
|
86
120
|
// Stage 1 — junction rows for this source id.
|
|
87
121
|
const joinWhere = opts.symmetric
|
|
88
122
|
? or(eq(srcCol, sourceId), eq(tgtCol, sourceId))
|