@kozou/api 0.0.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,260 @@
1
+ // OpenAPI 3.1 document generation from a SchemaContext (Kozou v0.2 spec
2
+ // §3.2). The differentiator over a generic auto-API is that COMMENT-derived
3
+ // metadata is baked into the document: table/view/column descriptions, the
4
+ // `@ai:` notes (as `x-kozou-ai`), `@policy:` rules (as `x-kozou-policy`),
5
+ // CHECK / ENUM members (as `enum`), and the resolved widget (as
6
+ // `x-kozou-widget`).
7
+ //
8
+ // `@policy:` rules are advisory metadata for AI agents and clients; they are
9
+ // not enforced here. Hard access control is the schema author's Postgres
10
+ // row-level security (see auth.ts).
11
+ //
12
+ // Pure function — no I/O. The server builds the document once at start and
13
+ // serves it at `GET /openapi.json`.
14
+ export function buildOpenApiDocument(schema, opts = {}) {
15
+ const resources = [
16
+ ...schema.tables.map((t) => ({ resource: t, writable: true })),
17
+ ...schema.views.map((v) => ({ resource: v, writable: false })),
18
+ ];
19
+ // Use the bare name as the URL segment when it is unique across schemas,
20
+ // otherwise the qualified name — mirroring the request resolver.
21
+ const nameCounts = new Map();
22
+ for (const { resource } of resources) {
23
+ nameCounts.set(resource.name, (nameCounts.get(resource.name) ?? 0) + 1);
24
+ }
25
+ const segmentFor = (r) => nameCounts.get(r.name) === 1 ? r.name : r.qualifiedName;
26
+ const knownQNames = new Set(resources.map(({ resource }) => resource.qualifiedName));
27
+ // Reverse index for one-to-many embed hints: parent qualifiedName -> children.
28
+ const reverseByParent = new Map();
29
+ for (const t of schema.tables) {
30
+ for (const rel of t.relations ?? []) {
31
+ const parentQN = `${rel.references.schema}.${rel.references.table}`;
32
+ const entry = { childName: t.name, childQN: t.qualifiedName, field: rel.field };
33
+ const list = reverseByParent.get(parentQN);
34
+ if (list)
35
+ list.push(entry);
36
+ else
37
+ reverseByParent.set(parentQN, [entry]);
38
+ }
39
+ }
40
+ const paths = {};
41
+ const schemas = {};
42
+ for (const { resource, writable } of resources) {
43
+ const ref = `#/components/schemas/${resource.qualifiedName}`;
44
+ const relations = 'relations' in resource ? resource.relations : [];
45
+ const reverse = reverseByParent.get(resource.qualifiedName) ?? [];
46
+ schemas[resource.qualifiedName] = resourceSchema(resource, relations, reverse, knownQNames);
47
+ Object.assign(paths, resourcePaths(resource, segmentFor(resource), ref, writable));
48
+ }
49
+ return {
50
+ openapi: '3.1.0',
51
+ info: {
52
+ title: opts.title ?? 'Kozou API',
53
+ version: opts.version ?? '0.0.0',
54
+ description: 'REST API generated by Kozou from PostgreSQL DDL + COMMENT. Descriptions, enums, and AI notes below are sourced from the database COMMENTs.',
55
+ },
56
+ paths,
57
+ components: { schemas },
58
+ };
59
+ }
60
+ function resourceSchema(resource, relations, reverse, knownQNames) {
61
+ const properties = {};
62
+ const required = [];
63
+ for (const column of resource.columns) {
64
+ properties[column.name] = columnSchema(column);
65
+ if (!column.nullable)
66
+ required.push(column.name);
67
+ }
68
+ const schema = { type: 'object', properties };
69
+ if (resource.description)
70
+ schema.description = resource.description;
71
+ if (resource.aiDescription)
72
+ schema['x-kozou-ai'] = resource.aiDescription;
73
+ if (resource.policy && resource.policy.length > 0)
74
+ schema['x-kozou-policy'] = resource.policy;
75
+ if (required.length > 0)
76
+ schema.required = required;
77
+ // Embeddable relations, as a hint for clients building `?embed=`: forward
78
+ // (to-one) plus reverse (to-many). Only targets that are themselves exposed
79
+ // resources are listed.
80
+ const embeds = embedHints(relations, reverse, knownQNames);
81
+ if (embeds.length > 0)
82
+ schema['x-kozou-embeds'] = embeds;
83
+ return schema;
84
+ }
85
+ function embedHints(forward, reverse, knownQNames) {
86
+ const hints = [];
87
+ for (const r of forward) {
88
+ const qn = `${r.references.schema}.${r.references.table}`;
89
+ if (!knownQNames.has(qn))
90
+ continue;
91
+ hints.push({
92
+ field: r.field,
93
+ key: r.references.table,
94
+ target: `#/components/schemas/${qn}`,
95
+ cardinality: 'to-one',
96
+ });
97
+ }
98
+ for (const e of reverse) {
99
+ if (!knownQNames.has(e.childQN))
100
+ continue;
101
+ hints.push({
102
+ field: e.field,
103
+ key: e.childName,
104
+ target: `#/components/schemas/${e.childQN}`,
105
+ cardinality: 'to-many',
106
+ });
107
+ }
108
+ return hints;
109
+ }
110
+ function columnSchema(column) {
111
+ const base = widgetType(column.widget);
112
+ const schema = { ...base };
113
+ if (column.nullable && typeof schema.type === 'string') {
114
+ schema.type = [schema.type, 'null'];
115
+ }
116
+ if (column.enumValues && column.enumValues.length > 0) {
117
+ schema.enum = column.nullable ? [...column.enumValues, null] : [...column.enumValues];
118
+ }
119
+ if (column.description)
120
+ schema.description = column.description;
121
+ if (column.aiDescription)
122
+ schema['x-kozou-ai'] = column.aiDescription;
123
+ if (column.policy && column.policy.length > 0)
124
+ schema['x-kozou-policy'] = column.policy;
125
+ schema['x-kozou-widget'] = column.widget;
126
+ return schema;
127
+ }
128
+ function widgetType(widget) {
129
+ switch (widget) {
130
+ case 'number':
131
+ case 'currency':
132
+ return { type: 'number' };
133
+ case 'boolean':
134
+ return { type: 'boolean' };
135
+ case 'date':
136
+ return { type: 'string', format: 'date' };
137
+ case 'datetime':
138
+ return { type: 'string', format: 'date-time' };
139
+ case 'uuid':
140
+ return { type: 'string', format: 'uuid' };
141
+ case 'image-url':
142
+ return { type: 'string', format: 'uri' };
143
+ case 'json':
144
+ return { type: 'object' };
145
+ case 'text':
146
+ case 'textarea':
147
+ case 'enum-select':
148
+ case 'relation-select':
149
+ default:
150
+ return { type: 'string' };
151
+ }
152
+ }
153
+ function resourcePaths(resource, segment, ref, writable) {
154
+ const rowRef = { $ref: ref };
155
+ const label = resource.label || resource.name;
156
+ const collection = {
157
+ get: {
158
+ summary: `List ${label}`,
159
+ description: resource.description ?? undefined,
160
+ parameters: [...listParameters(), embedParam()],
161
+ responses: {
162
+ '200': jsonResponse(`A page of ${label}.`, listResultSchema(rowRef)),
163
+ },
164
+ },
165
+ };
166
+ if (writable) {
167
+ collection.post = {
168
+ summary: `Create a ${label} row`,
169
+ requestBody: jsonBody(rowRef),
170
+ responses: {
171
+ '201': jsonResponse('The created row.', rowRef),
172
+ '400': errorResponse('Validation error.'),
173
+ },
174
+ };
175
+ }
176
+ const idParam = {
177
+ name: 'id',
178
+ in: 'path',
179
+ required: true,
180
+ schema: { type: 'string' },
181
+ description: 'Primary key of the row.',
182
+ };
183
+ const item = {
184
+ get: {
185
+ summary: `Fetch a ${label} row by id`,
186
+ parameters: [idParam, embedParam()],
187
+ responses: {
188
+ '200': jsonResponse('The row.', rowRef),
189
+ '404': errorResponse('No such row.'),
190
+ },
191
+ },
192
+ };
193
+ if (writable) {
194
+ item.patch = {
195
+ summary: `Update a ${label} row`,
196
+ parameters: [idParam],
197
+ requestBody: jsonBody(rowRef),
198
+ responses: {
199
+ '200': jsonResponse('The updated row.', rowRef),
200
+ '404': errorResponse('No such row.'),
201
+ },
202
+ };
203
+ item.delete = {
204
+ summary: `Delete a ${label} row`,
205
+ parameters: [idParam],
206
+ responses: {
207
+ '200': jsonResponse('The deleted row.', rowRef),
208
+ '404': errorResponse('No such row.'),
209
+ },
210
+ };
211
+ }
212
+ return {
213
+ [`/${segment}`]: collection,
214
+ [`/${segment}/{id}`]: item,
215
+ };
216
+ }
217
+ function listParameters() {
218
+ return [
219
+ queryParam('page', { type: 'integer', minimum: 1 }, '1-based page index.'),
220
+ queryParam('pageSize', { type: 'integer', minimum: 1 }, 'Rows per page.'),
221
+ queryParam('sort', { type: 'string' }, 'Comma-separated `field.asc` / `field.desc`.'),
222
+ queryParam('search', { type: 'string' }, 'Free-text ILIKE across text columns.'),
223
+ ];
224
+ }
225
+ function queryParam(name, schema, description) {
226
+ return { name, in: 'query', required: false, schema, description };
227
+ }
228
+ function embedParam() {
229
+ return queryParam('embed', { type: 'string' }, 'Comma-separated forward to-one relations to inline as nested objects; dot for depth (e.g. "author,editions.books.authors"). Each segment is a foreign-key column name or its referenced table name.');
230
+ }
231
+ function listResultSchema(rowRef) {
232
+ return {
233
+ type: 'object',
234
+ properties: {
235
+ rows: { type: 'array', items: rowRef },
236
+ total: { type: 'integer' },
237
+ page: { type: 'integer' },
238
+ pageSize: { type: 'integer' },
239
+ },
240
+ required: ['rows', 'total', 'page', 'pageSize'],
241
+ };
242
+ }
243
+ function jsonResponse(description, schema) {
244
+ return { description, content: { 'application/json': { schema } } };
245
+ }
246
+ function jsonBody(schema) {
247
+ return { required: true, content: { 'application/json': { schema } } };
248
+ }
249
+ function errorResponse(description) {
250
+ return jsonResponse(description, {
251
+ type: 'object',
252
+ properties: {
253
+ error: {
254
+ type: 'object',
255
+ properties: { code: { type: 'string' }, message: { type: 'string' } },
256
+ },
257
+ },
258
+ });
259
+ }
260
+ //# sourceMappingURL=openapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { quoteIdent } from './ident.js';
2
+ import { type EmbedNode } from './embed.js';
3
+ import type { Resource } from './schema-lookup.js';
4
+ export { quoteIdent };
5
+ export declare const DEFAULT_PAGE_SIZE = 50;
6
+ export declare const MAX_PAGE_SIZE = 200;
7
+ export type SortDirection = 'asc' | 'desc';
8
+ export type ListQueryParams = {
9
+ page?: number;
10
+ pageSize?: number;
11
+ sort?: {
12
+ field: string;
13
+ order: SortDirection;
14
+ }[];
15
+ search?: string;
16
+ /** Column-equality filters. Keys must be declared columns of the resource. */
17
+ filters?: Record<string, string>;
18
+ /** Resolved forward to-one relations to inline as nested JSON objects. */
19
+ embed?: EmbedNode[];
20
+ };
21
+ export type BuiltListQuery = {
22
+ dataText: string;
23
+ dataValues: unknown[];
24
+ countText: string;
25
+ countValues: unknown[];
26
+ /** Effective (clamped) pagination echoed back in the response. */
27
+ page: number;
28
+ pageSize: number;
29
+ };
30
+ export type BuiltGetQuery = {
31
+ text: string;
32
+ values: unknown[];
33
+ };
34
+ export declare function buildListQuery(resource: Resource, params: ListQueryParams): BuiltListQuery;
35
+ export declare function buildGetQuery(resource: Resource, id: string, embed?: EmbedNode[]): BuiltGetQuery;
36
+ export type BuiltMutation = {
37
+ text: string;
38
+ values: unknown[];
39
+ };
40
+ export declare const DEFAULT_RELATION_LIMIT = 20;
41
+ export declare const MAX_RELATION_LIMIT = 100;
42
+ export type RelationOptionsParams = {
43
+ labelField: string;
44
+ searchFields: string[];
45
+ query?: string;
46
+ limit?: number;
47
+ };
48
+ export type BuiltRelationOptions = {
49
+ text: string;
50
+ values: unknown[];
51
+ primaryKey: string;
52
+ labelField: string;
53
+ };
54
+ export declare function buildInsertQuery(resource: Resource, data: Record<string, unknown>): BuiltMutation;
55
+ export declare function buildUpdateQuery(resource: Resource, id: string, data: Record<string, unknown>): BuiltMutation;
56
+ export declare function buildDeleteQuery(resource: Resource, id: string): BuiltMutation;
57
+ /** Lightweight `{ id, label }` lookup used by relation-select widgets. */
58
+ export declare function buildRelationOptionsQuery(resource: Resource, params: RelationOptionsParams): BuiltRelationOptions;
59
+ //# sourceMappingURL=query-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-builder.d.ts","sourceRoot":"","sources":["../src/query-builder.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAa,MAAM,YAAY,CAAC;AACnD,OAAO,EAA4B,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAC;AAE3C,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,EAAE,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,EAAE,CAAC;IACvB,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AA4BF,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,eAAe,GACtB,cAAc,CA2EhB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,EAClB,EAAE,EAAE,MAAM,EACV,KAAK,CAAC,EAAE,SAAS,EAAE,GAClB,aAAa,CAYf;AAID,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAoBF,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,aAAa,CAmBf;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,aAAa,CAaf;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,aAAa,CAI9E;AAOD,0EAA0E;AAC1E,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,qBAAqB,GAC5B,oBAAoB,CAuBtB"}
@@ -0,0 +1,193 @@
1
+ // Pure SQL builders for the read path. No I/O — given a resolved Resource
2
+ // and structured request params, produce parameterized SQL text + values.
3
+ //
4
+ // Safety contract:
5
+ // - Identifiers (table/column names) only ever come from the resolved
6
+ // Resource's own schema/name/columns, never raw request strings. Any
7
+ // filter/sort key that is not a declared column is rejected with a
8
+ // 400 before it reaches the SQL text.
9
+ // - Every user-supplied value is a bound parameter ($1, $2, ...). No
10
+ // value is interpolated into the SQL string.
11
+ import { badRequest } from './errors.js';
12
+ import { quoteIdent, qualified } from './ident.js';
13
+ import { buildEmbedSelectFragment } from './embed.js';
14
+ export { quoteIdent };
15
+ export const DEFAULT_PAGE_SIZE = 50;
16
+ export const MAX_PAGE_SIZE = 200;
17
+ function selectColumns(resource) {
18
+ if (resource.columns.length === 0)
19
+ return '*';
20
+ return resource.columns.map((c) => quoteIdent(c.name)).join(', ');
21
+ }
22
+ /** Columns that free-text search targets: text-like widgets only. uuid /
23
+ * enum / numeric columns are excluded (an `ILIKE` against them either
24
+ * errors or is meaningless). */
25
+ function searchableColumns(resource) {
26
+ return resource.columns
27
+ .filter((c) => c.widget === 'text' || c.widget === 'textarea')
28
+ .map((c) => c.name);
29
+ }
30
+ function clampPageSize(pageSize) {
31
+ if (pageSize === undefined || !Number.isFinite(pageSize) || pageSize < 1) {
32
+ return DEFAULT_PAGE_SIZE;
33
+ }
34
+ return Math.min(Math.floor(pageSize), MAX_PAGE_SIZE);
35
+ }
36
+ function clampPage(page) {
37
+ if (page === undefined || !Number.isFinite(page) || page < 1)
38
+ return 1;
39
+ return Math.floor(page);
40
+ }
41
+ export function buildListQuery(resource, params) {
42
+ const columnNames = new Set(resource.columns.map((c) => c.name));
43
+ const whereParts = [];
44
+ const whereValues = [];
45
+ const nextParam = () => `$${whereValues.length + 1}`;
46
+ // Column-equality filters.
47
+ for (const [key, value] of Object.entries(params.filters ?? {})) {
48
+ if (!columnNames.has(key)) {
49
+ throw badRequest(`Unknown filter column "${key}" on resource "${resource.name}".`);
50
+ }
51
+ whereParts.push(`${quoteIdent(key)} = ${nextParam()}`);
52
+ whereValues.push(value);
53
+ }
54
+ // Free-text search across text-like columns.
55
+ const search = params.search?.trim();
56
+ if (search !== undefined && search.length > 0) {
57
+ const cols = searchableColumns(resource);
58
+ if (cols.length > 0) {
59
+ const placeholder = nextParam();
60
+ whereValues.push(`%${search}%`);
61
+ const ors = cols.map((c) => `${quoteIdent(c)} ILIKE ${placeholder}`).join(' OR ');
62
+ whereParts.push(`(${ors})`);
63
+ }
64
+ }
65
+ const whereClause = whereParts.length > 0 ? ` WHERE ${whereParts.join(' AND ')}` : '';
66
+ // ORDER BY: explicit sort, else default to the primary key for stable
67
+ // pagination. Views (no PK) fall back to no ordering.
68
+ const orderParts = [];
69
+ if (params.sort && params.sort.length > 0) {
70
+ for (const s of params.sort) {
71
+ if (!columnNames.has(s.field)) {
72
+ throw badRequest(`Unknown sort column "${s.field}" on resource "${resource.name}".`);
73
+ }
74
+ orderParts.push(`${quoteIdent(s.field)} ${s.order === 'desc' ? 'DESC' : 'ASC'}`);
75
+ }
76
+ }
77
+ else {
78
+ for (const pk of resource.primaryKey) {
79
+ orderParts.push(`${quoteIdent(pk)} ASC`);
80
+ }
81
+ }
82
+ const orderClause = orderParts.length > 0 ? ` ORDER BY ${orderParts.join(', ')}` : '';
83
+ const page = clampPage(params.page);
84
+ const pageSize = clampPageSize(params.pageSize);
85
+ const offset = (page - 1) * pageSize;
86
+ const cols = selectColumns(resource);
87
+ const table = qualified(resource);
88
+ // Embeds append correlated subqueries to the SELECT list only — they add no
89
+ // bound parameters, so the $n numbering above is unaffected.
90
+ const embedSql = params.embed && params.embed.length > 0
91
+ ? buildEmbedSelectFragment(params.embed, table, { n: 0 })
92
+ : '';
93
+ const dataValues = [...whereValues, pageSize, offset];
94
+ const limitParam = `$${whereValues.length + 1}`;
95
+ const offsetParam = `$${whereValues.length + 2}`;
96
+ const dataText = `SELECT ${cols}${embedSql} FROM ${table}${whereClause}${orderClause} LIMIT ${limitParam} OFFSET ${offsetParam}`;
97
+ const countText = `SELECT count(*) AS total FROM ${table}${whereClause}`;
98
+ return {
99
+ dataText,
100
+ dataValues,
101
+ countText,
102
+ countValues: [...whereValues],
103
+ page,
104
+ pageSize,
105
+ };
106
+ }
107
+ export function buildGetQuery(resource, id, embed) {
108
+ if (resource.primaryKey.length !== 1) {
109
+ throw badRequest(`Resource "${resource.name}" does not have a single-column primary key; fetch-by-id is unavailable.`);
110
+ }
111
+ const pk = resource.primaryKey[0];
112
+ const table = qualified(resource);
113
+ const embedSql = embed && embed.length > 0 ? buildEmbedSelectFragment(embed, table, { n: 0 }) : '';
114
+ const text = `SELECT ${selectColumns(resource)}${embedSql} FROM ${table} WHERE ${quoteIdent(pk)} = $1 LIMIT 1`;
115
+ return { text, values: [id] };
116
+ }
117
+ export const DEFAULT_RELATION_LIMIT = 20;
118
+ export const MAX_RELATION_LIMIT = 100;
119
+ function singlePrimaryKey(resource) {
120
+ if (resource.primaryKey.length !== 1) {
121
+ throw badRequest(`Resource "${resource.name}" does not have a single-column primary key.`);
122
+ }
123
+ return resource.primaryKey[0];
124
+ }
125
+ function assertKnownColumns(resource, keys) {
126
+ const columnNames = new Set(resource.columns.map((c) => c.name));
127
+ for (const key of keys) {
128
+ if (!columnNames.has(key)) {
129
+ throw badRequest(`Unknown column "${key}" on resource "${resource.name}".`);
130
+ }
131
+ }
132
+ }
133
+ export function buildInsertQuery(resource, data) {
134
+ const keys = Object.keys(data);
135
+ assertKnownColumns(resource, keys);
136
+ const returning = selectColumns(resource);
137
+ const table = qualified(resource);
138
+ // No columns supplied: insert a row of all column defaults.
139
+ if (keys.length === 0) {
140
+ return { text: `INSERT INTO ${table} DEFAULT VALUES RETURNING ${returning}`, values: [] };
141
+ }
142
+ const cols = keys.map(quoteIdent).join(', ');
143
+ const placeholders = keys.map((_, i) => `$${i + 1}`).join(', ');
144
+ const values = keys.map((k) => data[k]);
145
+ return {
146
+ text: `INSERT INTO ${table} (${cols}) VALUES (${placeholders}) RETURNING ${returning}`,
147
+ values,
148
+ };
149
+ }
150
+ export function buildUpdateQuery(resource, id, data) {
151
+ const pk = singlePrimaryKey(resource);
152
+ const keys = Object.keys(data);
153
+ if (keys.length === 0) {
154
+ throw badRequest(`No fields to update on resource "${resource.name}".`);
155
+ }
156
+ assertKnownColumns(resource, keys);
157
+ const sets = keys.map((k, i) => `${quoteIdent(k)} = $${i + 1}`).join(', ');
158
+ const values = keys.map((k) => data[k]);
159
+ values.push(id);
160
+ const text = `UPDATE ${qualified(resource)} SET ${sets} WHERE ${quoteIdent(pk)} = $${values.length} RETURNING ${selectColumns(resource)}`;
161
+ return { text, values };
162
+ }
163
+ export function buildDeleteQuery(resource, id) {
164
+ const pk = singlePrimaryKey(resource);
165
+ const text = `DELETE FROM ${qualified(resource)} WHERE ${quoteIdent(pk)} = $1 RETURNING ${selectColumns(resource)}`;
166
+ return { text, values: [id] };
167
+ }
168
+ function clampRelationLimit(limit) {
169
+ if (limit === undefined || !Number.isFinite(limit) || limit < 1)
170
+ return DEFAULT_RELATION_LIMIT;
171
+ return Math.min(Math.floor(limit), MAX_RELATION_LIMIT);
172
+ }
173
+ /** Lightweight `{ id, label }` lookup used by relation-select widgets. */
174
+ export function buildRelationOptionsQuery(resource, params) {
175
+ const pk = singlePrimaryKey(resource);
176
+ assertKnownColumns(resource, [params.labelField, ...params.searchFields]);
177
+ const values = [];
178
+ let where = '';
179
+ const q = params.query?.trim();
180
+ if (q !== undefined && q.length > 0 && params.searchFields.length > 0) {
181
+ values.push(`%${q}%`);
182
+ const ors = params.searchFields.map((f) => `${quoteIdent(f)} ILIKE $1`).join(' OR ');
183
+ where = ` WHERE (${ors})`;
184
+ }
185
+ values.push(clampRelationLimit(params.limit));
186
+ const limitParam = `$${values.length}`;
187
+ const cols = params.labelField === pk
188
+ ? quoteIdent(pk)
189
+ : `${quoteIdent(pk)}, ${quoteIdent(params.labelField)}`;
190
+ const text = `SELECT ${cols} FROM ${qualified(resource)}${where} LIMIT ${limitParam}`;
191
+ return { text, values, primaryKey: pk, labelField: params.labelField };
192
+ }
193
+ //# sourceMappingURL=query-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-builder.js","sourceRoot":"","sources":["../src/query-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { SchemaContext, ColumnContext, RelationContext } from '@kozou/core';
2
+ export type ResourceKind = 'table' | 'view';
3
+ /** A normalized, query-ready view of a table or a view. */
4
+ export type Resource = {
5
+ kind: ResourceKind;
6
+ schema: string;
7
+ name: string;
8
+ qualifiedName: string;
9
+ columns: ColumnContext[];
10
+ /** Primary-key columns. Empty for views and PK-less tables. */
11
+ primaryKey: string[];
12
+ /** Outgoing forward (to-one / one-to-one) relations. Empty for views. */
13
+ relations: RelationContext[];
14
+ };
15
+ /** A child resource holding a foreign key that points back at some parent —
16
+ * the basis for reverse (one-to-many) embedding. */
17
+ export type ReverseRelation = {
18
+ child: Resource;
19
+ relation: RelationContext;
20
+ };
21
+ export type ResourceLookup = {
22
+ /** Resolve by bare name (when unambiguous) or by `schema.name`. */
23
+ resolve(name: string): Resource | undefined;
24
+ /** Qualified names of every addressable resource, sorted. */
25
+ list(): string[];
26
+ /** Children whose foreign key references the given qualified resource. */
27
+ reverse(qualifiedName: string): ReverseRelation[];
28
+ };
29
+ export declare function buildResourceLookup(schema: SchemaContext): ResourceLookup;
30
+ //# sourceMappingURL=schema-lookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-lookup.d.ts","sourceRoot":"","sources":["../src/schema-lookup.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEjF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5C,2DAA2D;AAC3D,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,yEAAyE;IACzE,SAAS,EAAE,eAAe,EAAE,CAAC;CAC9B,CAAC;AAEF;qDACqD;AACrD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,eAAe,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,mEAAmE;IACnE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC5C,6DAA6D;IAC7D,IAAI,IAAI,MAAM,EAAE,CAAC;IACjB,0EAA0E;IAC1E,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,EAAE,CAAC;CACnD,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,CA0DzE"}
@@ -0,0 +1,61 @@
1
+ // Resolve a request path segment (e.g. "books" or "public.books") to a
2
+ // concrete table or view from the introspected SchemaContext. This map is
3
+ // the allowlist: only resources that exist in the schema are addressable,
4
+ // and only their declared columns can be filtered / sorted on.
5
+ export function buildResourceLookup(schema) {
6
+ const resources = [];
7
+ for (const t of schema.tables) {
8
+ resources.push({
9
+ kind: 'table',
10
+ schema: t.schema,
11
+ name: t.name,
12
+ qualifiedName: t.qualifiedName,
13
+ columns: t.columns,
14
+ primaryKey: t.primaryKey,
15
+ relations: t.relations ?? [],
16
+ });
17
+ }
18
+ for (const v of schema.views) {
19
+ resources.push({
20
+ kind: 'view',
21
+ schema: v.schema,
22
+ name: v.name,
23
+ qualifiedName: v.qualifiedName,
24
+ columns: v.columns,
25
+ primaryKey: [],
26
+ relations: [],
27
+ });
28
+ }
29
+ const byKey = new Map();
30
+ const bareNameCounts = new Map();
31
+ for (const r of resources) {
32
+ byKey.set(r.qualifiedName, r);
33
+ bareNameCounts.set(r.name, (bareNameCounts.get(r.name) ?? 0) + 1);
34
+ }
35
+ // Register the bare name only when it is unique across schemas and does
36
+ // not collide with an existing qualified-name key.
37
+ for (const r of resources) {
38
+ if (bareNameCounts.get(r.name) === 1 && !byKey.has(r.name)) {
39
+ byKey.set(r.name, r);
40
+ }
41
+ }
42
+ const sortedNames = resources.map((r) => r.qualifiedName).sort();
43
+ // Reverse index: parent qualifiedName -> children that reference it.
44
+ const reverseIndex = new Map();
45
+ for (const r of resources) {
46
+ for (const rel of r.relations) {
47
+ const parentKey = `${rel.references.schema}.${rel.references.table}`;
48
+ const list = reverseIndex.get(parentKey);
49
+ if (list)
50
+ list.push({ child: r, relation: rel });
51
+ else
52
+ reverseIndex.set(parentKey, [{ child: r, relation: rel }]);
53
+ }
54
+ }
55
+ return {
56
+ resolve: (name) => byKey.get(name),
57
+ list: () => sortedNames,
58
+ reverse: (qualifiedName) => reverseIndex.get(qualifiedName) ?? [],
59
+ };
60
+ }
61
+ //# sourceMappingURL=schema-lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-lookup.js","sourceRoot":"","sources":["../src/schema-lookup.ts"],"names":[],"mappings":"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"}