@metaobjectsdev/runtime-ts 1.0.3 → 1.0.4
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/dist/drizzle-fastify/mount-read-only.d.ts +12 -1
- package/dist/drizzle-fastify/mount-read-only.d.ts.map +1 -1
- package/dist/drizzle-fastify/mount-read-only.js +6 -5
- package/dist/drizzle-fastify/mount-read-only.js.map +1 -1
- package/dist/relation-resolver.d.ts.map +1 -1
- package/dist/relation-resolver.js +15 -30
- package/dist/relation-resolver.js.map +1 -1
- package/package.json +3 -3
- package/src/drizzle-fastify/mount-read-only.ts +18 -6
- package/src/relation-resolver.ts +25 -28
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FastifyInstance } from "fastify";
|
|
1
|
+
import type { FastifyInstance, RouteShorthandOptions } from "fastify";
|
|
2
2
|
import type { FilterAllowlist, SortAllowlist } from "./filter-allowlist.js";
|
|
3
3
|
type AnyView = any;
|
|
4
4
|
export interface MountReadOnlyOptions {
|
|
@@ -11,6 +11,17 @@ export interface MountReadOnlyOptions {
|
|
|
11
11
|
readonly dialect: "postgres" | "sqlite";
|
|
12
12
|
/** Override default ID column name (defaults to "id"). */
|
|
13
13
|
readonly idColumn?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Fastify route-level hooks applied to every route this mounts — the same option
|
|
16
|
+
* `mountCrudRoutes` and `mountM2mRoute` take, and for the same reason:
|
|
17
|
+
* routeOptions: { preHandler: requireAuthHook }
|
|
18
|
+
*
|
|
19
|
+
* A projection is read-only, not public. It was the one mount helper of the three
|
|
20
|
+
* without this, so a generated projection route could not carry a hook the way a
|
|
21
|
+
* generated entity route could — an inconsistency, not a policy. (Guarding the whole
|
|
22
|
+
* mount from an enclosing plugin scope works here too, and needs no option at all.)
|
|
23
|
+
*/
|
|
24
|
+
readonly routeOptions?: RouteShorthandOptions;
|
|
14
25
|
}
|
|
15
26
|
export declare function mountReadOnlyCrudRoutes(opts: MountReadOnlyOptions): void;
|
|
16
27
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount-read-only.d.ts","sourceRoot":"","sources":["../../src/drizzle-fastify/mount-read-only.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"mount-read-only.d.ts","sourceRoot":"","sources":["../../src/drizzle-fastify/mount-read-only.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAItE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAI5E,KAAK,OAAO,GAAG,GAAG,CAAC;AAUnB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAC;IACxC,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,qBAAqB,CAAC;CAC/C;AA8FD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,CAwGxE"}
|
|
@@ -96,10 +96,11 @@ async function rawRows(db, dialect, query) {
|
|
|
96
96
|
export function mountReadOnlyCrudRoutes(opts) {
|
|
97
97
|
const { fastify, path, db, view, filterAllowlist, sortAllowlist, dialect } = opts;
|
|
98
98
|
const idCol = opts.idColumn ?? "id";
|
|
99
|
+
const ro = opts.routeOptions ?? {};
|
|
99
100
|
const viewName = resolveViewName(view);
|
|
100
101
|
const useRawSql = isEmptyColumnView(view) && !!viewName;
|
|
101
102
|
// ── List ──────────────────────────────────────────────────────────────────
|
|
102
|
-
fastify.get(path, async (req, reply) => {
|
|
103
|
+
fastify.get(path, ro, async (req, reply) => {
|
|
103
104
|
try {
|
|
104
105
|
if (useRawSql) {
|
|
105
106
|
// .existing() view with no column schema — use raw SQL.
|
|
@@ -171,7 +172,7 @@ export function mountReadOnlyCrudRoutes(opts) {
|
|
|
171
172
|
}
|
|
172
173
|
});
|
|
173
174
|
// ── Get by ID ─────────────────────────────────────────────────────────────
|
|
174
|
-
fastify.get(`${path}/:id`, async (req, reply) => {
|
|
175
|
+
fastify.get(`${path}/:id`, ro, async (req, reply) => {
|
|
175
176
|
const { id } = req.params;
|
|
176
177
|
if (useRawSql) {
|
|
177
178
|
// biome-ignore lint/suspicious/noExplicitAny: dynamic raw result
|
|
@@ -192,8 +193,8 @@ export function mountReadOnlyCrudRoutes(opts) {
|
|
|
192
193
|
return row ?? reply.code(404).send({ error: "not_found" });
|
|
193
194
|
});
|
|
194
195
|
// ── Mutations explicitly rejected (405) ───────────────────────────────────
|
|
195
|
-
fastify.post(path, REJECT_MUTATION);
|
|
196
|
-
fastify.patch(`${path}/:id`, REJECT_MUTATION);
|
|
197
|
-
fastify.delete(`${path}/:id`, REJECT_MUTATION);
|
|
196
|
+
fastify.post(path, ro, REJECT_MUTATION);
|
|
197
|
+
fastify.patch(`${path}/:id`, ro, REJECT_MUTATION);
|
|
198
|
+
fastify.delete(`${path}/:id`, ro, REJECT_MUTATION);
|
|
198
199
|
}
|
|
199
200
|
//# sourceMappingURL=mount-read-only.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount-read-only.js","sourceRoot":"","sources":["../../src/drizzle-fastify/mount-read-only.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAK7F;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"mount-read-only.js","sourceRoot":"","sources":["../../src/drizzle-fastify/mount-read-only.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAK7F;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;AA0B9D,MAAM,eAAe,GAAG,KAAK,EAC3B,OAA2B,EAC3B,KAAiE,EACjE,EAAE;IACF,KAAK;SACF,IAAI,CAAC,GAAG,CAAC;SACT,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,gDAAgD,EAAE,CAAC,CAAC;AACvH,CAAC,CAAC;AAEF,SAAS,aAAa,CAAC,IAAa;IAClC,IAAI,CAAC;QACH,MAAM,GAAG,GAAI,IAAgC,CAAC,gBAAgB,CAAC,CAAC;QAChE,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,OAAO,GAA8B,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,eAAe,CAAC,IAAa;IACpC,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,QAAQ;YAAE,OAAO,GAAG,CAAC,MAAM,CAAW,CAAC;IACpE,CAAC;IACD,gCAAgC;IAChC,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,OAAO,CACL,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAW,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/E,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CACpE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,IAAa;IACtC,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAwC,CAAC;QAC5E,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,0EAA0E;AAC1E,SAAS,WAAW,CAAC,GAA4B;IAC/C,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,iFAAiF;AACjF,KAAK,UAAU,OAAO,CAAC,EAAO,EAAE,OAA2B,EAAE,KAAc;IACzE,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAY,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,OAAO,GAAgC,CAAC;QAChE,OAAQ,GAAmD,EAAE,IAAI,IAAI,EAAE,CAAC;IAC1E,CAAC;IACD,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAA8B,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAA0B;IAChE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAClF,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;IACpC,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC;IAEnC,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC;IAExD,6EAA6E;IAC7E,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACzC,IAAI,CAAC;YACH,IAAI,SAAS,EAAE,CAAC;gBACd,wDAAwD;gBACxD,uEAAuE;gBACvE,qEAAqE;gBACrE,kDAAkD;gBAClD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;gBAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC9B,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzD,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAA4B,CAAC;gBAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACnH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnG,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;gBACpD,iEAAiE;gBACjE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,kBAAkB,QAAQ,WAAW,QAAQ,WAAW,SAAS,EAAE,CAAC,CAAU,CAAC;gBAC/H,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAA0B,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3E,IAAI,CAAC,SAAS;oBAAE,OAAO,SAAS,CAAC;gBACjC,iEAAiE;gBACjE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,QAAQ,GAAG,CAAC,CAAU,CAAC;gBAC1G,MAAM,KAAK,GAAW,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;gBACnD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;YACpC,CAAC;YAED,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAA4B,CAAC;YAChE,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;YACpD,MAAM,MAAM,GAAG,iBAAiB,CAAC;gBAC/B,KAAK,EAAE,MAAM;gBACb,KAAK,EAAE,IAAI;gBACX,SAAS,EAAE,eAAe;gBAC1B,aAAa;gBACb,OAAO;aACR,CAAC,CAAC;YACH,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW;gBACtD,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC;gBACvC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC;YACzC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,aAAa;gBAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YAC9C,IAAI,MAAM,CAAC,OAAO;gBAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YACrD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;gBAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;gBAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7D,+DAA+D;YAC/D,uEAAuE;YACvE,qEAAqE;YACrE,yEAAyE;YACzE,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC;YAErB,IAAI,CAAC,SAAS;gBAAE,OAAO,IAAI,CAAC;YAE5B,oDAAoD;YACpD,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,IAAI,aAAa;gBAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAA8B,CAAC;YAC5D,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC;YAC/B,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,gBAAgB,EAAE,CAAC;gBACpC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBACnF,OAAO;YACT,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QAClD,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAwB,CAAC;QAC5C,IAAI,SAAS,EAAE,CAAC;YACd,iEAAiE;YACjE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,kBAAkB,QAAQ,YAAY,KAAK,OAAO,YAAY,CAAC,EAAE,CAAC,UAAU,CAAC,CAAU,CAAC;YACxI,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvD,OAAO,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,4EAA4E;QAC5E,MAAM,MAAM,GAAI,IAAY,CAAC,KAAK,CAAC,CAAC;QACpC,qFAAqF;QACrF,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC9C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,uEAAuE;QACvE,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAC7C,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CACvD,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACX,MAAM,GAAG,GAAI,IAAkB,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,eAAe,CAAC,CAAC;IACxC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,MAAM,EAAE,EAAE,EAAE,eAAe,CAAC,CAAC;IAClD,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,MAAM,EAAE,EAAE,EAAE,eAAe,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation-resolver.d.ts","sourceRoot":"","sources":["../src/relation-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"relation-resolver.d.ts","sourceRoot":"","sources":["../src/relation-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAc,MAAM,0BAA0B,CAAC;AAC3F,OAAO,EAIL,eAAe,EAAE,gBAAgB,EAGlC,MAAM,0BAA0B,CAAC;AAKlC,OAAO,KAAK,EAAE,UAAU,EAAkB,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAE/E,MAAM,WAAW,kBAAkB;IACjC,4GAA4G;IAC5G,WAAW,EAAE,OAAO,eAAe,GAAG,OAAO,gBAAgB,CAAC;IAC9D,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,4GAA4G;IAC5G,WAAW,EAAE,MAAM,CAAC;IACpB,iGAAiG;IACjG,WAAW,EAAE,MAAM,CAAC;CACrB;AAmBD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,QAAQ,EACtB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,QAAQ,GACb,kBAAkB,CA8EpB;AAUD,uFAAuF;AACvF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,kBAAkB,EACxB,YAAY,EAAE,GAAG,EACjB,IAAI,EAAE,QAAQ,EACd,QAAQ,GAAE,oBAAqD,GAC9D,UAAU,GAAG,IAAI,CAKnB;AAED,gGAAgG;AAChG,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,kBAAkB,EACxB,aAAa,EAAE,GAAG,EAAE,EACpB,IAAI,EAAE,QAAQ,EACd,QAAQ,GAAE,oBAAqD,GAC9D,UAAU,GAAG,IAAI,CAUnB"}
|
|
@@ -1,35 +1,14 @@
|
|
|
1
|
-
import { TYPE_OBJECT, TYPE_RELATIONSHIP,
|
|
1
|
+
import { TYPE_OBJECT, TYPE_RELATIONSHIP, RELATIONSHIP_ATTR_CARDINALITY, RELATIONSHIP_ATTR_OBJECT_REF, RELATIONSHIP_ATTR_SOURCE_REF_FIELD, CARDINALITY_ONE, CARDINALITY_MANY, DEFAULT_COLUMN_NAMING_STRATEGY, resolveRelationshipReference, } from "@metaobjectsdev/metadata";
|
|
2
2
|
import { MetadataError } from "./errors.js";
|
|
3
3
|
import { buildSelectSpec, resolvePkFields, } from "./query-builder.js";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* The FK field a `@cardinality: one` relationship navigates through.
|
|
6
|
+
* #368: an entity may declare several identity.reference nodes onto the same
|
|
7
|
+
* target, so the target alone is not enough — resolve through the shared ladder.
|
|
7
8
|
*/
|
|
8
|
-
function findReferenceFkField(holder, targetName) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (child.type !== TYPE_IDENTITY)
|
|
12
|
-
continue;
|
|
13
|
-
if (child.subType !== IDENTITY_SUBTYPE_REFERENCE)
|
|
14
|
-
continue;
|
|
15
|
-
// ADR-0039: effective attrs — @references/@fields may be inherited.
|
|
16
|
-
const ref = child.attr(IDENTITY_REFERENCE_ATTR_REFERENCES);
|
|
17
|
-
if (typeof ref !== "string")
|
|
18
|
-
continue;
|
|
19
|
-
const dotIdx = ref.indexOf(".");
|
|
20
|
-
const entityName = dotIdx === -1 ? ref : ref.slice(0, dotIdx);
|
|
21
|
-
if (entityName !== targetName)
|
|
22
|
-
continue;
|
|
23
|
-
const fields = child.attr(IDENTITY_ATTR_FIELDS);
|
|
24
|
-
if (Array.isArray(fields) && fields.length > 0)
|
|
25
|
-
return String(fields[0]);
|
|
26
|
-
if (typeof fields === "string") {
|
|
27
|
-
const first = fields.split(",")[0]?.trim();
|
|
28
|
-
if (first)
|
|
29
|
-
return first;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return undefined;
|
|
9
|
+
function findReferenceFkField(holder, targetName, relationshipName, sourceRefField) {
|
|
10
|
+
const ref = resolveRelationshipReference(holder, relationshipName, targetName, sourceRefField);
|
|
11
|
+
return ref?.fields[0];
|
|
33
12
|
}
|
|
34
13
|
/**
|
|
35
14
|
* Walks one-side (relationship children of `sourceEntity`) then many-side (relationship
|
|
@@ -54,7 +33,9 @@ export function resolveRelationDescriptor(sourceEntity, relationName, root) {
|
|
|
54
33
|
if (!targetEntityName) {
|
|
55
34
|
throw new MetadataError(`Relationship '${relationName}' on '${sourceEntity.name}' missing @objectRef`, { entity: sourceEntity.name });
|
|
56
35
|
}
|
|
57
|
-
|
|
36
|
+
// ADR-0039: resolving — @sourceRefField may be inherited via extends.
|
|
37
|
+
const declaredRefField = child.attr(RELATIONSHIP_ATTR_SOURCE_REF_FIELD);
|
|
38
|
+
const fkField = findReferenceFkField(sourceEntity, targetEntityName, child.name, declaredRefField);
|
|
58
39
|
if (!fkField) {
|
|
59
40
|
throw new MetadataError(`Relationship '${relationName}' on '${sourceEntity.name}' has no identity.reference targeting '${targetEntityName}'`, { entity: sourceEntity.name });
|
|
60
41
|
}
|
|
@@ -90,7 +71,11 @@ export function resolveRelationDescriptor(sourceEntity, relationName, root) {
|
|
|
90
71
|
const inverseName = inversePluralName(other.name);
|
|
91
72
|
if (inverseName !== relationName)
|
|
92
73
|
continue;
|
|
93
|
-
|
|
74
|
+
// ADR-0039: resolving — @sourceRefField may be inherited via extends. This
|
|
75
|
+
// FK lives on `other` and belongs to `other`'s own relationship `child` —
|
|
76
|
+
// not to anything declared on sourceEntity (see #368 module comment).
|
|
77
|
+
const declaredRefField = child.attr(RELATIONSHIP_ATTR_SOURCE_REF_FIELD);
|
|
78
|
+
const fkField = findReferenceFkField(other, sourceEntity.name, child.name, declaredRefField);
|
|
94
79
|
if (!fkField) {
|
|
95
80
|
throw new MetadataError(`Inverse relationship for '${relationName}' on '${sourceEntity.name}': entity '${other.name}' has no identity.reference targeting '${sourceEntity.name}'`, { entity: sourceEntity.name });
|
|
96
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation-resolver.js","sourceRoot":"","sources":["../src/relation-resolver.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"relation-resolver.js","sourceRoot":"","sources":["../src/relation-resolver.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.
|
|
3
|
+
"version": "1.0.4",
|
|
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.
|
|
68
|
-
"@metaobjectsdev/render": "1.0.
|
|
67
|
+
"@metaobjectsdev/metadata": "1.0.4",
|
|
68
|
+
"@metaobjectsdev/render": "1.0.4",
|
|
69
69
|
"qs": "^6.13.0"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FastifyInstance } from "fastify";
|
|
1
|
+
import type { FastifyInstance, RouteShorthandOptions } from "fastify";
|
|
2
2
|
import { sql, eq, and, count } from "drizzle-orm";
|
|
3
3
|
import qs from "qs";
|
|
4
4
|
import { parseFilterParams, FilterParseError } from "./filter-parser.js";
|
|
@@ -27,6 +27,17 @@ export interface MountReadOnlyOptions {
|
|
|
27
27
|
readonly dialect: "postgres" | "sqlite";
|
|
28
28
|
/** Override default ID column name (defaults to "id"). */
|
|
29
29
|
readonly idColumn?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Fastify route-level hooks applied to every route this mounts — the same option
|
|
32
|
+
* `mountCrudRoutes` and `mountM2mRoute` take, and for the same reason:
|
|
33
|
+
* routeOptions: { preHandler: requireAuthHook }
|
|
34
|
+
*
|
|
35
|
+
* A projection is read-only, not public. It was the one mount helper of the three
|
|
36
|
+
* without this, so a generated projection route could not carry a hook the way a
|
|
37
|
+
* generated entity route could — an inconsistency, not a policy. (Guarding the whole
|
|
38
|
+
* mount from an enclosing plugin scope works here too, and needs no option at all.)
|
|
39
|
+
*/
|
|
40
|
+
readonly routeOptions?: RouteShorthandOptions;
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
const REJECT_MUTATION = async (
|
|
@@ -124,12 +135,13 @@ async function rawRows(db: any, dialect: string | undefined, query: unknown): Pr
|
|
|
124
135
|
export function mountReadOnlyCrudRoutes(opts: MountReadOnlyOptions): void {
|
|
125
136
|
const { fastify, path, db, view, filterAllowlist, sortAllowlist, dialect } = opts;
|
|
126
137
|
const idCol = opts.idColumn ?? "id";
|
|
138
|
+
const ro = opts.routeOptions ?? {};
|
|
127
139
|
|
|
128
140
|
const viewName = resolveViewName(view);
|
|
129
141
|
const useRawSql = isEmptyColumnView(view) && !!viewName;
|
|
130
142
|
|
|
131
143
|
// ── List ──────────────────────────────────────────────────────────────────
|
|
132
|
-
fastify.get(path, async (req, reply) => {
|
|
144
|
+
fastify.get(path, ro, async (req, reply) => {
|
|
133
145
|
try {
|
|
134
146
|
if (useRawSql) {
|
|
135
147
|
// .existing() view with no column schema — use raw SQL.
|
|
@@ -197,7 +209,7 @@ export function mountReadOnlyCrudRoutes(opts: MountReadOnlyOptions): void {
|
|
|
197
209
|
});
|
|
198
210
|
|
|
199
211
|
// ── Get by ID ─────────────────────────────────────────────────────────────
|
|
200
|
-
fastify.get(`${path}/:id`, async (req, reply) => {
|
|
212
|
+
fastify.get(`${path}/:id`, ro, async (req, reply) => {
|
|
201
213
|
const { id } = req.params as { id: string };
|
|
202
214
|
if (useRawSql) {
|
|
203
215
|
// biome-ignore lint/suspicious/noExplicitAny: dynamic raw result
|
|
@@ -221,7 +233,7 @@ export function mountReadOnlyCrudRoutes(opts: MountReadOnlyOptions): void {
|
|
|
221
233
|
});
|
|
222
234
|
|
|
223
235
|
// ── Mutations explicitly rejected (405) ───────────────────────────────────
|
|
224
|
-
fastify.post(path, REJECT_MUTATION);
|
|
225
|
-
fastify.patch(`${path}/:id`, REJECT_MUTATION);
|
|
226
|
-
fastify.delete(`${path}/:id`, REJECT_MUTATION);
|
|
236
|
+
fastify.post(path, ro, REJECT_MUTATION);
|
|
237
|
+
fastify.patch(`${path}/:id`, ro, REJECT_MUTATION);
|
|
238
|
+
fastify.delete(`${path}/:id`, ro, REJECT_MUTATION);
|
|
227
239
|
}
|
package/src/relation-resolver.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type { ColumnNamingStrategy, MetaData } from "@metaobjectsdev/metadata";
|
|
1
|
+
import type { ColumnNamingStrategy, MetaData, MetaObject } from "@metaobjectsdev/metadata";
|
|
2
2
|
import {
|
|
3
|
-
TYPE_OBJECT, TYPE_RELATIONSHIP,
|
|
4
|
-
IDENTITY_SUBTYPE_REFERENCE,
|
|
5
|
-
IDENTITY_ATTR_FIELDS,
|
|
6
|
-
IDENTITY_REFERENCE_ATTR_REFERENCES,
|
|
3
|
+
TYPE_OBJECT, TYPE_RELATIONSHIP,
|
|
7
4
|
RELATIONSHIP_ATTR_CARDINALITY, RELATIONSHIP_ATTR_OBJECT_REF,
|
|
5
|
+
RELATIONSHIP_ATTR_SOURCE_REF_FIELD,
|
|
8
6
|
CARDINALITY_ONE, CARDINALITY_MANY,
|
|
9
7
|
DEFAULT_COLUMN_NAMING_STRATEGY,
|
|
8
|
+
resolveRelationshipReference,
|
|
10
9
|
} from "@metaobjectsdev/metadata";
|
|
11
10
|
import { MetadataError } from "./errors.js";
|
|
12
11
|
import {
|
|
@@ -26,28 +25,20 @@ export interface RelationDescriptor {
|
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* The FK field a `@cardinality: one` relationship navigates through.
|
|
29
|
+
* #368: an entity may declare several identity.reference nodes onto the same
|
|
30
|
+
* target, so the target alone is not enough — resolve through the shared ladder.
|
|
31
31
|
*/
|
|
32
|
-
function findReferenceFkField(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (entityName !== targetName) continue;
|
|
43
|
-
const fields = child.attr(IDENTITY_ATTR_FIELDS);
|
|
44
|
-
if (Array.isArray(fields) && fields.length > 0) return String(fields[0]);
|
|
45
|
-
if (typeof fields === "string") {
|
|
46
|
-
const first = fields.split(",")[0]?.trim();
|
|
47
|
-
if (first) return first;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return undefined;
|
|
32
|
+
function findReferenceFkField(
|
|
33
|
+
holder: MetaData,
|
|
34
|
+
targetName: string,
|
|
35
|
+
relationshipName: string,
|
|
36
|
+
sourceRefField?: string,
|
|
37
|
+
): string | undefined {
|
|
38
|
+
const ref = resolveRelationshipReference(
|
|
39
|
+
holder as unknown as MetaObject, relationshipName, targetName, sourceRefField,
|
|
40
|
+
);
|
|
41
|
+
return ref?.fields[0];
|
|
51
42
|
}
|
|
52
43
|
|
|
53
44
|
/**
|
|
@@ -77,7 +68,9 @@ export function resolveRelationDescriptor(
|
|
|
77
68
|
{ entity: sourceEntity.name },
|
|
78
69
|
);
|
|
79
70
|
}
|
|
80
|
-
|
|
71
|
+
// ADR-0039: resolving — @sourceRefField may be inherited via extends.
|
|
72
|
+
const declaredRefField = child.attr(RELATIONSHIP_ATTR_SOURCE_REF_FIELD) as string | undefined;
|
|
73
|
+
const fkField = findReferenceFkField(sourceEntity, targetEntityName, child.name, declaredRefField);
|
|
81
74
|
if (!fkField) {
|
|
82
75
|
throw new MetadataError(
|
|
83
76
|
`Relationship '${relationName}' on '${sourceEntity.name}' has no identity.reference targeting '${targetEntityName}'`,
|
|
@@ -114,7 +107,11 @@ export function resolveRelationDescriptor(
|
|
|
114
107
|
if (targetEntityName !== sourceEntity.name) continue;
|
|
115
108
|
const inverseName = inversePluralName(other.name);
|
|
116
109
|
if (inverseName !== relationName) continue;
|
|
117
|
-
|
|
110
|
+
// ADR-0039: resolving — @sourceRefField may be inherited via extends. This
|
|
111
|
+
// FK lives on `other` and belongs to `other`'s own relationship `child` —
|
|
112
|
+
// not to anything declared on sourceEntity (see #368 module comment).
|
|
113
|
+
const declaredRefField = child.attr(RELATIONSHIP_ATTR_SOURCE_REF_FIELD) as string | undefined;
|
|
114
|
+
const fkField = findReferenceFkField(other, sourceEntity.name, child.name, declaredRefField);
|
|
118
115
|
if (!fkField) {
|
|
119
116
|
throw new MetadataError(
|
|
120
117
|
`Inverse relationship for '${relationName}' on '${sourceEntity.name}': entity '${other.name}' has no identity.reference targeting '${sourceEntity.name}'`,
|