@danielfgray/pg-sourcerer 0.2.2 → 0.4.0
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/bin/pgsourcerer +2 -0
- package/dist/__tests__/fixtures/index.d.ts +15 -0
- package/dist/__tests__/fixtures/index.d.ts.map +1 -0
- package/dist/__tests__/fixtures/index.js +19 -0
- package/dist/__tests__/fixtures/index.js.map +1 -0
- package/dist/__tests__/fixtures/introspection.json +40522 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +7 -46
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +38 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -2
- package/dist/config.js.map +1 -1
- package/dist/{lib/conjure.d.ts → conjure/index.d.ts} +62 -3
- package/dist/conjure/index.d.ts.map +1 -0
- package/dist/{lib/conjure.js → conjure/index.js} +124 -3
- package/dist/conjure/index.js.map +1 -0
- package/dist/conjure/signature.d.ts +85 -0
- package/dist/conjure/signature.d.ts.map +1 -0
- package/dist/conjure/signature.js +130 -0
- package/dist/conjure/signature.js.map +1 -0
- package/dist/conjure/types.d.ts +97 -0
- package/dist/conjure/types.d.ts.map +1 -0
- package/dist/conjure/types.js +206 -0
- package/dist/conjure/types.js.map +1 -0
- package/dist/errors.d.ts +114 -139
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +82 -36
- package/dist/errors.js.map +1 -1
- package/dist/generate.d.ts +45 -46
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +86 -59
- package/dist/generate.js.map +1 -1
- package/dist/hex/builder.d.ts +12 -0
- package/dist/hex/builder.d.ts.map +1 -0
- package/dist/hex/builder.js +64 -0
- package/dist/hex/builder.js.map +1 -0
- package/dist/hex/ddl.d.ts +53 -0
- package/dist/hex/ddl.d.ts.map +1 -0
- package/dist/hex/ddl.js +306 -0
- package/dist/hex/ddl.js.map +1 -0
- package/dist/hex/index.d.ts +105 -0
- package/dist/hex/index.d.ts.map +1 -0
- package/dist/hex/index.js +81 -0
- package/dist/hex/index.js.map +1 -0
- package/dist/hex/primitives.d.ts +23 -0
- package/dist/hex/primitives.d.ts.map +1 -0
- package/dist/hex/primitives.js +38 -0
- package/dist/hex/primitives.js.map +1 -0
- package/dist/hex/query.d.ts +116 -0
- package/dist/hex/query.d.ts.map +1 -0
- package/dist/hex/query.js +219 -0
- package/dist/hex/query.js.map +1 -0
- package/dist/hex/types.d.ts +287 -0
- package/dist/hex/types.d.ts.map +1 -0
- package/dist/hex/types.js +431 -0
- package/dist/hex/types.js.map +1 -0
- package/dist/index.d.ts +17 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -44
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +76 -140
- package/dist/init.js.map +1 -1
- package/dist/ir/extensions/queries.d.ts +6 -6
- package/dist/ir/extensions/queries.d.ts.map +1 -1
- package/dist/ir/extensions/queries.js +6 -4
- package/dist/ir/extensions/queries.js.map +1 -1
- package/dist/ir/extensions/schema-builder.d.ts.map +1 -1
- package/dist/ir/extensions/schema-builder.js.map +1 -1
- package/dist/ir/index.d.ts.map +1 -1
- package/dist/ir/index.js.map +1 -1
- package/dist/ir/relation-graph.d.ts.map +1 -1
- package/dist/ir/relation-graph.js +8 -8
- package/dist/ir/relation-graph.js.map +1 -1
- package/dist/ir/semantic-ir.d.ts +38 -0
- package/dist/ir/semantic-ir.d.ts.map +1 -1
- package/dist/ir/semantic-ir.js +50 -2
- package/dist/ir/semantic-ir.js.map +1 -1
- package/dist/ir/smart-tags.d.ts.map +1 -1
- package/dist/ir/smart-tags.js.map +1 -1
- package/dist/lib/field-utils.d.ts.map +1 -1
- package/dist/lib/field-utils.js +7 -7
- package/dist/lib/field-utils.js.map +1 -1
- package/dist/lib/join-graph.d.ts +95 -0
- package/dist/lib/join-graph.d.ts.map +1 -0
- package/dist/lib/join-graph.js +305 -0
- package/dist/lib/join-graph.js.map +1 -0
- package/dist/lib/picker.d.ts +60 -0
- package/dist/lib/picker.d.ts.map +1 -0
- package/dist/lib/picker.js +325 -0
- package/dist/lib/picker.js.map +1 -0
- package/dist/plugins/arktype.d.ts +20 -24
- package/dist/plugins/arktype.d.ts.map +1 -1
- package/dist/plugins/arktype.js +462 -386
- package/dist/plugins/arktype.js.map +1 -1
- package/dist/plugins/effect/http.d.ts +7 -0
- package/dist/plugins/effect/http.d.ts.map +1 -0
- package/dist/plugins/effect/http.js +460 -0
- package/dist/plugins/effect/http.js.map +1 -0
- package/dist/plugins/effect/index.d.ts +22 -0
- package/dist/plugins/effect/index.d.ts.map +1 -0
- package/dist/plugins/effect/index.js +65 -0
- package/dist/plugins/effect/index.js.map +1 -0
- package/dist/plugins/effect/models.d.ts +6 -0
- package/dist/plugins/effect/models.d.ts.map +1 -0
- package/dist/plugins/effect/models.js +116 -0
- package/dist/plugins/effect/models.js.map +1 -0
- package/dist/plugins/effect/repos.d.ts +21 -0
- package/dist/plugins/effect/repos.d.ts.map +1 -0
- package/dist/plugins/effect/repos.js +131 -0
- package/dist/plugins/effect/repos.js.map +1 -0
- package/dist/plugins/effect/schemas.d.ts +7 -0
- package/dist/plugins/effect/schemas.d.ts.map +1 -0
- package/dist/plugins/effect/schemas.js +75 -0
- package/dist/plugins/effect/schemas.js.map +1 -0
- package/dist/plugins/effect/shared.d.ts +116 -0
- package/dist/plugins/effect/shared.d.ts.map +1 -0
- package/dist/plugins/effect/shared.js +164 -0
- package/dist/plugins/effect/shared.js.map +1 -0
- package/dist/plugins/http-elysia.d.ts +20 -27
- package/dist/plugins/http-elysia.d.ts.map +1 -1
- package/dist/plugins/http-elysia.js +350 -475
- package/dist/plugins/http-elysia.js.map +1 -1
- package/dist/plugins/http-express.d.ts +20 -31
- package/dist/plugins/http-express.d.ts.map +1 -1
- package/dist/plugins/http-express.js +281 -268
- package/dist/plugins/http-express.js.map +1 -1
- package/dist/plugins/http-hono.d.ts +17 -33
- package/dist/plugins/http-hono.d.ts.map +1 -1
- package/dist/plugins/http-hono.js +317 -341
- package/dist/plugins/http-hono.js.map +1 -1
- package/dist/plugins/http-orpc.d.ts +34 -33
- package/dist/plugins/http-orpc.d.ts.map +1 -1
- package/dist/plugins/http-orpc.js +345 -257
- package/dist/plugins/http-orpc.js.map +1 -1
- package/dist/plugins/http-trpc.d.ts +33 -35
- package/dist/plugins/http-trpc.d.ts.map +1 -1
- package/dist/plugins/http-trpc.js +337 -241
- package/dist/plugins/http-trpc.js.map +1 -1
- package/dist/plugins/kysely.d.ts +54 -59
- package/dist/plugins/kysely.d.ts.map +1 -1
- package/dist/plugins/kysely.js +826 -687
- package/dist/plugins/kysely.js.map +1 -1
- package/dist/plugins/sql-queries.d.ts +38 -44
- package/dist/plugins/sql-queries.d.ts.map +1 -1
- package/dist/plugins/sql-queries.js +497 -897
- package/dist/plugins/sql-queries.js.map +1 -1
- package/dist/plugins/types.d.ts +12 -20
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/plugins/types.js +84 -227
- package/dist/plugins/types.js.map +1 -1
- package/dist/plugins/valibot.d.ts +7 -44
- package/dist/plugins/valibot.d.ts.map +1 -1
- package/dist/plugins/valibot.js +376 -382
- package/dist/plugins/valibot.js.map +1 -1
- package/dist/plugins/zod.d.ts +20 -24
- package/dist/plugins/zod.d.ts.map +1 -1
- package/dist/plugins/zod.js +370 -367
- package/dist/plugins/zod.js.map +1 -1
- package/dist/runtime/emit.d.ts +64 -0
- package/dist/runtime/emit.d.ts.map +1 -0
- package/dist/runtime/emit.js +445 -0
- package/dist/runtime/emit.js.map +1 -0
- package/dist/runtime/errors.d.ts +36 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +29 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/file-assignment.d.ts +161 -0
- package/dist/runtime/file-assignment.d.ts.map +1 -0
- package/dist/runtime/file-assignment.js +195 -0
- package/dist/runtime/file-assignment.js.map +1 -0
- package/dist/runtime/orchestrator.d.ts +62 -0
- package/dist/runtime/orchestrator.d.ts.map +1 -0
- package/dist/runtime/orchestrator.js +99 -0
- package/dist/runtime/orchestrator.js.map +1 -0
- package/dist/runtime/registry.d.ts +268 -0
- package/dist/runtime/registry.d.ts.map +1 -0
- package/dist/runtime/registry.js +436 -0
- package/dist/runtime/registry.js.map +1 -0
- package/dist/runtime/types.d.ts +182 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/validation.d.ts +41 -0
- package/dist/runtime/validation.d.ts.map +1 -0
- package/dist/runtime/validation.js +70 -0
- package/dist/runtime/validation.js.map +1 -0
- package/dist/services/config-loader.d.ts.map +1 -1
- package/dist/services/config-loader.js +15 -6
- package/dist/services/config-loader.js.map +1 -1
- package/dist/services/config.d.ts +55 -25
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +60 -34
- package/dist/services/config.js.map +1 -1
- package/dist/services/file-writer.d.ts +3 -3
- package/dist/services/file-writer.d.ts.map +1 -1
- package/dist/services/file-writer.js +6 -8
- package/dist/services/file-writer.js.map +1 -1
- package/dist/services/inflection.d.ts +126 -27
- package/dist/services/inflection.d.ts.map +1 -1
- package/dist/services/inflection.js +300 -72
- package/dist/services/inflection.js.map +1 -1
- package/dist/services/introspection.d.ts.map +1 -1
- package/dist/services/introspection.js +6 -6
- package/dist/services/introspection.js.map +1 -1
- package/dist/services/ir-builder.d.ts.map +1 -1
- package/dist/services/ir-builder.js +73 -77
- package/dist/services/ir-builder.js.map +1 -1
- package/dist/services/ir.d.ts.map +1 -1
- package/dist/services/ir.js.map +1 -1
- package/dist/services/pg-types.d.ts.map +1 -1
- package/dist/services/pg-types.js +3 -3
- package/dist/services/pg-types.js.map +1 -1
- package/dist/services/smart-tags-parser.d.ts.map +1 -1
- package/dist/services/smart-tags-parser.js +4 -4
- package/dist/services/smart-tags-parser.js.map +1 -1
- package/dist/services/type-hints.d.ts.map +1 -1
- package/dist/services/type-hints.js +1 -1
- package/dist/services/type-hints.js.map +1 -1
- package/dist/services/user-module-parser.d.ts +46 -0
- package/dist/services/user-module-parser.d.ts.map +1 -0
- package/dist/services/user-module-parser.js +181 -0
- package/dist/services/user-module-parser.js.map +1 -0
- package/dist/shared/converters.d.ts +60 -0
- package/dist/shared/converters.d.ts.map +1 -0
- package/dist/shared/converters.js +168 -0
- package/dist/shared/converters.js.map +1 -0
- package/dist/shared/query-types.d.ts +95 -0
- package/dist/shared/query-types.d.ts.map +1 -0
- package/dist/shared/query-types.js +9 -0
- package/dist/shared/query-types.js.map +1 -0
- package/dist/testing.d.ts +125 -37
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +134 -42
- package/dist/testing.js.map +1 -1
- package/dist/user-module.d.ts +86 -0
- package/dist/user-module.d.ts.map +1 -0
- package/dist/user-module.js +55 -0
- package/dist/user-module.js.map +1 -0
- package/package.json +10 -6
- package/dist/lib/conjure.d.ts.map +0 -1
- package/dist/lib/conjure.js.map +0 -1
- package/dist/lib/hex.d.ts +0 -119
- package/dist/lib/hex.d.ts.map +0 -1
- package/dist/lib/hex.js +0 -188
- package/dist/lib/hex.js.map +0 -1
- package/dist/plugins/effect.d.ts +0 -53
- package/dist/plugins/effect.d.ts.map +0 -1
- package/dist/plugins/effect.js +0 -1074
- package/dist/plugins/effect.js.map +0 -1
- package/dist/plugins/kysely/queries.d.ts +0 -92
- package/dist/plugins/kysely/queries.d.ts.map +0 -1
- package/dist/plugins/kysely/queries.js +0 -1169
- package/dist/plugins/kysely/queries.js.map +0 -1
- package/dist/plugins/kysely/shared.d.ts +0 -59
- package/dist/plugins/kysely/shared.d.ts.map +0 -1
- package/dist/plugins/kysely/shared.js +0 -247
- package/dist/plugins/kysely/shared.js.map +0 -1
- package/dist/plugins/kysely/types.d.ts +0 -22
- package/dist/plugins/kysely/types.d.ts.map +0 -1
- package/dist/plugins/kysely/types.js +0 -428
- package/dist/plugins/kysely/types.js.map +0 -1
- package/dist/services/artifact-store.d.ts +0 -65
- package/dist/services/artifact-store.d.ts.map +0 -1
- package/dist/services/artifact-store.js +0 -57
- package/dist/services/artifact-store.js.map +0 -1
- package/dist/services/core-providers.d.ts +0 -15
- package/dist/services/core-providers.d.ts.map +0 -1
- package/dist/services/core-providers.js +0 -23
- package/dist/services/core-providers.js.map +0 -1
- package/dist/services/emissions.d.ts +0 -103
- package/dist/services/emissions.d.ts.map +0 -1
- package/dist/services/emissions.js +0 -241
- package/dist/services/emissions.js.map +0 -1
- package/dist/services/execution.d.ts +0 -35
- package/dist/services/execution.d.ts.map +0 -1
- package/dist/services/execution.js +0 -86
- package/dist/services/execution.js.map +0 -1
- package/dist/services/file-builder.d.ts +0 -85
- package/dist/services/file-builder.d.ts.map +0 -1
- package/dist/services/file-builder.js +0 -112
- package/dist/services/file-builder.js.map +0 -1
- package/dist/services/plugin-meta.d.ts +0 -33
- package/dist/services/plugin-meta.d.ts.map +0 -1
- package/dist/services/plugin-meta.js +0 -24
- package/dist/services/plugin-meta.js.map +0 -1
- package/dist/services/plugin-runner.d.ts +0 -42
- package/dist/services/plugin-runner.d.ts.map +0 -1
- package/dist/services/plugin-runner.js +0 -84
- package/dist/services/plugin-runner.js.map +0 -1
- package/dist/services/plugin.d.ts +0 -421
- package/dist/services/plugin.d.ts.map +0 -1
- package/dist/services/plugin.js +0 -197
- package/dist/services/plugin.js.map +0 -1
- package/dist/services/resolution.d.ts +0 -38
- package/dist/services/resolution.d.ts.map +0 -1
- package/dist/services/resolution.js +0 -242
- package/dist/services/resolution.js.map +0 -1
- package/dist/services/service-registry.d.ts +0 -74
- package/dist/services/service-registry.d.ts.map +0 -1
- package/dist/services/service-registry.js +0 -61
- package/dist/services/service-registry.js.map +0 -1
- package/dist/services/symbols.d.ts +0 -144
- package/dist/services/symbols.d.ts.map +0 -1
- package/dist/services/symbols.js +0 -144
- package/dist/services/symbols.js.map +0 -1
|
@@ -1,48 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HTTP tRPC Plugin -
|
|
2
|
+
* HTTP tRPC Plugin - Generates tRPC routers from query symbols
|
|
3
3
|
*
|
|
4
|
-
* Consumes
|
|
5
|
-
*
|
|
4
|
+
* Consumes "queries" and "schema" capabilities (provider-agnostic).
|
|
5
|
+
* Works with any queries provider (kysely, drizzle, effect-sql, etc.)
|
|
6
|
+
* and any schema provider (zod, arktype, effect, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Uses the SymbolRegistry to resolve query functions and optionally
|
|
9
|
+
* schema symbols for request validation.
|
|
10
|
+
*
|
|
11
|
+
* Imports are resolved via the cross-reference system:
|
|
12
|
+
* - Calls registry.import(queryCapability).ref() during render
|
|
13
|
+
* - Emit phase generates imports from the recorded references
|
|
6
14
|
*/
|
|
7
|
-
import { Schema as S } from "effect";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
15
|
+
import { Effect, Schema as S } from "effect";
|
|
16
|
+
import { IR } from "../services/ir.js";
|
|
17
|
+
import { Inflection } from "../services/inflection.js";
|
|
18
|
+
import { SymbolRegistry } from "../runtime/registry.js";
|
|
19
|
+
import { isTableEntity } from "../ir/semantic-ir.js";
|
|
20
|
+
import { conjure, cast } from "../conjure/index.js";
|
|
21
|
+
import { normalizeFileNaming } from "../runtime/file-assignment.js";
|
|
22
|
+
const b = conjure.b;
|
|
23
|
+
const stmt = conjure.stmt;
|
|
24
|
+
const PLUGIN_NAME = "trpc-http";
|
|
13
25
|
// ============================================================================
|
|
14
26
|
// Configuration
|
|
15
27
|
// ============================================================================
|
|
28
|
+
const DEFAULT_OUTPUT_DIR = "";
|
|
29
|
+
const DEFAULT_ROUTES_FILE = "trpc.ts";
|
|
30
|
+
const DEFAULT_APP_FILE = "trpc.ts";
|
|
31
|
+
/**
|
|
32
|
+
* Schema-validated portion of the config (simple types only).
|
|
33
|
+
*/
|
|
16
34
|
const HttpTrpcConfigSchema = S.Struct({
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Header content to prepend to each generated file.
|
|
21
|
-
* MUST import `router` and a base procedure (e.g., `publicProcedure`).
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* header: `import { router, publicProcedure } from "../trpc.js";`
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
header: S.String,
|
|
29
|
-
/**
|
|
30
|
-
* Name of the base procedure to use in generated code.
|
|
31
|
-
* Must match an import from your header.
|
|
32
|
-
* Default: "publicProcedure"
|
|
33
|
-
*/
|
|
35
|
+
outputDir: S.optionalWith(S.String, { default: () => DEFAULT_OUTPUT_DIR }),
|
|
36
|
+
/** Name of the base procedure to use. Default: "publicProcedure" */
|
|
34
37
|
baseProcedure: S.optionalWith(S.String, { default: () => "publicProcedure" }),
|
|
35
38
|
/** Name of the aggregated router export. Default: "appRouter" */
|
|
36
39
|
aggregatorName: S.optionalWith(S.String, { default: () => "appRouter" }),
|
|
37
40
|
});
|
|
38
41
|
// ============================================================================
|
|
39
|
-
// String Helpers
|
|
42
|
+
// String Helpers - removed, now using inflection service:
|
|
43
|
+
// - inflection.variableName(entity, "Router") for router variable names
|
|
44
|
+
// - inflection.camelCase(entity) for merged router keys
|
|
45
|
+
// - inflection.pascalCase(field) for lookup field suffix
|
|
40
46
|
// ============================================================================
|
|
41
|
-
/** Convert PascalCase/camelCase to kebab-case */
|
|
42
|
-
const toKebabCase = (str) => str
|
|
43
|
-
.replace(/([a-z])([A-Z])/g, "$1-$2")
|
|
44
|
-
.replace(/_/g, "-")
|
|
45
|
-
.toLowerCase();
|
|
46
47
|
// ============================================================================
|
|
47
48
|
// Procedure Builders
|
|
48
49
|
// ============================================================================
|
|
@@ -63,14 +64,20 @@ const kindToProcedureType = (kind) => {
|
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
/**
|
|
66
|
-
*
|
|
67
|
-
* tRPC handlers receive { input, ctx } and return data directly.
|
|
67
|
+
* Check if a param needs coercion (comes from URL string).
|
|
68
68
|
*/
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
function needsCoercion(param) {
|
|
70
|
+
return (param.source === "pk" ||
|
|
71
|
+
param.source === "fk" ||
|
|
72
|
+
param.source === "lookup" ||
|
|
73
|
+
param.source === "pagination");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Build the handler function body for a tRPC procedure.
|
|
77
|
+
* tRPC handlers receive { input } and return data directly.
|
|
78
|
+
*/
|
|
79
|
+
function buildProcedureBody(method) {
|
|
71
80
|
const callSig = method.callSignature ?? { style: "named" };
|
|
72
|
-
const statements = [];
|
|
73
|
-
// Build the function call arguments based on callSignature
|
|
74
81
|
const args = [];
|
|
75
82
|
if (callSig.style === "positional") {
|
|
76
83
|
// Positional: fn(a, b, c)
|
|
@@ -79,7 +86,7 @@ const buildProcedureBody = (method) => {
|
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
88
|
else {
|
|
82
|
-
// Named
|
|
89
|
+
// Named style
|
|
83
90
|
const bodyParam = method.params.find((p) => p.source === "body");
|
|
84
91
|
if (bodyParam && callSig.bodyStyle === "spread") {
|
|
85
92
|
// Body fields spread directly: fn(input)
|
|
@@ -87,29 +94,19 @@ const buildProcedureBody = (method) => {
|
|
|
87
94
|
}
|
|
88
95
|
else if (bodyParam && callSig.bodyStyle === "property") {
|
|
89
96
|
// Body wrapped in property: fn({ id, data })
|
|
90
|
-
// Collect non-body params that need to be extracted from input
|
|
91
97
|
const nonBodyParams = method.params.filter((p) => p.source === "pk" || p.source === "fk" || p.source === "lookup" || p.source === "pagination");
|
|
92
98
|
if (nonBodyParams.length > 0) {
|
|
93
|
-
//
|
|
94
|
-
const destructureProps = nonBodyParams.map((p) => b.property.from({ kind: "init", key: b.identifier(p.name), value: b.identifier(p.name), shorthand: true }));
|
|
95
|
-
const restId = b.identifier(bodyParam.name);
|
|
96
|
-
const restElem = b.restElement(restId);
|
|
97
|
-
const pattern = b.objectPattern([...destructureProps, restElem]);
|
|
98
|
-
const destructureDecl = b.variableDeclaration("const", [
|
|
99
|
-
b.variableDeclarator(pattern, b.identifier("input")),
|
|
100
|
-
]);
|
|
101
|
-
statements.push(destructureDecl);
|
|
102
|
-
// Build: { id, data } using the destructured variables
|
|
99
|
+
// Build object with non-body params + body property
|
|
103
100
|
let objBuilder = conjure.obj();
|
|
104
101
|
for (const param of nonBodyParams) {
|
|
105
|
-
objBuilder = objBuilder.
|
|
102
|
+
objBuilder = objBuilder.prop(param.name, b.memberExpression(b.identifier("input"), b.identifier(param.name)));
|
|
106
103
|
}
|
|
107
|
-
objBuilder = objBuilder.
|
|
104
|
+
objBuilder = objBuilder.prop(bodyParam.name, b.memberExpression(b.identifier("input"), b.identifier(bodyParam.name)));
|
|
108
105
|
args.push(objBuilder.build());
|
|
109
106
|
}
|
|
110
107
|
else {
|
|
111
|
-
// No non-body params, just
|
|
112
|
-
args.push(
|
|
108
|
+
// No non-body params, just pass input
|
|
109
|
+
args.push(b.identifier("input"));
|
|
113
110
|
}
|
|
114
111
|
}
|
|
115
112
|
else if (method.params.length > 0) {
|
|
@@ -117,73 +114,98 @@ const buildProcedureBody = (method) => {
|
|
|
117
114
|
args.push(b.identifier("input"));
|
|
118
115
|
}
|
|
119
116
|
}
|
|
120
|
-
// Build:
|
|
121
|
-
const queryCall = b.callExpression(b.identifier(
|
|
122
|
-
|
|
117
|
+
// Build: queryFn(args)
|
|
118
|
+
const queryCall = b.callExpression(b.identifier(method.name), args.map(cast.toExpr));
|
|
119
|
+
// Add the appropriate .execute*() method based on query kind
|
|
120
|
+
const executeMethod = method.kind === "read" || (method.kind === "lookup" && method.isUniqueLookup)
|
|
121
|
+
? "executeTakeFirst"
|
|
122
|
+
: method.kind === "create" || method.kind === "update"
|
|
123
|
+
? "executeTakeFirstOrThrow"
|
|
124
|
+
: "execute";
|
|
125
|
+
const queryWithExecute = b.callExpression(b.memberExpression(queryCall, b.identifier(executeMethod)), []);
|
|
126
|
+
const awaitExpr = b.awaitExpression(queryWithExecute);
|
|
123
127
|
// For delete, return success object
|
|
124
128
|
if (method.kind === "delete") {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
return [
|
|
130
|
+
b.expressionStatement(awaitExpr),
|
|
131
|
+
b.returnStatement(conjure.obj().prop("success", b.booleanLiteral(true)).build()),
|
|
132
|
+
];
|
|
128
133
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
};
|
|
134
|
+
return [b.returnStatement(awaitExpr)];
|
|
135
|
+
}
|
|
132
136
|
/**
|
|
133
|
-
*
|
|
137
|
+
* Build Zod type expression for a param.
|
|
134
138
|
*/
|
|
135
|
-
|
|
139
|
+
function buildZodParamType(param) {
|
|
140
|
+
const baseType = param.type.toLowerCase();
|
|
141
|
+
let zodCall;
|
|
142
|
+
switch (baseType) {
|
|
143
|
+
case "number":
|
|
144
|
+
zodCall = b.callExpression(b.memberExpression(b.memberExpression(b.identifier("z"), b.identifier("coerce")), b.identifier("number")), []);
|
|
145
|
+
break;
|
|
146
|
+
case "boolean":
|
|
147
|
+
zodCall = b.callExpression(b.memberExpression(b.identifier("z"), b.identifier("boolean")), []);
|
|
148
|
+
break;
|
|
149
|
+
case "date":
|
|
150
|
+
zodCall = b.callExpression(b.memberExpression(b.memberExpression(b.identifier("z"), b.identifier("coerce")), b.identifier("date")), []);
|
|
151
|
+
break;
|
|
152
|
+
case "string":
|
|
153
|
+
default:
|
|
154
|
+
zodCall = b.callExpression(b.memberExpression(b.identifier("z"), b.identifier("string")), []);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
if (!param.required) {
|
|
158
|
+
zodCall = b.callExpression(b.memberExpression(cast.toExpr(zodCall), b.identifier("optional")), []);
|
|
159
|
+
}
|
|
160
|
+
return zodCall;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get the body schema name for a method if it needs validation.
|
|
164
|
+
*/
|
|
165
|
+
function getBodySchemaName(method, entityName) {
|
|
136
166
|
if (method.kind === "create") {
|
|
137
|
-
return
|
|
167
|
+
return `${entityName}Insert`;
|
|
138
168
|
}
|
|
139
169
|
if (method.kind === "update") {
|
|
140
|
-
|
|
170
|
+
// Use UpdateInput schema: required PK + optional non-PK fields
|
|
171
|
+
return `${entityName}UpdateInput`;
|
|
141
172
|
}
|
|
142
173
|
return null;
|
|
143
|
-
}
|
|
174
|
+
}
|
|
144
175
|
/**
|
|
145
|
-
* Build
|
|
176
|
+
* Build input schema expression for a procedure.
|
|
177
|
+
* Returns the schema expression and whether we need z import.
|
|
146
178
|
*/
|
|
147
|
-
|
|
148
|
-
const
|
|
179
|
+
function buildInputSchema(method, entityName) {
|
|
180
|
+
const bodySchemaName = getBodySchemaName(method, entityName);
|
|
149
181
|
const nonBodyParams = method.params.filter((p) => p.source !== "body");
|
|
150
182
|
const callSig = method.callSignature ?? { style: "named" };
|
|
151
|
-
// For update with bodyStyle: "property",
|
|
152
|
-
if (
|
|
153
|
-
// Build: z.object({ id: z.coerce.number() }).merge(PostUpdate)
|
|
183
|
+
// For update with bodyStyle: "property", merge PK params with body schema
|
|
184
|
+
if (bodySchemaName && nonBodyParams.length > 0 && callSig.bodyStyle === "property") {
|
|
154
185
|
let objBuilder = conjure.obj();
|
|
155
186
|
for (const p of nonBodyParams) {
|
|
156
187
|
objBuilder = objBuilder.prop(p.name, buildZodParamType(p));
|
|
157
188
|
}
|
|
158
189
|
const zodObject = b.callExpression(b.memberExpression(b.identifier("z"), b.identifier("object")), [cast.toExpr(objBuilder.build())]);
|
|
159
|
-
const mergedSchema = b.callExpression(b.memberExpression(zodObject, b.identifier("merge")), [b.identifier(
|
|
190
|
+
const mergedSchema = b.callExpression(b.memberExpression(zodObject, b.identifier("merge")), [b.identifier(bodySchemaName)]);
|
|
160
191
|
return {
|
|
161
192
|
inputExpr: mergedSchema,
|
|
162
|
-
|
|
163
|
-
|
|
193
|
+
bodySchemaName,
|
|
194
|
+
needsZodImport: true,
|
|
164
195
|
};
|
|
165
196
|
}
|
|
166
197
|
// Body params only use imported entity schemas
|
|
167
|
-
if (
|
|
198
|
+
if (bodySchemaName) {
|
|
168
199
|
return {
|
|
169
|
-
inputExpr: b.identifier(
|
|
170
|
-
|
|
171
|
-
|
|
200
|
+
inputExpr: b.identifier(bodySchemaName),
|
|
201
|
+
bodySchemaName,
|
|
202
|
+
needsZodImport: false,
|
|
172
203
|
};
|
|
173
204
|
}
|
|
174
|
-
// Non-body params:
|
|
205
|
+
// Non-body params: build inline z.object
|
|
175
206
|
if (nonBodyParams.length === 0) {
|
|
176
|
-
return { inputExpr: null,
|
|
177
|
-
}
|
|
178
|
-
const schemaResult = requestSchema(nonBodyParams);
|
|
179
|
-
if (schemaResult) {
|
|
180
|
-
return {
|
|
181
|
-
inputExpr: schemaResult.ast,
|
|
182
|
-
bodySchema: null,
|
|
183
|
-
schemaBuilderImport: schemaResult.importSpec,
|
|
184
|
-
};
|
|
207
|
+
return { inputExpr: null, bodySchemaName: null, needsZodImport: false };
|
|
185
208
|
}
|
|
186
|
-
// Fallback: build inline z.object (tRPC requires Zod)
|
|
187
209
|
let objBuilder = conjure.obj();
|
|
188
210
|
for (const param of nonBodyParams) {
|
|
189
211
|
const zodType = buildZodParamType(param);
|
|
@@ -191,45 +213,19 @@ const buildInputSchema = (method, entityName, requestSchema) => {
|
|
|
191
213
|
}
|
|
192
214
|
return {
|
|
193
215
|
inputExpr: b.callExpression(b.memberExpression(b.identifier("z"), b.identifier("object")), [cast.toExpr(objBuilder.build())]),
|
|
194
|
-
|
|
195
|
-
|
|
216
|
+
bodySchemaName: null,
|
|
217
|
+
needsZodImport: true,
|
|
196
218
|
};
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Build Zod type expression for a param (fallback when no schema-builder).
|
|
200
|
-
*/
|
|
201
|
-
const buildZodParamType = (param) => {
|
|
202
|
-
const baseType = param.type.toLowerCase();
|
|
203
|
-
let zodCall;
|
|
204
|
-
switch (baseType) {
|
|
205
|
-
case "number":
|
|
206
|
-
zodCall = b.callExpression(b.memberExpression(b.memberExpression(b.identifier("z"), b.identifier("coerce")), b.identifier("number")), []);
|
|
207
|
-
break;
|
|
208
|
-
case "boolean":
|
|
209
|
-
zodCall = b.callExpression(b.memberExpression(b.identifier("z"), b.identifier("boolean")), []);
|
|
210
|
-
break;
|
|
211
|
-
case "date":
|
|
212
|
-
zodCall = b.callExpression(b.memberExpression(b.memberExpression(b.identifier("z"), b.identifier("coerce")), b.identifier("date")), []);
|
|
213
|
-
break;
|
|
214
|
-
case "string":
|
|
215
|
-
default:
|
|
216
|
-
zodCall = b.callExpression(b.memberExpression(b.identifier("z"), b.identifier("string")), []);
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
if (!param.required) {
|
|
220
|
-
zodCall = b.callExpression(b.memberExpression(cast.toExpr(zodCall), b.identifier("optional")), []);
|
|
221
|
-
}
|
|
222
|
-
return zodCall;
|
|
223
|
-
};
|
|
219
|
+
}
|
|
224
220
|
/**
|
|
225
|
-
* Build a single tRPC procedure.
|
|
221
|
+
* Build a single tRPC procedure expression.
|
|
226
222
|
*/
|
|
227
|
-
|
|
223
|
+
function buildProcedure(method, entityName, baseProcedure) {
|
|
228
224
|
const procedureType = kindToProcedureType(method.kind);
|
|
229
225
|
// Start with base procedure
|
|
230
226
|
let chainExpr = b.identifier(baseProcedure);
|
|
231
227
|
// Build input schema
|
|
232
|
-
const { inputExpr,
|
|
228
|
+
const { inputExpr, bodySchemaName, needsZodImport } = buildInputSchema(method, entityName);
|
|
233
229
|
// Add .input(schema) if there are params
|
|
234
230
|
if (inputExpr) {
|
|
235
231
|
chainExpr = b.callExpression(b.memberExpression(cast.toExpr(chainExpr), b.identifier("input")), [cast.toExpr(inputExpr)]);
|
|
@@ -246,147 +242,247 @@ const buildProcedure = (method, entityName, baseProcedure, requestSchema) => {
|
|
|
246
242
|
handler.async = true;
|
|
247
243
|
// Add .query() or .mutation()
|
|
248
244
|
chainExpr = b.callExpression(b.memberExpression(cast.toExpr(chainExpr), b.identifier(procedureType)), [handler]);
|
|
249
|
-
return { procedureExpr: chainExpr,
|
|
250
|
-
}
|
|
245
|
+
return { procedureExpr: chainExpr, bodySchemaName, needsZodImport };
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Get the capability suffix for a query method.
|
|
249
|
+
*/
|
|
250
|
+
function getMethodCapabilitySuffix(method, inflection) {
|
|
251
|
+
switch (method.kind) {
|
|
252
|
+
case "read":
|
|
253
|
+
return "findById";
|
|
254
|
+
case "list":
|
|
255
|
+
return "list";
|
|
256
|
+
case "create":
|
|
257
|
+
return "create";
|
|
258
|
+
case "update":
|
|
259
|
+
return "update";
|
|
260
|
+
case "delete":
|
|
261
|
+
return "delete";
|
|
262
|
+
case "lookup":
|
|
263
|
+
if (method.lookupField) {
|
|
264
|
+
const pascalField = inflection.pascalCase(method.lookupField);
|
|
265
|
+
return `findBy${pascalField}`;
|
|
266
|
+
}
|
|
267
|
+
return "lookup";
|
|
268
|
+
case "function":
|
|
269
|
+
return method.name;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Generate tRPC router for an entity.
|
|
274
|
+
*/
|
|
275
|
+
function generateTrpcRouter(entityName, queries, config, registry, inflection) {
|
|
276
|
+
const routerName = inflection.variableName(entityName, "Router");
|
|
277
|
+
let needsZodImport = false;
|
|
278
|
+
const bodySchemaNames = [];
|
|
279
|
+
// Build router object
|
|
280
|
+
let routerObjBuilder = conjure.obj();
|
|
281
|
+
for (const method of queries.methods) {
|
|
282
|
+
// Record cross-reference for this query method
|
|
283
|
+
const methodCapability = `queries:${entityName}:${getMethodCapabilitySuffix(method, inflection)}`;
|
|
284
|
+
if (registry.has(methodCapability)) {
|
|
285
|
+
registry.import(methodCapability).ref();
|
|
286
|
+
}
|
|
287
|
+
const { procedureExpr, bodySchemaName, needsZodImport: methodNeedsZod } = buildProcedure(method, entityName, config.baseProcedure);
|
|
288
|
+
if (bodySchemaName && !bodySchemaNames.includes(bodySchemaName)) {
|
|
289
|
+
bodySchemaNames.push(bodySchemaName);
|
|
290
|
+
// Import schema via cross-reference system
|
|
291
|
+
const schemaCapability = `schema:${bodySchemaName}`;
|
|
292
|
+
if (registry.has(schemaCapability)) {
|
|
293
|
+
registry.import(schemaCapability).ref();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (methodNeedsZod)
|
|
297
|
+
needsZodImport = true;
|
|
298
|
+
routerObjBuilder = routerObjBuilder.prop(method.name, procedureExpr);
|
|
299
|
+
}
|
|
300
|
+
// Build: export const userRouter = router({ ... })
|
|
301
|
+
const routerCall = b.callExpression(b.identifier("router"), [cast.toExpr(routerObjBuilder.build())]);
|
|
302
|
+
const variableDeclarator = b.variableDeclarator(b.identifier(routerName), cast.toExpr(routerCall));
|
|
303
|
+
const variableDeclaration = b.variableDeclaration("const", [variableDeclarator]);
|
|
304
|
+
const externalImports = [];
|
|
305
|
+
if (needsZodImport) {
|
|
306
|
+
externalImports.push({ from: "zod", names: ["z"] });
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
statements: [variableDeclaration],
|
|
310
|
+
externalImports,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Generate aggregator router that combines all entity routers.
|
|
315
|
+
*/
|
|
316
|
+
function generateAggregator(entities, config, registry, inflection) {
|
|
317
|
+
const entityEntries = Array.from(entities.entries());
|
|
318
|
+
if (entityEntries.length === 0) {
|
|
319
|
+
return { statements: [], externalImports: [] };
|
|
320
|
+
}
|
|
321
|
+
// Build: router({ user: userRouter, post: postRouter, ... })
|
|
322
|
+
let routerObjBuilder = conjure.obj();
|
|
323
|
+
for (const [entityName] of entityEntries) {
|
|
324
|
+
const routerName = inflection.variableName(entityName, "Router");
|
|
325
|
+
const key = inflection.camelCase(entityName);
|
|
326
|
+
routerObjBuilder = routerObjBuilder.prop(key, b.identifier(routerName));
|
|
327
|
+
// Record cross-reference to the entity's router capability
|
|
328
|
+
const routeCapability = `http-routes:trpc:${entityName}`;
|
|
329
|
+
if (registry.has(routeCapability)) {
|
|
330
|
+
registry.import(routeCapability).ref();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
const routerCall = b.callExpression(b.identifier("router"), [cast.toExpr(routerObjBuilder.build())]);
|
|
334
|
+
const variableDeclarator = b.variableDeclarator(b.identifier(config.aggregatorName), cast.toExpr(routerCall));
|
|
335
|
+
const variableDeclaration = b.variableDeclaration("const", [variableDeclarator]);
|
|
336
|
+
// Also export the type: export type AppRouter = typeof appRouter
|
|
337
|
+
const typeExport = b.exportNamedDeclaration(b.tsTypeAliasDeclaration(b.identifier("AppRouter"), b.tsTypeQuery(b.identifier(config.aggregatorName))));
|
|
338
|
+
return {
|
|
339
|
+
statements: [variableDeclaration, typeExport],
|
|
340
|
+
externalImports: [],
|
|
341
|
+
};
|
|
342
|
+
}
|
|
251
343
|
// ============================================================================
|
|
252
344
|
// Plugin Definition
|
|
253
345
|
// ============================================================================
|
|
254
346
|
/**
|
|
255
|
-
* Create an http-trpc
|
|
347
|
+
* Create an http-trpc plugin that generates tRPC routers.
|
|
256
348
|
*
|
|
257
349
|
* @example
|
|
258
350
|
* ```typescript
|
|
259
|
-
* import {
|
|
351
|
+
* import { trpc } from "pg-sourcerer"
|
|
260
352
|
*
|
|
261
353
|
* export default defineConfig({
|
|
262
354
|
* plugins: [
|
|
263
355
|
* zod(),
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
356
|
+
* kyselyQueries(),
|
|
357
|
+
* trpc({
|
|
358
|
+
* baseProcedure: "publicProcedure",
|
|
267
359
|
* }),
|
|
268
360
|
* ],
|
|
269
361
|
* })
|
|
270
362
|
* ```
|
|
271
363
|
*/
|
|
272
|
-
export function
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
364
|
+
export function trpc(config) {
|
|
365
|
+
const schemaConfig = S.decodeSync(HttpTrpcConfigSchema)(config ?? {});
|
|
366
|
+
const resolvedConfig = {
|
|
367
|
+
outputDir: schemaConfig.outputDir,
|
|
368
|
+
baseProcedure: schemaConfig.baseProcedure,
|
|
369
|
+
aggregatorName: schemaConfig.aggregatorName,
|
|
370
|
+
routesFile: normalizeFileNaming(config?.routesFile, DEFAULT_ROUTES_FILE),
|
|
371
|
+
appFile: normalizeFileNaming(config?.appFile, DEFAULT_APP_FILE),
|
|
372
|
+
trpcImport: config?.trpcImport,
|
|
373
|
+
};
|
|
374
|
+
return {
|
|
375
|
+
name: PLUGIN_NAME,
|
|
376
|
+
provides: [],
|
|
377
|
+
fileDefaults: [
|
|
378
|
+
// Entity routers use routesFile config
|
|
379
|
+
{
|
|
380
|
+
pattern: "http-routes:trpc:",
|
|
381
|
+
outputDir: resolvedConfig.outputDir,
|
|
382
|
+
fileNaming: resolvedConfig.routesFile,
|
|
383
|
+
},
|
|
384
|
+
// App aggregator uses appFile config (more specific pattern wins)
|
|
385
|
+
{
|
|
386
|
+
pattern: "http-routes:trpc:app",
|
|
387
|
+
outputDir: resolvedConfig.outputDir,
|
|
388
|
+
fileNaming: resolvedConfig.appFile,
|
|
389
|
+
},
|
|
282
390
|
],
|
|
283
|
-
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
// Track generated routers for aggregator
|
|
291
|
-
const generatedRouters = [];
|
|
292
|
-
// Create schema builder function
|
|
293
|
-
const requestSchema = (params) => {
|
|
294
|
-
if (params.length === 0)
|
|
295
|
-
return undefined;
|
|
296
|
-
try {
|
|
297
|
-
const request = { variant: "params", params };
|
|
298
|
-
return ctx.request(SCHEMA_BUILDER_KIND, request);
|
|
299
|
-
}
|
|
300
|
-
catch {
|
|
301
|
-
return undefined;
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
// Generate router for each entity
|
|
305
|
-
for (const entityName of entityNames) {
|
|
306
|
-
const entityMethods = ctx.symbols.getEntityMethods(entityName);
|
|
307
|
-
if (!entityMethods || entityMethods.methods.length === 0)
|
|
391
|
+
declare: Effect.gen(function* () {
|
|
392
|
+
const ir = yield* IR;
|
|
393
|
+
const inflection = yield* Inflection;
|
|
394
|
+
const declarations = [];
|
|
395
|
+
// Declare routers for all table entities that might have queries
|
|
396
|
+
for (const entity of ir.entities.values()) {
|
|
397
|
+
if (!isTableEntity(entity))
|
|
308
398
|
continue;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
from: queriesImportPath,
|
|
321
|
-
});
|
|
322
|
-
// Build router object
|
|
323
|
-
let routerObjBuilder = conjure.obj();
|
|
324
|
-
const bodySchemaImports = [];
|
|
325
|
-
let schemaLibraryImport = null;
|
|
326
|
-
for (const method of entityMethods.methods) {
|
|
327
|
-
const { procedureExpr, bodySchema, schemaBuilderImport } = buildProcedure(method, entityName, baseProcedure, requestSchema);
|
|
328
|
-
if (bodySchema)
|
|
329
|
-
bodySchemaImports.push(bodySchema);
|
|
330
|
-
if (schemaBuilderImport)
|
|
331
|
-
schemaLibraryImport = schemaBuilderImport;
|
|
332
|
-
routerObjBuilder = routerObjBuilder.prop(method.name, procedureExpr);
|
|
333
|
-
}
|
|
334
|
-
// Import schema library if needed
|
|
335
|
-
if (schemaLibraryImport) {
|
|
336
|
-
if (schemaLibraryImport.names) {
|
|
337
|
-
file.import({
|
|
338
|
-
kind: "package",
|
|
339
|
-
names: [...schemaLibraryImport.names],
|
|
340
|
-
from: schemaLibraryImport.from,
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
// Import body schemas
|
|
345
|
-
for (const schemaImport of bodySchemaImports) {
|
|
346
|
-
file.import({
|
|
347
|
-
kind: "symbol",
|
|
348
|
-
ref: {
|
|
349
|
-
capability: "schemas",
|
|
350
|
-
entity: schemaImport.entity,
|
|
351
|
-
shape: schemaImport.shape,
|
|
352
|
-
},
|
|
399
|
+
if (entity.tags.omit === true)
|
|
400
|
+
continue;
|
|
401
|
+
const hasAnyPermissions = entity.permissions.canSelect ||
|
|
402
|
+
entity.permissions.canInsert ||
|
|
403
|
+
entity.permissions.canUpdate ||
|
|
404
|
+
entity.permissions.canDelete;
|
|
405
|
+
if (hasAnyPermissions) {
|
|
406
|
+
declarations.push({
|
|
407
|
+
name: inflection.variableName(entity.name, "Router"),
|
|
408
|
+
capability: `http-routes:trpc:${entity.name}`,
|
|
409
|
+
baseEntityName: entity.name,
|
|
353
410
|
});
|
|
354
411
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
412
|
+
}
|
|
413
|
+
// Also declare the aggregator
|
|
414
|
+
declarations.push({
|
|
415
|
+
name: resolvedConfig.aggregatorName,
|
|
416
|
+
capability: "http-routes:trpc:app",
|
|
417
|
+
});
|
|
418
|
+
return declarations;
|
|
419
|
+
}),
|
|
420
|
+
render: Effect.gen(function* () {
|
|
421
|
+
const ir = yield* IR;
|
|
422
|
+
const registry = yield* SymbolRegistry;
|
|
423
|
+
const inflection = yield* Inflection;
|
|
424
|
+
const rendered = [];
|
|
425
|
+
// Query the registry for all entity query capabilities
|
|
426
|
+
const entityQueries = new Map();
|
|
427
|
+
const queryCapabilities = registry.query("queries:");
|
|
428
|
+
for (const decl of queryCapabilities) {
|
|
429
|
+
// Only look at aggregate capabilities (queries:impl:EntityName, not queries:impl:EntityName:method)
|
|
430
|
+
const parts = decl.capability.split(":");
|
|
431
|
+
if (parts.length !== 3)
|
|
432
|
+
continue;
|
|
433
|
+
const entityName = parts[2];
|
|
434
|
+
const metadata = registry.getMetadata(decl.capability);
|
|
435
|
+
if (metadata && typeof metadata === "object" && "methods" in metadata) {
|
|
436
|
+
entityQueries.set(entityName, metadata);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
// User module imports for router and procedure (if configured)
|
|
440
|
+
const trpcUserImports = resolvedConfig.trpcImport
|
|
441
|
+
? [resolvedConfig.trpcImport]
|
|
442
|
+
: undefined;
|
|
443
|
+
for (const [entityName, queries] of entityQueries) {
|
|
444
|
+
const entity = ir.entities.get(entityName);
|
|
445
|
+
if (!entity || !isTableEntity(entity))
|
|
446
|
+
continue;
|
|
447
|
+
const capability = `http-routes:trpc:${entityName}`;
|
|
448
|
+
// Scope cross-references to this specific capability
|
|
449
|
+
const { statements, externalImports } = registry.forSymbol(capability, () => generateTrpcRouter(entityName, queries, resolvedConfig, registry, inflection));
|
|
450
|
+
rendered.push({
|
|
451
|
+
name: inflection.variableName(entityName, "Router"),
|
|
452
|
+
capability,
|
|
453
|
+
node: statements[0],
|
|
454
|
+
exports: "named",
|
|
455
|
+
externalImports,
|
|
456
|
+
userImports: trpcUserImports,
|
|
362
457
|
});
|
|
363
458
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
459
|
+
if (entityQueries.size > 0) {
|
|
460
|
+
const appCapability = "http-routes:trpc:app";
|
|
461
|
+
// Scope cross-references to the app capability
|
|
462
|
+
const { statements, externalImports } = registry.forSymbol(appCapability, () => generateAggregator(entityQueries, resolvedConfig, registry, inflection));
|
|
463
|
+
// The aggregator has multiple statements (const + type export)
|
|
464
|
+
// We need to handle this differently - wrap in a program or return multiple
|
|
465
|
+
rendered.push({
|
|
466
|
+
name: resolvedConfig.aggregatorName,
|
|
467
|
+
capability: appCapability,
|
|
468
|
+
node: statements[0], // The const declaration
|
|
469
|
+
exports: "named",
|
|
470
|
+
externalImports,
|
|
471
|
+
userImports: trpcUserImports,
|
|
472
|
+
});
|
|
473
|
+
// Add the type export as a separate rendered symbol
|
|
474
|
+
if (statements[1]) {
|
|
475
|
+
rendered.push({
|
|
476
|
+
name: "AppRouter",
|
|
477
|
+
capability: "http-routes:trpc:app:type",
|
|
478
|
+
node: statements[1],
|
|
479
|
+
exports: false, // Already has export in the node
|
|
480
|
+
// No userImports needed for type export
|
|
375
481
|
});
|
|
376
482
|
}
|
|
377
|
-
// Build: export const appRouter = router({ user: userRouter, ... })
|
|
378
|
-
let routerObjBuilder = conjure.obj();
|
|
379
|
-
for (const route of generatedRouters) {
|
|
380
|
-
const key = route.routerName.replace(/Router$/, "");
|
|
381
|
-
routerObjBuilder = routerObjBuilder.prop(key, b.identifier(route.routerName));
|
|
382
|
-
}
|
|
383
|
-
const routerCall = b.callExpression(b.identifier("router"), [cast.toExpr(routerObjBuilder.build())]);
|
|
384
|
-
const exportStmt = conjure.export.const(aggregatorName, routerCall);
|
|
385
|
-
// Also export the type
|
|
386
|
-
const typeExport = b.exportNamedDeclaration(b.tsTypeAliasDeclaration(b.identifier("AppRouter"), b.tsTypeQuery(b.identifier(aggregatorName))));
|
|
387
|
-
indexFile.ast(conjure.program(exportStmt, typeExport)).emit();
|
|
388
483
|
}
|
|
389
|
-
|
|
390
|
-
|
|
484
|
+
return rendered;
|
|
485
|
+
}),
|
|
486
|
+
};
|
|
391
487
|
}
|
|
392
488
|
//# sourceMappingURL=http-trpc.js.map
|