postgresdk 0.18.1 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/cli.js +0 -0
  2. package/package.json +1 -1
  3. package/dist/cli.d.ts.map +0 -1
  4. package/dist/cli.js.map +0 -1
  5. package/dist/core/operations.d.ts +0 -68
  6. package/dist/emit-api-contract.d.ts +0 -60
  7. package/dist/emit-client.d.ts.map +0 -1
  8. package/dist/emit-client.js +0 -114
  9. package/dist/emit-client.js.map +0 -1
  10. package/dist/emit-include-builder.d.ts.map +0 -1
  11. package/dist/emit-include-builder.js +0 -30
  12. package/dist/emit-include-builder.js.map +0 -1
  13. package/dist/emit-include-loader.d.ts.map +0 -1
  14. package/dist/emit-include-loader.js +0 -299
  15. package/dist/emit-include-loader.js.map +0 -1
  16. package/dist/emit-include-spec.d.ts.map +0 -1
  17. package/dist/emit-include-spec.js +0 -26
  18. package/dist/emit-include-spec.js.map +0 -1
  19. package/dist/emit-logger.d.ts.map +0 -1
  20. package/dist/emit-logger.js +0 -35
  21. package/dist/emit-logger.js.map +0 -1
  22. package/dist/emit-router.d.ts +0 -5
  23. package/dist/emit-routes.d.ts.map +0 -1
  24. package/dist/emit-routes.js +0 -208
  25. package/dist/emit-routes.js.map +0 -1
  26. package/dist/emit-server-index.d.ts +0 -5
  27. package/dist/emit-types.d.ts.map +0 -1
  28. package/dist/emit-types.js +0 -51
  29. package/dist/emit-types.js.map +0 -1
  30. package/dist/emit-zod.d.ts.map +0 -1
  31. package/dist/emit-zod.js +0 -43
  32. package/dist/emit-zod.js.map +0 -1
  33. package/dist/gen.config.d.ts +0 -10
  34. package/dist/gen.config.js +0 -10
  35. package/dist/gen.config.js.map +0 -1
  36. package/dist/index.d.ts.map +0 -1
  37. package/dist/index.js.map +0 -1
  38. package/dist/introspect.d.ts.map +0 -1
  39. package/dist/introspect.js +0 -132
  40. package/dist/introspect.js.map +0 -1
  41. package/dist/rel-classify.d.ts.map +0 -1
  42. package/dist/rel-classify.js +0 -52
  43. package/dist/rel-classify.js.map +0 -1
  44. package/dist/src/cli.d.ts +0 -2
  45. package/dist/src/cli.js +0 -39
  46. package/dist/src/cli.js.map +0 -1
  47. package/dist/src/emit-client.d.ts +0 -3
  48. package/dist/src/emit-client.js +0 -114
  49. package/dist/src/emit-client.js.map +0 -1
  50. package/dist/src/emit-include-builder.d.ts +0 -2
  51. package/dist/src/emit-include-builder.js +0 -30
  52. package/dist/src/emit-include-builder.js.map +0 -1
  53. package/dist/src/emit-include-loader.d.ts +0 -9
  54. package/dist/src/emit-include-loader.js +0 -299
  55. package/dist/src/emit-include-loader.js.map +0 -1
  56. package/dist/src/emit-include-spec.d.ts +0 -2
  57. package/dist/src/emit-include-spec.js +0 -26
  58. package/dist/src/emit-include-spec.js.map +0 -1
  59. package/dist/src/emit-logger.d.ts +0 -1
  60. package/dist/src/emit-logger.js +0 -35
  61. package/dist/src/emit-logger.js.map +0 -1
  62. package/dist/src/emit-routes.d.ts +0 -20
  63. package/dist/src/emit-routes.js +0 -208
  64. package/dist/src/emit-routes.js.map +0 -1
  65. package/dist/src/emit-types.d.ts +0 -5
  66. package/dist/src/emit-types.js +0 -51
  67. package/dist/src/emit-types.js.map +0 -1
  68. package/dist/src/emit-zod.d.ts +0 -5
  69. package/dist/src/emit-zod.js +0 -43
  70. package/dist/src/emit-zod.js.map +0 -1
  71. package/dist/src/index.d.ts +0 -1
  72. package/dist/src/index.js +0 -83
  73. package/dist/src/index.js.map +0 -1
  74. package/dist/src/introspect.d.ts +0 -26
  75. package/dist/src/introspect.js +0 -132
  76. package/dist/src/introspect.js.map +0 -1
  77. package/dist/src/rel-classify.d.ts +0 -10
  78. package/dist/src/rel-classify.js +0 -52
  79. package/dist/src/rel-classify.js.map +0 -1
  80. package/dist/src/utils.d.ts +0 -6
  81. package/dist/src/utils.js +0 -17
  82. package/dist/src/utils.js.map +0 -1
  83. package/dist/utils.d.ts.map +0 -1
  84. package/dist/utils.js +0 -17
  85. package/dist/utils.js.map +0 -1
package/dist/cli.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postgresdk",
3
- "version": "0.18.1",
3
+ "version": "0.18.2",
4
4
  "description": "Generate a typed server/client SDK from a Postgres schema (includes, Zod, Hono).",
5
5
  "type": "module",
6
6
  "bin": {
package/dist/cli.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,2BAA2B;AAC3B,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAC1F,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AAEpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,mBAAmB;AACnB,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,gBAAgB;AAChB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;CAUb,CAAC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,kBAAkB;AAClB,IAAI,UAAU,GAAG,sBAAsB,CAAC;AACxC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC;AACxE,IAAI,WAAW,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC;IAChD,UAAU,GAAG,IAAI,CAAC,WAAW,GAAG,CAAC,CAAE,CAAC;AACtC,CAAC;AAED,gBAAgB;AAChB,IAAI,CAAC;IACH,MAAM,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;AACrD,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -1,68 +0,0 @@
1
- /**
2
- * Core database operations that are framework-agnostic.
3
- * These functions handle the actual database logic and can be used by any framework adapter.
4
- */
5
- export interface DatabaseClient {
6
- query: (text: string, params?: any[]) => Promise<{
7
- rows: any[];
8
- }>;
9
- }
10
- export interface OperationContext {
11
- pg: DatabaseClient;
12
- table: string;
13
- pkColumns: string[];
14
- softDeleteColumn?: string | null;
15
- includeMethodsDepth: number;
16
- }
17
- /**
18
- * CREATE operation - Insert a new record
19
- */
20
- export declare function createRecord(ctx: OperationContext, data: Record<string, any>): Promise<{
21
- data?: any;
22
- error?: string;
23
- issues?: any;
24
- status: number;
25
- }>;
26
- /**
27
- * READ operation - Get a record by primary key
28
- */
29
- export declare function getByPk(ctx: OperationContext, pkValues: any[]): Promise<{
30
- data?: any;
31
- error?: string;
32
- status: number;
33
- }>;
34
- /**
35
- * LIST operation - Get multiple records with optional filters
36
- */
37
- export declare function listRecords(ctx: OperationContext, params: {
38
- where?: any;
39
- limit?: number;
40
- offset?: number;
41
- include?: any;
42
- orderBy?: string | string[];
43
- order?: "asc" | "desc" | ("asc" | "desc")[];
44
- }): Promise<{
45
- data?: any;
46
- error?: string;
47
- issues?: any;
48
- needsIncludes?: boolean;
49
- includeSpec?: any;
50
- status: number;
51
- }>;
52
- /**
53
- * UPDATE operation - Update a record by primary key
54
- */
55
- export declare function updateRecord(ctx: OperationContext, pkValues: any[], updateData: Record<string, any>): Promise<{
56
- data?: any;
57
- error?: string;
58
- issues?: any;
59
- status: number;
60
- }>;
61
- /**
62
- * DELETE operation - Delete or soft-delete a record by primary key
63
- */
64
- export declare function deleteRecord(ctx: OperationContext, pkValues: any[]): Promise<{
65
- data?: any;
66
- error?: string;
67
- status: number;
68
- }>;
@@ -1,60 +0,0 @@
1
- import type { Model } from "./introspect";
2
- import type { Config, AuthConfig } from "./types";
3
- export interface ApiContract {
4
- version: string;
5
- generatedAt: string;
6
- description: string;
7
- authentication?: {
8
- type: string;
9
- description: string;
10
- };
11
- resources: ResourceContract[];
12
- relationships: RelationshipContract[];
13
- }
14
- export interface ResourceContract {
15
- name: string;
16
- tableName: string;
17
- description: string;
18
- endpoints: EndpointContract[];
19
- fields: FieldContract[];
20
- }
21
- export interface EndpointContract {
22
- method: string;
23
- path: string;
24
- description: string;
25
- requestBody?: any;
26
- responseBody?: any;
27
- queryParameters?: any;
28
- }
29
- export interface FieldContract {
30
- name: string;
31
- type: string;
32
- required: boolean;
33
- description: string;
34
- foreignKey?: {
35
- table: string;
36
- field: string;
37
- };
38
- }
39
- export interface RelationshipContract {
40
- from: string;
41
- to: string;
42
- type: "one-to-many" | "many-to-one" | "many-to-many";
43
- description: string;
44
- }
45
- /**
46
- * Generate a comprehensive API contract in JSON format
47
- */
48
- export declare function generateApiContract(model: Model, config: Config & {
49
- auth?: AuthConfig;
50
- }): ApiContract;
51
- /**
52
- * Generate a human-readable markdown version of the contract
53
- */
54
- export declare function generateApiContractMarkdown(contract: ApiContract): string;
55
- /**
56
- * Emit the API contract as TypeScript code that can be served as an endpoint
57
- */
58
- export declare function emitApiContract(model: Model, config: Config & {
59
- auth?: AuthConfig;
60
- }): string;
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-client.d.ts","sourceRoot":"","sources":["../src/emit-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAG1C,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,UA8FtC;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,UAmB9C"}
@@ -1,114 +0,0 @@
1
- import { pascal } from "./utils";
2
- export function emitClient(table) {
3
- const Type = pascal(table.name);
4
- // Normalize PKs
5
- const pkCols = Array.isArray(table.pk)
6
- ? table.pk
7
- : table.pk
8
- ? [table.pk]
9
- : [];
10
- const safePk = pkCols.length ? pkCols : ["id"];
11
- const hasCompositePk = safePk.length > 1;
12
- const pkType = hasCompositePk ? `{ ${safePk.map((c) => `${c}: string`).join("; ")} }` : `string`;
13
- const pkPathExpr = hasCompositePk ? safePk.map((c) => `pk.${c}`).join(` + "/" + `) : `pk`;
14
- return `/* Generated. Do not edit. */
15
- import type { ${Type}IncludeSpec } from "./include-spec";
16
- import type { Insert${Type}, Update${Type}, Select${Type} } from "./types/${table.name}";
17
-
18
- export class ${Type}Client {
19
- constructor(
20
- private baseUrl: string,
21
- private fetchFn: typeof fetch = fetch,
22
- private auth?: () => Promise<Record<string,string>>
23
- ) {}
24
-
25
- private async headers(json = false) {
26
- const extra = (await this.auth?.()) ?? {};
27
- return json ? { "Content-Type": "application/json", ...extra } : extra;
28
- }
29
-
30
- private async okOrThrow(res: Response, action: string) {
31
- if (!res.ok) {
32
- let detail = "";
33
- try { detail = await res.text(); } catch {}
34
- throw new Error(\`\${action} ${table.name} failed: \${res.status} \${detail}\`);
35
- }
36
- }
37
-
38
- async create(data: Insert${Type}): Promise<Select${Type}> {
39
- const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}\`, {
40
- method: "POST",
41
- headers: await this.headers(true),
42
- body: JSON.stringify(data),
43
- });
44
- await this.okOrThrow(res, "create");
45
- return (await res.json()) as Select${Type};
46
- }
47
-
48
- async getByPk(pk: ${pkType}): Promise<Select${Type} | null> {
49
- const path = ${pkPathExpr};
50
- const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}/\${path}\`, {
51
- headers: await this.headers(),
52
- });
53
- if (res.status === 404) return null;
54
- await this.okOrThrow(res, "get");
55
- return (await res.json()) as Select${Type};
56
- }
57
-
58
- async list(params?: { include?: ${Type}IncludeSpec; limit?: number; offset?: number }): Promise<Select${Type}[]> {
59
- const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}/list\`, {
60
- method: "POST",
61
- headers: await this.headers(true),
62
- body: JSON.stringify(params ?? {}),
63
- });
64
- await this.okOrThrow(res, "list");
65
- return (await res.json()) as Select${Type}[];
66
- }
67
-
68
- async update(pk: ${pkType}, patch: Update${Type}): Promise<Select${Type} | null> {
69
- const path = ${pkPathExpr};
70
- const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}/\${path}\`, {
71
- method: "PATCH",
72
- headers: await this.headers(true),
73
- body: JSON.stringify(patch),
74
- });
75
- if (res.status === 404) return null;
76
- await this.okOrThrow(res, "update");
77
- return (await res.json()) as Select${Type};
78
- }
79
-
80
- async delete(pk: ${pkType}): Promise<Select${Type} | null> {
81
- const path = ${pkPathExpr};
82
- const res = await this.fetchFn(\`\${this.baseUrl}/v1/${table.name}/\${path}\`, {
83
- method: "DELETE",
84
- headers: await this.headers(),
85
- });
86
- if (res.status === 404) return null;
87
- await this.okOrThrow(res, "delete");
88
- return (await res.json()) as Select${Type};
89
- }
90
- }
91
- `;
92
- }
93
- export function emitClientIndex(tables) {
94
- let out = `/* Generated. Do not edit. */\n`;
95
- for (const t of tables) {
96
- out += `import { ${pascal(t.name)}Client } from "./${t.name}";\n`;
97
- }
98
- out += `\nexport class SDK {\n`;
99
- for (const t of tables) {
100
- out += ` public ${t.name}: ${pascal(t.name)}Client;\n`;
101
- }
102
- out += `\n constructor(cfg: { baseUrl: string; fetch?: typeof fetch; auth?: () => Promise<Record<string,string>> }) {\n`;
103
- out += ` const f = cfg.fetch ?? fetch;\n`;
104
- for (const t of tables) {
105
- out += ` this.${t.name} = new ${pascal(t.name)}Client(cfg.baseUrl, f, cfg.auth);\n`;
106
- }
107
- out += ` }\n`;
108
- out += `}\n`;
109
- for (const t of tables)
110
- out += `export { ${pascal(t.name)}Client } from "./${t.name}";\n`;
111
- out += `export * from "./include-spec";\n`;
112
- return out;
113
- }
114
- //# sourceMappingURL=emit-client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-client.js","sourceRoot":"","sources":["../src/emit-client.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-include-builder.d.ts","sourceRoot":"","sources":["../src/emit-include-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UA4BhE"}
@@ -1,30 +0,0 @@
1
- export function emitIncludeBuilder(graph, maxDepth) {
2
- return `// Generated. Do not edit.
3
- export const RELATION_GRAPH = ${JSON.stringify(graph, null, 2)} as const;
4
- type TableName = keyof typeof RELATION_GRAPH;
5
-
6
- export function buildWith(root: TableName, spec: any, maxDepth = ${maxDepth}) {
7
- return walk(root as string, spec, 0);
8
- function walk(table: string, s: any, depth: number): any {
9
- if (!s || depth >= maxDepth) return undefined;
10
- const rels: any = (RELATION_GRAPH as any)[table] || {};
11
- const out: any = {};
12
- for (const key of Object.keys(s)) {
13
- const rel = rels[key];
14
- if (!rel) throw new Error(\`Unknown include key '\${key}' on table '\${table}'\`);
15
- const v = s[key];
16
- if (v === true) out[key] = true;
17
- else if (v && typeof v === "object") {
18
- const child = "include" in v ? walk(rel.target, v.include, depth + 1) : undefined;
19
- out[key] = child ? { with: child } : true;
20
- }
21
- }
22
- return Object.keys(out).length ? out : undefined;
23
- }
24
- }
25
-
26
- export const buildWithFor = (t: TableName) =>
27
- (spec?: any, depth = ${maxDepth}) => (spec ? buildWith(t, spec, depth) : undefined);
28
- `;
29
- }
30
- //# sourceMappingURL=emit-include-builder.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-include-builder.js","sourceRoot":"","sources":["../src/emit-include-builder.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAAC,KAAY,EAAE,QAAgB;IAC/D,OAAO;gCACuB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;;;mEAGK,QAAQ;;;;;;;;;;;;;;;;;;;;;yBAqBlD,QAAQ;CAChC,CAAC;AACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-include-loader.d.ts","sourceRoot":"","sources":["../src/emit-include-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,UAgT7E"}
@@ -1,299 +0,0 @@
1
- /**
2
- * Emit a generic include loader that:
3
- * - Walks the include spec
4
- * - Loads children in batches per edge kind
5
- * - Stitches onto parent rows (mutates copies)
6
- */
7
- export function emitIncludeLoader(graph, model, maxDepth) {
8
- // Precompute helpful maps for FK discovery
9
- const fkIndex = {};
10
- for (const t of Object.values(model.tables)) {
11
- fkIndex[t.name] = t.fks.map((f) => ({ from: f.from, toTable: f.toTable, to: f.to }));
12
- }
13
- return `/* Generated. Do not edit. */
14
- import { RELATION_GRAPH } from "./include-builder";
15
-
16
- // Minimal types to keep the file self-contained
17
- type Graph = typeof RELATION_GRAPH;
18
- type TableName = keyof Graph;
19
- type IncludeSpec = any;
20
-
21
- // Debug helpers (enabled with SDK_DEBUG=1)
22
- const DEBUG = process.env.SDK_DEBUG === "1" || process.env.SDK_DEBUG === "true";
23
- const log = {
24
- debug: (...args: any[]) => { if (DEBUG) console.debug("[sdk:include]", ...args); },
25
- warn: (...args: any[]) => console.warn("[sdk:include]", ...args),
26
- error: (...args: any[]) => console.error("[sdk:include]", ...args),
27
- };
28
-
29
- // Helpers for PK/FK discovery from model (inlined)
30
- const FK_INDEX = ${JSON.stringify(fkIndex, null, 2)} as const;
31
- const PKS = ${JSON.stringify(Object.fromEntries(Object.values(model.tables).map((t) => [t.name, t.pk])), null, 2)} as const;
32
-
33
- // Build WHERE predicate for OR-of-AND on composite values
34
- function buildOrAndPredicate(cols: string[], count: number, startIndex: number) {
35
- // Generates: (c1=$i AND c2=$i+1) OR (c1=$j AND c2=$j+1) ...
36
- const groups: string[] = [];
37
- let idx = startIndex;
38
- for (let k = 0; k < count; k++) {
39
- const parts = cols.map((c, j) => \`"\${c}" = $\${idx + j}\`);
40
- groups.push('(' + parts.join(' AND ') + ')');
41
- idx += cols.length;
42
- }
43
- return groups.join(' OR ');
44
- }
45
-
46
- // Extract distinct tuples from rows
47
- function distinctTuples(rows: any[], cols: string[]): any[] {
48
- const s = new Set<string>();
49
- const res: any[] = [];
50
- for (const r of rows) {
51
- const tup = cols.map(c => r[c]);
52
- const key = JSON.stringify(tup);
53
- if (!s.has(key)) {
54
- s.add(key);
55
- res.push(tup);
56
- }
57
- }
58
- return res;
59
- }
60
-
61
- // Index rows by tuple key
62
- function indexByTuple(rows: any[], cols: string[]) {
63
- const map = new Map<string, any>();
64
- for (const r of rows) {
65
- const key = JSON.stringify(cols.map(c => r[c]));
66
- map.set(key, r);
67
- }
68
- return map;
69
- }
70
-
71
- // Group rows by tuple key (1:N)
72
- function groupByTuple(rows: any[], cols: string[]) {
73
- const map = new Map<string, any[]>();
74
- for (const r of rows) {
75
- const key = JSON.stringify(cols.map(c => r[c]));
76
- const arr = map.get(key) ?? [];
77
- arr.push(r);
78
- map.set(key, arr);
79
- }
80
- return map;
81
- }
82
-
83
- // Public entry
84
- export async function loadIncludes(
85
- root: TableName,
86
- parents: any[],
87
- spec: IncludeSpec | undefined,
88
- pg: { query: (text: string, params?: any[]) => Promise<{ rows: any[] }> },
89
- maxDepth: number = ${maxDepth}
90
- ) {
91
- try {
92
- if (!spec || !parents.length) return parents;
93
- log.debug("loadIncludes root/spec/rows", root, Object.keys(spec ?? {}).length, parents.length);
94
-
95
- // Deep clone parents to avoid mutating caller refs
96
- const cloned = parents.map(p => ({ ...p }));
97
- await walk(root, cloned, spec, 0);
98
- return cloned;
99
- } catch (e: any) {
100
- log.error("loadIncludes error:", e?.message ?? e, e?.stack);
101
- // Never throw to the route; return base rows
102
- return parents;
103
- }
104
-
105
- async function walk(table: TableName, rows: any[], s: any, depth: number): Promise<void> {
106
- if (!s || depth >= maxDepth || rows.length === 0) return;
107
- const rels: any = (RELATION_GRAPH as any)[table] || {};
108
- log.debug("walk", { table, depth, keys: Object.keys(s) });
109
-
110
- // Process each requested relation at this level
111
- for (const key of Object.keys(s)) {
112
- const rel = rels[key];
113
- if (!rel) {
114
- log.warn(\`Unknown include key '\${key}' on '\${table}' — skipping\`);
115
- continue;
116
- }
117
- const target = rel.target as TableName;
118
-
119
- // Safely run each loader; never let one bad edge 500 the route
120
- if (rel.via) {
121
- // M:N via junction
122
- try {
123
- await loadManyToMany(table, target, rel.via as string, rows, key);
124
- } catch (e: any) {
125
- log.error("loadManyToMany failed", { table, key, via: rel.via, target }, e?.message ?? e);
126
- for (const r of rows) r[key] = [];
127
- }
128
- // Recurse if nested include specified
129
- const childSpec = s[key] && typeof s[key] === "object" ? (s[key] as any).include : undefined;
130
- if (childSpec) {
131
- const children = rows.flatMap(r => (r[key] ?? []));
132
- try {
133
- await walk(target, children, childSpec, depth + 1);
134
- } catch (e: any) {
135
- log.error("walk nested (via) failed", { table: String(target), key }, e?.message ?? e);
136
- }
137
- }
138
- continue;
139
- }
140
-
141
- if (rel.kind === "many") {
142
- // 1:N target has FK to current
143
- try {
144
- await loadOneToMany(table, target, rows, key);
145
- } catch (e: any) {
146
- log.error("loadOneToMany failed", { table, key, target }, e?.message ?? e);
147
- for (const r of rows) r[key] = [];
148
- }
149
- const childSpec = s[key] && typeof s[key] === "object" ? (s[key] as any).include : undefined;
150
- if (childSpec) {
151
- const children = rows.flatMap(r => (r[key] ?? []));
152
- try {
153
- await walk(target, children, childSpec, depth + 1);
154
- } catch (e: any) {
155
- log.error("walk nested (many) failed", { table: String(target), key }, e?.message ?? e);
156
- }
157
- }
158
- } else {
159
- // kind === "one"
160
- // Could be belongs-to (current has FK to target) OR has-one (target unique-FK to current)
161
- const currFks = (FK_INDEX as any)[table] as Array<{from:string[];toTable:string;to:string[]}>;
162
- const toTarget = currFks.find(f => f.toTable === target);
163
- if (toTarget) {
164
- try {
165
- await loadBelongsTo(table, target, rows, key);
166
- } catch (e: any) {
167
- log.error("loadBelongsTo failed", { table, key, target }, e?.message ?? e);
168
- for (const r of rows) r[key] = null;
169
- }
170
- } else {
171
- try {
172
- await loadHasOne(table, target, rows, key);
173
- } catch (e: any) {
174
- log.error("loadHasOne failed", { table, key, target }, e?.message ?? e);
175
- for (const r of rows) r[key] = null;
176
- }
177
- }
178
- const childSpec = s[key] && typeof s[key] === "object" ? (s[key] as any).include : undefined;
179
- if (childSpec) {
180
- const children = rows.map(r => r[key]).filter(Boolean);
181
- try {
182
- await walk(target, children, childSpec, depth + 1);
183
- } catch (e: any) {
184
- log.error("walk nested (one) failed", { table: String(target), key }, e?.message ?? e);
185
- }
186
- }
187
- }
188
- }
189
- }
190
-
191
- async function loadBelongsTo(curr: TableName, target: TableName, rows: any[], key: string) {
192
- // current has FK cols referencing target PK
193
- const fk = (FK_INDEX as any)[curr].find((f: any) => f.toTable === target);
194
- if (!fk) { for (const r of rows) r[key] = null; return; }
195
- const tuples = distinctTuples(rows, fk.from).filter(t => t.every((v: any) => v != null));
196
- if (!tuples.length) { for (const r of rows) r[key] = null; return; }
197
-
198
- // Query target WHERE target.pk IN tuples
199
- const pkCols = (PKS as any)[target] as string[];
200
- const where = buildOrAndPredicate(pkCols, tuples.length, 1);
201
- const params = tuples.flat();
202
- const sql = \`SELECT * FROM "\${target}" WHERE \${where}\`;
203
- log.debug("belongsTo SQL", { curr, target, key, sql, paramsCount: params.length });
204
- const { rows: targets } = await pg.query(sql, params);
205
-
206
- const idx = indexByTuple(targets, pkCols);
207
- for (const r of rows) {
208
- const tup = fk.from.map((c: string) => r[c]);
209
- const keyStr = JSON.stringify(tup);
210
- r[key] = idx.get(keyStr) ?? null;
211
- }
212
- }
213
-
214
- async function loadHasOne(curr: TableName, target: TableName, rows: any[], key: string) {
215
- // target has FK cols referencing current PK (unique)
216
- const fk = (FK_INDEX as any)[target].find((f: any) => f.toTable === curr);
217
- if (!fk) { for (const r of rows) r[key] = null; return; }
218
-
219
- const pkCols = (PKS as any)[curr] as string[];
220
- const tuples = distinctTuples(rows, pkCols).filter(t => t.every((v: any) => v != null));
221
- if (!tuples.length) { for (const r of rows) r[key] = null; return; }
222
-
223
- // SELECT target WHERE fk IN tuples
224
- const where = buildOrAndPredicate(fk.from, tuples.length, 1);
225
- const params = tuples.flat();
226
- const sql = \`SELECT * FROM "\${target}" WHERE \${where}\`;
227
- log.debug("hasOne SQL", { curr, target, key, sql, paramsCount: params.length });
228
- const { rows: targets } = await pg.query(sql, params);
229
-
230
- const idx = indexByTuple(targets, fk.from);
231
- for (const r of rows) {
232
- const keyStr = JSON.stringify(pkCols.map((c: string) => r[c]));
233
- r[key] = idx.get(keyStr) ?? null;
234
- }
235
- }
236
-
237
- async function loadOneToMany(curr: TableName, target: TableName, rows: any[], key: string) {
238
- // target has FK cols referencing current PK
239
- const fk = (FK_INDEX as any)[target].find((f: any) => f.toTable === curr);
240
- if (!fk) { for (const r of rows) r[key] = []; return; }
241
-
242
- const pkCols = (PKS as any)[curr] as string[];
243
- const tuples = distinctTuples(rows, pkCols).filter(t => t.every((v: any) => v != null));
244
- if (!tuples.length) { for (const r of rows) r[key] = []; return; }
245
-
246
- const where = buildOrAndPredicate(fk.from, tuples.length, 1);
247
- const params = tuples.flat();
248
- const sql = \`SELECT * FROM "\${target}" WHERE \${where}\`;
249
- log.debug("oneToMany SQL", { curr, target, key, sql, paramsCount: params.length });
250
- const { rows: children } = await pg.query(sql, params);
251
-
252
- const groups = groupByTuple(children, fk.from);
253
- for (const r of rows) {
254
- const keyStr = JSON.stringify(pkCols.map((c: string) => r[c]));
255
- r[key] = groups.get(keyStr) ?? [];
256
- }
257
- }
258
-
259
- async function loadManyToMany(curr: TableName, target: TableName, via: string, rows: any[], key: string) {
260
- // via has two FKs: one to curr, one to target
261
- const toCurr = (FK_INDEX as any)[via].find((f: any) => f.toTable === curr);
262
- const toTarget = (FK_INDEX as any)[via].find((f: any) => f.toTable === target);
263
- if (!toCurr || !toTarget) { for (const r of rows) r[key] = []; return; }
264
-
265
- const pkCols = (PKS as any)[curr] as string[];
266
- const tuples = distinctTuples(rows, pkCols).filter(t => t.every((v: any) => v != null));
267
- if (!tuples.length) { for (const r of rows) r[key] = []; return; }
268
-
269
- // 1) Load junction rows for current parents
270
- const whereVia = buildOrAndPredicate(toCurr.from, tuples.length, 1);
271
- const sqlVia = \`SELECT * FROM "\${via}" WHERE \${whereVia}\`;
272
- const paramsVia = tuples.flat();
273
- log.debug("manyToMany junction SQL", { curr, target, via, key, sql: sqlVia, paramsCount: paramsVia.length });
274
- const { rows: jrows } = await pg.query(sqlVia, paramsVia);
275
-
276
- if (!jrows.length) { for (const r of rows) r[key] = []; return; }
277
-
278
- // 2) Load targets by distinct target fk tuples in junction
279
- const tTuples = distinctTuples(jrows, toTarget.from);
280
- const whereT = buildOrAndPredicate((PKS as any)[target], tTuples.length, 1);
281
- const sqlT = \`SELECT * FROM "\${target}" WHERE \${whereT}\`;
282
- const paramsT = tTuples.flat();
283
- log.debug("manyToMany target SQL", { curr, target, via, key, sql: sqlT, paramsCount: paramsT.length });
284
- const { rows: targets } = await pg.query(sqlT, paramsT);
285
-
286
- const tIdx = indexByTuple(targets, (PKS as any)[target]);
287
-
288
- // 3) Group junction rows by current pk tuple, map to target rows
289
- const byCurr = groupByTuple(jrows, toCurr.from);
290
- for (const r of rows) {
291
- const currKey = JSON.stringify(pkCols.map((c: string) => r[c]));
292
- const j = byCurr.get(currKey) ?? [];
293
- r[key] = j.map(jr => tIdx.get(JSON.stringify(toTarget.from.map((c: string) => jr[c])))).filter(Boolean);
294
- }
295
- }
296
- }
297
- `;
298
- }
299
- //# sourceMappingURL=emit-include-loader.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-include-loader.js","sourceRoot":"","sources":["../src/emit-include-loader.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAY,EAAE,KAAY,EAAE,QAAgB;IAC5E,2CAA2C;IAC3C,MAAM,OAAO,GAQT,EAAE,CAAC;IACP,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACvF,CAAC;IAED,OAAO;;;;;;;;;;;;;;;;;mBAiBU,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;cACrC,IAAI,CAAC,SAAS,CACxB,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAC1E,IAAI,EACJ,CAAC,CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBA0DoB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgN9B,CAAC;AACF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-include-spec.d.ts","sourceRoot":"","sources":["../src/emit-include-spec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,UAsB3C"}
@@ -1,26 +0,0 @@
1
- export function emitIncludeSpec(graph) {
2
- let out = `/* Generated. Do not edit. */\n`;
3
- const tables = Object.keys(graph);
4
- for (const table of tables) {
5
- const rels = graph[table] ?? {};
6
- const entries = Object.entries(rels);
7
- out += `export type ${toPascal(table)}IncludeSpec = {\n`;
8
- for (const [relKey, edge] of entries) {
9
- if (edge.kind === "many") {
10
- out += ` ${relKey}?: boolean | { include?: ${toPascal(edge.target)}IncludeSpec; limit?: number; offset?: number; };\n`;
11
- }
12
- else {
13
- out += ` ${relKey}?: boolean | ${toPascal(edge.target)}IncludeSpec;\n`;
14
- }
15
- }
16
- out += `};\n\n`;
17
- }
18
- return out;
19
- }
20
- function toPascal(s) {
21
- return s
22
- .split(/[_\s-]+/)
23
- .map((w) => (w?.[0] ? w[0].toUpperCase() + w.slice(1) : ""))
24
- .join("");
25
- }
26
- //# sourceMappingURL=emit-include-spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-include-spec.js","sourceRoot":"","sources":["../src/emit-include-spec.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,eAAe,CAAC,KAAY;IAC1C,IAAI,GAAG,GAAG,iCAAiC,CAAC;IAE5C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAErC,GAAG,IAAI,eAAe,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC;QACzD,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzB,GAAG,IAAI,KAAK,MAAM,4BAA4B,QAAQ,CACpD,IAAI,CAAC,MAAM,CACZ,oDAAoD,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,GAAG,IAAI,KAAK,MAAM,gBAAgB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC;YAC1E,CAAC;QACH,CAAC;QACD,GAAG,IAAI,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC;SACL,KAAK,CAAC,SAAS,CAAC;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAC3D,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit-logger.d.ts","sourceRoot":"","sources":["../src/emit-logger.ts"],"names":[],"mappings":"AACA,wBAAgB,UAAU,WAgCzB"}