@supabase/postgrest-typegen 0.4.0 → 0.5.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/README.md +120 -21
- package/dist/generation/index.d.ts +0 -1
- package/dist/generation/index.js +0 -1
- package/dist/generation/typescript.d.ts +2 -1
- package/dist/generation/typescript.js +70 -288
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/introspection/index.js +3 -1
- package/dist/rpc.d.ts +2 -0
- package/dist/rpc.js +223 -0
- package/dist/sort.js +23 -0
- package/dist/types.d.ts +151 -0
- package/dist/types.js +91 -0
- package/package.json +5 -4
- package/src/generation/index.ts +0 -5
- package/src/generation/typescript.ts +99 -383
- package/src/index.ts +1 -0
- package/src/introspection/index.ts +3 -1
- package/src/rpc.ts +299 -0
- package/src/sort.ts +31 -0
- package/src/types.ts +101 -0
- package/dist/generation/constants.d.ts +0 -9
- package/dist/generation/constants.js +0 -10
- package/dist/generation/swift.d.ts +0 -11
- package/dist/generation/swift.js +0 -358
- package/src/generation/constants.ts +0 -11
- package/src/generation/swift.ts +0 -531
package/dist/rpc.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the PostgREST view of `GeneratorMetadata.functions`.
|
|
3
|
+
*
|
|
4
|
+
* The raw `functions` collection is `pg_proc` as introspected. Which of those
|
|
5
|
+
* functions PostgREST exposes under `/rpc`, how their overloads group, what a
|
|
6
|
+
* call returns and whether a function doubles as a computed field or an
|
|
7
|
+
* embeddable relation are PostgREST rules, not language rules. This pass
|
|
8
|
+
* applies them once so every generator, in this package or in another SDK
|
|
9
|
+
* repo reading the serialized document, emits the same RPC surface.
|
|
10
|
+
*
|
|
11
|
+
* Pure and deterministic: the output is canonically ordered regardless of the
|
|
12
|
+
* order of the input collections. `introspect()` attaches the result as
|
|
13
|
+
* `rpcFunctions`; generators that meet a document without it (produced by a
|
|
14
|
+
* version predating the collection, or by a custom producer) run this pass
|
|
15
|
+
* themselves.
|
|
16
|
+
*/
|
|
17
|
+
import { compareStrings } from "./collation.js";
|
|
18
|
+
/** json, jsonb and text: the types PostgREST accepts for a single unnamed parameter. */
|
|
19
|
+
const UNNAMED_ARG_TYPE_IDS = new Set([114, 3802, 25]);
|
|
20
|
+
const INPUT_ARG_MODES = new Set(["in", "inout", "variadic"]);
|
|
21
|
+
export function resolveRpcFunctions(metadata) {
|
|
22
|
+
const schemaNames = new Set(metadata.schemas.map(({ name }) => name));
|
|
23
|
+
const typesById = new Map(metadata.types.map((type) => [type.id, type]));
|
|
24
|
+
const relationTypesById = new Map(metadata.types
|
|
25
|
+
.filter((type) => type.type_relation_id !== null)
|
|
26
|
+
.map((type) => [type.id, type]));
|
|
27
|
+
const relationsById = new Map([
|
|
28
|
+
...metadata.tables,
|
|
29
|
+
...metadata.foreignTables,
|
|
30
|
+
...metadata.views,
|
|
31
|
+
...metadata.materializedViews,
|
|
32
|
+
].map((relation) => [relation.id, relation]));
|
|
33
|
+
const columnNamesByRelationId = new Map();
|
|
34
|
+
for (const column of metadata.columns) {
|
|
35
|
+
let names = columnNamesByRelationId.get(column.table_id);
|
|
36
|
+
if (!names) {
|
|
37
|
+
names = new Set();
|
|
38
|
+
columnNamesByRelationId.set(column.table_id, names);
|
|
39
|
+
}
|
|
40
|
+
names.add(column.name);
|
|
41
|
+
}
|
|
42
|
+
const typeReference = (typeId) => {
|
|
43
|
+
const type = typesById.get(typeId);
|
|
44
|
+
return {
|
|
45
|
+
type_id: typeId,
|
|
46
|
+
format: type?.name ?? null,
|
|
47
|
+
type_schema: type?.schema ?? null,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const typeName = (typeId) => typesById.get(typeId)?.name ?? "unknown";
|
|
51
|
+
// The relation a return type stands for, or a composite type's name when the
|
|
52
|
+
// return type is one, since both are relations in `pg_class`. Resolved
|
|
53
|
+
// against every schema: a function may return rows of another schema.
|
|
54
|
+
const returnRelationName = (fn) => {
|
|
55
|
+
if (fn.return_type_relation_id === null)
|
|
56
|
+
return null;
|
|
57
|
+
return (relationsById.get(fn.return_type_relation_id)?.name ??
|
|
58
|
+
relationTypesById.get(fn.return_type_id)?.name ??
|
|
59
|
+
null);
|
|
60
|
+
};
|
|
61
|
+
// The function is a computed field of the relation whose row type its sole
|
|
62
|
+
// input parameter has, provided the relation lives in the function's schema
|
|
63
|
+
// and has no column of the function's name: PostgREST resolves the name to
|
|
64
|
+
// the column, so such a function is neither selectable nor part of `Row`.
|
|
65
|
+
// When the parameter's type is not in `types` (a reduced custom document),
|
|
66
|
+
// the rendered argument list may still name the relation.
|
|
67
|
+
const computedFieldOf = ({ fn, inArgs }) => {
|
|
68
|
+
const soleInArg = inArgs.length === 1 ? inArgs[0] : undefined;
|
|
69
|
+
const argType = soleInArg && relationTypesById.get(soleInArg.type_id);
|
|
70
|
+
const relation = argType
|
|
71
|
+
? relationsById.get(argType.type_relation_id)
|
|
72
|
+
: [...relationsById.values()].find((relation) => relation.schema === fn.schema &&
|
|
73
|
+
relation.name === fn.argument_types);
|
|
74
|
+
if (!relation || relation.schema !== fn.schema)
|
|
75
|
+
return null;
|
|
76
|
+
if (columnNamesByRelationId.get(relation.id)?.has(fn.name))
|
|
77
|
+
return null;
|
|
78
|
+
return relation.id;
|
|
79
|
+
};
|
|
80
|
+
const isCallable = ({ inArgs }) => {
|
|
81
|
+
if (inArgs.length === 0)
|
|
82
|
+
return true;
|
|
83
|
+
if (!inArgs.some(({ name }) => name === ""))
|
|
84
|
+
return true;
|
|
85
|
+
if (inArgs.every((arg) => arg.name !== "" ||
|
|
86
|
+
(arg.has_default === true && UNNAMED_ARG_TYPE_IDS.has(arg.type_id)))) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
const soleInArg = inArgs.length === 1 ? inArgs[0] : undefined;
|
|
90
|
+
return (soleInArg !== undefined &&
|
|
91
|
+
soleInArg.name === "" &&
|
|
92
|
+
(UNNAMED_ARG_TYPE_IDS.has(soleInArg.type_id) ||
|
|
93
|
+
relationTypesById.has(soleInArg.type_id)));
|
|
94
|
+
};
|
|
95
|
+
const overloadError = (candidate, group) => {
|
|
96
|
+
const { fn, inArgs } = candidate;
|
|
97
|
+
const soleInArg = inArgs.length === 1 ? inArgs[0] : undefined;
|
|
98
|
+
if (group.length > 1) {
|
|
99
|
+
// A no-argument overload next to one whose sole unnamed parameter has a
|
|
100
|
+
// default: PostgREST cannot pick one for an empty call.
|
|
101
|
+
if (inArgs.length === 0) {
|
|
102
|
+
const conflicting = group.find((other) => other !== candidate &&
|
|
103
|
+
other.inArgs.length === 1 &&
|
|
104
|
+
other.inArgs[0]?.name === "" &&
|
|
105
|
+
other.inArgs[0].has_default === true);
|
|
106
|
+
if (conflicting) {
|
|
107
|
+
return `Could not choose the best candidate function between: ${fn.schema}.${fn.name}(), ${fn.schema}.${fn.name}( => ${typeName(conflicting.fn.return_type_id)}). Try renaming the parameters or the function itself in the database so function overloading can be resolved`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Overloads whose sole parameter shares a name but not a type: a call
|
|
111
|
+
// carries no type information, so PostgREST cannot pick one.
|
|
112
|
+
if (soleInArg && soleInArg.name !== "") {
|
|
113
|
+
const conflicting = group.filter((other) => other !== candidate &&
|
|
114
|
+
other.inArgs.length === 1 &&
|
|
115
|
+
other.inArgs[0]?.name === soleInArg.name &&
|
|
116
|
+
other.inArgs[0].type_id !== soleInArg.type_id);
|
|
117
|
+
if (conflicting.length > 0) {
|
|
118
|
+
const conflictList = [candidate, ...conflicting]
|
|
119
|
+
.sort((a, b) => (a.inArgs[0]?.type_id || 0) - (b.inArgs[0]?.type_id || 0))
|
|
120
|
+
.map((other) => `${fn.schema}.${fn.name}(${other.inArgs
|
|
121
|
+
.map((arg) => `${arg.name} => ${typeName(arg.type_id)}`)
|
|
122
|
+
.join(", ")})`)
|
|
123
|
+
.join(", ");
|
|
124
|
+
return `Could not choose the best candidate function between: ${conflictList}. Try renaming the parameters or the function itself in the database so function overloading can be resolved`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// A sole unnamed row parameter makes the function a computed field, which
|
|
129
|
+
// PostgREST only exposes under `/rpc` when it also returns rows.
|
|
130
|
+
if (soleInArg &&
|
|
131
|
+
soleInArg.name === "" &&
|
|
132
|
+
relationTypesById.has(soleInArg.type_id) &&
|
|
133
|
+
returnRelationName(fn) === null) {
|
|
134
|
+
return `the function ${fn.schema}.${fn.name} with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache`;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
};
|
|
138
|
+
const resolveOverload = (candidate, group) => {
|
|
139
|
+
const { fn, inArgs } = candidate;
|
|
140
|
+
const args = inArgs
|
|
141
|
+
.map((arg) => {
|
|
142
|
+
const relationId = relationTypesById.get(arg.type_id)?.type_relation_id;
|
|
143
|
+
return {
|
|
144
|
+
name: arg.name,
|
|
145
|
+
mode: arg.mode,
|
|
146
|
+
...typeReference(arg.type_id),
|
|
147
|
+
has_default: arg.has_default === true,
|
|
148
|
+
relation_id: relationId !== undefined &&
|
|
149
|
+
relationId !== null &&
|
|
150
|
+
relationsById.has(relationId)
|
|
151
|
+
? relationId
|
|
152
|
+
: null,
|
|
153
|
+
};
|
|
154
|
+
})
|
|
155
|
+
.sort((a, b) => compareStrings(a.name, b.name));
|
|
156
|
+
const tableColumns = fn.args
|
|
157
|
+
.filter(({ mode }) => mode === "table")
|
|
158
|
+
.map(({ name, type_id }) => ({ name, ...typeReference(type_id) }))
|
|
159
|
+
.sort((a, b) => compareStrings(a.name, b.name));
|
|
160
|
+
const relationName = returnRelationName(fn);
|
|
161
|
+
const returnsMultipleRows = fn.prorows !== null && fn.prorows > 1;
|
|
162
|
+
// A function whose sole parameter (of any mode) is a row type is embedded
|
|
163
|
+
// from that relation; any other row-returning function embeds from `*`.
|
|
164
|
+
const soleArg = fn.args.length === 1 ? fn.args[0] : undefined;
|
|
165
|
+
const sourceType = soleArg && relationTypesById.get(soleArg.type_id);
|
|
166
|
+
const setofOptions = relationName === null
|
|
167
|
+
? null
|
|
168
|
+
: {
|
|
169
|
+
from: sourceType ? sourceType.format : "*",
|
|
170
|
+
to: relationName,
|
|
171
|
+
is_one_to_one: sourceType && !fn.is_set_returning_function
|
|
172
|
+
? true
|
|
173
|
+
: !returnsMultipleRows,
|
|
174
|
+
is_setof_return: fn.is_set_returning_function,
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
function_id: fn.id,
|
|
178
|
+
args,
|
|
179
|
+
returns: {
|
|
180
|
+
...typeReference(fn.return_type_id),
|
|
181
|
+
relation_id: fn.return_type_relation_id !== null &&
|
|
182
|
+
relationsById.has(fn.return_type_relation_id)
|
|
183
|
+
? fn.return_type_relation_id
|
|
184
|
+
: null,
|
|
185
|
+
columns: tableColumns.length > 0 ? tableColumns : null,
|
|
186
|
+
},
|
|
187
|
+
is_set_returning: fn.is_set_returning_function,
|
|
188
|
+
rows_estimate: fn.prorows,
|
|
189
|
+
setof_options: setofOptions,
|
|
190
|
+
computed_field_of: computedFieldOf(candidate),
|
|
191
|
+
error: overloadError(candidate, group),
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
const groups = new Map();
|
|
195
|
+
for (const fn of metadata.functions) {
|
|
196
|
+
if (!schemaNames.has(fn.schema))
|
|
197
|
+
continue;
|
|
198
|
+
const inArgs = fn.args.filter((arg) => INPUT_ARG_MODES.has(arg.mode));
|
|
199
|
+
const candidate = { fn, inArgs };
|
|
200
|
+
if (!isCallable(candidate))
|
|
201
|
+
continue;
|
|
202
|
+
const key = `${fn.schema}.${fn.name}`;
|
|
203
|
+
let group = groups.get(key);
|
|
204
|
+
if (!group) {
|
|
205
|
+
group = [];
|
|
206
|
+
groups.set(key, group);
|
|
207
|
+
}
|
|
208
|
+
group.push(candidate);
|
|
209
|
+
}
|
|
210
|
+
return [...groups.values()]
|
|
211
|
+
.map((group) => {
|
|
212
|
+
const sorted = [...group].sort((a, b) => compareStrings(a.fn.argument_types, b.fn.argument_types) ||
|
|
213
|
+
compareStrings(a.fn.return_type, b.fn.return_type) ||
|
|
214
|
+
a.fn.id - b.fn.id);
|
|
215
|
+
const [{ fn }] = sorted;
|
|
216
|
+
return {
|
|
217
|
+
schema: fn.schema,
|
|
218
|
+
name: fn.name,
|
|
219
|
+
overloads: sorted.map((candidate) => resolveOverload(candidate, sorted)),
|
|
220
|
+
};
|
|
221
|
+
})
|
|
222
|
+
.sort((a, b) => compareStrings(a.schema, b.schema) || compareStrings(a.name, b.name));
|
|
223
|
+
}
|
package/dist/sort.js
CHANGED
|
@@ -60,5 +60,28 @@ export function sortGeneratorMetadata(metadata) {
|
|
|
60
60
|
args: [...fn.args].sort((a, b) => compareStrings(a.name, b.name)),
|
|
61
61
|
})),
|
|
62
62
|
types: [...metadata.types].sort(bySchemaName),
|
|
63
|
+
// `resolveRpcFunctions` orders the overloads of a function by signature,
|
|
64
|
+
// and that order is kept here, like composite attributes; the entries,
|
|
65
|
+
// their args and their table columns are addressed by name.
|
|
66
|
+
...(metadata.rpcFunctions === undefined
|
|
67
|
+
? {}
|
|
68
|
+
: {
|
|
69
|
+
rpcFunctions: [...metadata.rpcFunctions]
|
|
70
|
+
.sort((a, b) => compareStrings(a.schema, b.schema) ||
|
|
71
|
+
compareStrings(a.name, b.name))
|
|
72
|
+
.map((fn) => ({
|
|
73
|
+
...fn,
|
|
74
|
+
overloads: fn.overloads.map((overload) => ({
|
|
75
|
+
...overload,
|
|
76
|
+
args: [...overload.args].sort((a, b) => compareStrings(a.name, b.name)),
|
|
77
|
+
returns: {
|
|
78
|
+
...overload.returns,
|
|
79
|
+
columns: overload.returns.columns === null
|
|
80
|
+
? null
|
|
81
|
+
: [...overload.returns.columns].sort((a, b) => compareStrings(a.name, b.name)),
|
|
82
|
+
},
|
|
83
|
+
})),
|
|
84
|
+
})),
|
|
85
|
+
}),
|
|
63
86
|
};
|
|
64
87
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -208,6 +208,119 @@ declare const postgresViewSchema: import("arktype/internal/variants/object.ts").
|
|
|
208
208
|
}[] | undefined;
|
|
209
209
|
}, {}>;
|
|
210
210
|
export type PostgresView = typeof postgresViewSchema.infer;
|
|
211
|
+
/**
|
|
212
|
+
* A reference to a `types` entry by oid. `format` is the type's `name` (the
|
|
213
|
+
* same spelling `PostgresColumn.format` uses, `_` prefixed for arrays) and
|
|
214
|
+
* `type_schema` its schema; both are `null` when the type is not in `types`,
|
|
215
|
+
* which never happens in a document produced by `introspect()`.
|
|
216
|
+
*/
|
|
217
|
+
declare const rpcTypeReferenceSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
218
|
+
type_id: number;
|
|
219
|
+
format: string | null;
|
|
220
|
+
type_schema: string | null;
|
|
221
|
+
}, {}>;
|
|
222
|
+
export type RpcTypeReference = typeof rpcTypeReferenceSchema.infer;
|
|
223
|
+
declare const rpcFunctionArgSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
224
|
+
type_id: number;
|
|
225
|
+
format: string | null;
|
|
226
|
+
type_schema: string | null;
|
|
227
|
+
name: string;
|
|
228
|
+
mode: "in" | "inout" | "variadic";
|
|
229
|
+
has_default: boolean;
|
|
230
|
+
relation_id: number | null;
|
|
231
|
+
}, {}>;
|
|
232
|
+
export type RpcFunctionArg = typeof rpcFunctionArgSchema.infer;
|
|
233
|
+
declare const rpcFunctionReturnsSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
234
|
+
type_id: number;
|
|
235
|
+
format: string | null;
|
|
236
|
+
type_schema: string | null;
|
|
237
|
+
relation_id: number | null;
|
|
238
|
+
columns: {
|
|
239
|
+
type_id: number;
|
|
240
|
+
format: string | null;
|
|
241
|
+
type_schema: string | null;
|
|
242
|
+
name: string;
|
|
243
|
+
}[] | null;
|
|
244
|
+
}, {}>;
|
|
245
|
+
export type RpcFunctionReturns = typeof rpcFunctionReturnsSchema.infer;
|
|
246
|
+
declare const rpcFunctionOverloadSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
247
|
+
function_id: number;
|
|
248
|
+
args: {
|
|
249
|
+
type_id: number;
|
|
250
|
+
format: string | null;
|
|
251
|
+
type_schema: string | null;
|
|
252
|
+
name: string;
|
|
253
|
+
mode: "in" | "inout" | "variadic";
|
|
254
|
+
has_default: boolean;
|
|
255
|
+
relation_id: number | null;
|
|
256
|
+
}[];
|
|
257
|
+
returns: {
|
|
258
|
+
type_id: number;
|
|
259
|
+
format: string | null;
|
|
260
|
+
type_schema: string | null;
|
|
261
|
+
relation_id: number | null;
|
|
262
|
+
columns: {
|
|
263
|
+
type_id: number;
|
|
264
|
+
format: string | null;
|
|
265
|
+
type_schema: string | null;
|
|
266
|
+
name: string;
|
|
267
|
+
}[] | null;
|
|
268
|
+
};
|
|
269
|
+
is_set_returning: boolean;
|
|
270
|
+
rows_estimate: number | null;
|
|
271
|
+
setof_options: {
|
|
272
|
+
from: string;
|
|
273
|
+
to: string;
|
|
274
|
+
is_one_to_one: boolean;
|
|
275
|
+
is_setof_return: boolean;
|
|
276
|
+
} | null;
|
|
277
|
+
computed_field_of: number | null;
|
|
278
|
+
error: string | null;
|
|
279
|
+
}, {}>;
|
|
280
|
+
export type RpcFunctionOverload = typeof rpcFunctionOverloadSchema.infer;
|
|
281
|
+
/**
|
|
282
|
+
* A function PostgREST exposes under `/rpc`, with its overloads resolved.
|
|
283
|
+
* Produced by `resolveRpcFunctions` from the raw `functions` collection.
|
|
284
|
+
*/
|
|
285
|
+
declare const rpcFunctionSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
286
|
+
schema: string;
|
|
287
|
+
name: string;
|
|
288
|
+
overloads: {
|
|
289
|
+
function_id: number;
|
|
290
|
+
args: {
|
|
291
|
+
type_id: number;
|
|
292
|
+
format: string | null;
|
|
293
|
+
type_schema: string | null;
|
|
294
|
+
name: string;
|
|
295
|
+
mode: "in" | "inout" | "variadic";
|
|
296
|
+
has_default: boolean;
|
|
297
|
+
relation_id: number | null;
|
|
298
|
+
}[];
|
|
299
|
+
returns: {
|
|
300
|
+
type_id: number;
|
|
301
|
+
format: string | null;
|
|
302
|
+
type_schema: string | null;
|
|
303
|
+
relation_id: number | null;
|
|
304
|
+
columns: {
|
|
305
|
+
type_id: number;
|
|
306
|
+
format: string | null;
|
|
307
|
+
type_schema: string | null;
|
|
308
|
+
name: string;
|
|
309
|
+
}[] | null;
|
|
310
|
+
};
|
|
311
|
+
is_set_returning: boolean;
|
|
312
|
+
rows_estimate: number | null;
|
|
313
|
+
setof_options: {
|
|
314
|
+
from: string;
|
|
315
|
+
to: string;
|
|
316
|
+
is_one_to_one: boolean;
|
|
317
|
+
is_setof_return: boolean;
|
|
318
|
+
} | null;
|
|
319
|
+
computed_field_of: number | null;
|
|
320
|
+
error: string | null;
|
|
321
|
+
}[];
|
|
322
|
+
}, {}>;
|
|
323
|
+
export type RpcFunction = typeof rpcFunctionSchema.infer;
|
|
211
324
|
/**
|
|
212
325
|
* Bumped whenever `GeneratorMetadata`'s shape changes in a way a consumer
|
|
213
326
|
* should branch on. Out-of-process consumers (a generator in another
|
|
@@ -341,6 +454,44 @@ export declare const generatorMetadataSchema: import("arktype/internal/variants/
|
|
|
341
454
|
comment: string | null;
|
|
342
455
|
type_relation_id: number | null;
|
|
343
456
|
}[];
|
|
457
|
+
rpcFunctions?: {
|
|
458
|
+
schema: string;
|
|
459
|
+
name: string;
|
|
460
|
+
overloads: {
|
|
461
|
+
function_id: number;
|
|
462
|
+
args: {
|
|
463
|
+
type_id: number;
|
|
464
|
+
format: string | null;
|
|
465
|
+
type_schema: string | null;
|
|
466
|
+
name: string;
|
|
467
|
+
mode: "in" | "inout" | "variadic";
|
|
468
|
+
has_default: boolean;
|
|
469
|
+
relation_id: number | null;
|
|
470
|
+
}[];
|
|
471
|
+
returns: {
|
|
472
|
+
type_id: number;
|
|
473
|
+
format: string | null;
|
|
474
|
+
type_schema: string | null;
|
|
475
|
+
relation_id: number | null;
|
|
476
|
+
columns: {
|
|
477
|
+
type_id: number;
|
|
478
|
+
format: string | null;
|
|
479
|
+
type_schema: string | null;
|
|
480
|
+
name: string;
|
|
481
|
+
}[] | null;
|
|
482
|
+
};
|
|
483
|
+
is_set_returning: boolean;
|
|
484
|
+
rows_estimate: number | null;
|
|
485
|
+
setof_options: {
|
|
486
|
+
from: string;
|
|
487
|
+
to: string;
|
|
488
|
+
is_one_to_one: boolean;
|
|
489
|
+
is_setof_return: boolean;
|
|
490
|
+
} | null;
|
|
491
|
+
computed_field_of: number | null;
|
|
492
|
+
error: string | null;
|
|
493
|
+
}[];
|
|
494
|
+
}[] | undefined;
|
|
344
495
|
}, {}>;
|
|
345
496
|
export type GeneratorMetadata = typeof generatorMetadataSchema.infer;
|
|
346
497
|
/**
|
package/dist/types.js
CHANGED
|
@@ -150,6 +150,89 @@ const postgresViewSchema = type({
|
|
|
150
150
|
comment: "string | null",
|
|
151
151
|
"columns?": postgresColumnSchema.array(),
|
|
152
152
|
});
|
|
153
|
+
/**
|
|
154
|
+
* A reference to a `types` entry by oid. `format` is the type's `name` (the
|
|
155
|
+
* same spelling `PostgresColumn.format` uses, `_` prefixed for arrays) and
|
|
156
|
+
* `type_schema` its schema; both are `null` when the type is not in `types`,
|
|
157
|
+
* which never happens in a document produced by `introspect()`.
|
|
158
|
+
*/
|
|
159
|
+
const rpcTypeReferenceSchema = type({
|
|
160
|
+
type_id: "number",
|
|
161
|
+
format: "string | null",
|
|
162
|
+
type_schema: "string | null",
|
|
163
|
+
});
|
|
164
|
+
const rpcFunctionArgSchema = rpcTypeReferenceSchema.merge({
|
|
165
|
+
/** Empty for an unnamed parameter. */
|
|
166
|
+
name: "string",
|
|
167
|
+
mode: "'in' | 'inout' | 'variadic'",
|
|
168
|
+
has_default: "boolean",
|
|
169
|
+
/**
|
|
170
|
+
* The relation whose row type this parameter has, when that relation is in
|
|
171
|
+
* the metadata. A caller passes such a parameter as a row object.
|
|
172
|
+
*/
|
|
173
|
+
relation_id: "number | null",
|
|
174
|
+
});
|
|
175
|
+
const rpcFunctionReturnsSchema = rpcTypeReferenceSchema.merge({
|
|
176
|
+
/**
|
|
177
|
+
* The relation whose rows the function returns, when that relation is in
|
|
178
|
+
* the metadata; the row shape is the relation's `columns`.
|
|
179
|
+
*/
|
|
180
|
+
relation_id: "number | null",
|
|
181
|
+
/**
|
|
182
|
+
* The columns of a `RETURNS TABLE (…)` or `OUT` parameter result, in name
|
|
183
|
+
* order; `null` for every other return type.
|
|
184
|
+
*/
|
|
185
|
+
columns: rpcTypeReferenceSchema.merge({ name: "string" }).array().or("null"),
|
|
186
|
+
});
|
|
187
|
+
const rpcFunctionOverloadSchema = type({
|
|
188
|
+
/** The `functions` entry this overload was resolved from. */
|
|
189
|
+
function_id: "number",
|
|
190
|
+
/** The input parameters (`in`, `inout` and `variadic`), in name order. */
|
|
191
|
+
args: rpcFunctionArgSchema.array(),
|
|
192
|
+
returns: rpcFunctionReturnsSchema,
|
|
193
|
+
/** `true` when the response is an array of rows or values. */
|
|
194
|
+
is_set_returning: "boolean",
|
|
195
|
+
/** The planner's `ROWS` estimate of a set-returning function, else `null`. */
|
|
196
|
+
rows_estimate: "number | null",
|
|
197
|
+
/**
|
|
198
|
+
* Present when the result can be embedded and sub-selected like a relation.
|
|
199
|
+
* `to` names the relation (or composite type) whose rows come back, `from`
|
|
200
|
+
* the relation a sole row-typed parameter embeds from, or `*` when the
|
|
201
|
+
* function is called directly. `is_one_to_one` is `true` when at most one
|
|
202
|
+
* row comes back, so a client may unwrap the array. `is_setof_return`
|
|
203
|
+
* mirrors `is_set_returning`.
|
|
204
|
+
*/
|
|
205
|
+
setof_options: type({
|
|
206
|
+
from: "string",
|
|
207
|
+
to: "string",
|
|
208
|
+
is_one_to_one: "boolean",
|
|
209
|
+
is_setof_return: "boolean",
|
|
210
|
+
}).or("null"),
|
|
211
|
+
/**
|
|
212
|
+
* The relation this function is a computed field of: its sole input
|
|
213
|
+
* parameter has that relation's row type, the relation is in the function's
|
|
214
|
+
* schema, and no column of the relation shares the function's name. Such a
|
|
215
|
+
* function is selectable as a nullable column of the relation.
|
|
216
|
+
*/
|
|
217
|
+
computed_field_of: "number | null",
|
|
218
|
+
/**
|
|
219
|
+
* Why PostgREST cannot resolve a call to this overload, when it cannot: the
|
|
220
|
+
* function conflicts with another overload, or it is a computed field that
|
|
221
|
+
* returns no rows. Generators surface the message instead of a callable
|
|
222
|
+
* signature.
|
|
223
|
+
*/
|
|
224
|
+
error: "string | null",
|
|
225
|
+
});
|
|
226
|
+
/**
|
|
227
|
+
* A function PostgREST exposes under `/rpc`, with its overloads resolved.
|
|
228
|
+
* Produced by `resolveRpcFunctions` from the raw `functions` collection.
|
|
229
|
+
*/
|
|
230
|
+
const rpcFunctionSchema = type({
|
|
231
|
+
schema: "string",
|
|
232
|
+
name: "string",
|
|
233
|
+
/** Ordered by argument list, then by return type. Never empty. */
|
|
234
|
+
overloads: rpcFunctionOverloadSchema.array(),
|
|
235
|
+
});
|
|
153
236
|
/**
|
|
154
237
|
* Bumped whenever `GeneratorMetadata`'s shape changes in a way a consumer
|
|
155
238
|
* should branch on. Out-of-process consumers (a generator in another
|
|
@@ -177,6 +260,14 @@ export const generatorMetadataSchema = type({
|
|
|
177
260
|
relationships: postgresRelationshipSchema.array(),
|
|
178
261
|
functions: postgresFunctionSchema.array(),
|
|
179
262
|
types: postgresTypeSchema.array(),
|
|
263
|
+
/**
|
|
264
|
+
* The PostgREST view of `functions`: which are callable through `/rpc`, how
|
|
265
|
+
* their overloads group and what a call returns. Derived from the other
|
|
266
|
+
* collections by `resolveRpcFunctions`, which `introspect()` runs. Optional
|
|
267
|
+
* because version 1 documents predating the collection are still valid;
|
|
268
|
+
* a generator falls back to running `resolveRpcFunctions` itself.
|
|
269
|
+
*/
|
|
270
|
+
"rpcFunctions?": rpcFunctionSchema.array(),
|
|
180
271
|
});
|
|
181
272
|
/**
|
|
182
273
|
* JSON Schema for {@link generatorMetadataSchema}, published so out-of-process
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supabase/postgrest-typegen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Type generation for PostgREST from PostgreSQL schemas",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codegen",
|
|
@@ -58,11 +58,12 @@
|
|
|
58
58
|
"check-types:consumer": "tsc --project tsconfig.consumer.json",
|
|
59
59
|
"format-and-lint": "oxfmt --check . && oxlint --deny-warnings src test scripts",
|
|
60
60
|
"format-and-lint:fix": "oxfmt . && oxlint --fix src test scripts",
|
|
61
|
+
"generate:postgrest-js-types": "bun scripts/generate-postgrest-js-types.ts",
|
|
61
62
|
"knip": "knip",
|
|
62
63
|
"test": "bun scripts/run-tests.ts test/"
|
|
63
64
|
},
|
|
64
65
|
"dependencies": {
|
|
65
|
-
"arktype": "2.2.
|
|
66
|
+
"arktype": "2.2.8"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"@testcontainers/postgresql": "^12.1.0",
|
|
@@ -74,8 +75,8 @@
|
|
|
74
75
|
"@types/pg": "^8.23.1",
|
|
75
76
|
"knip": "^6.32.3",
|
|
76
77
|
"oxfmt": "0.66.0",
|
|
77
|
-
"oxlint": "1.
|
|
78
|
-
"oxlint-tsgolint": "7.0.
|
|
78
|
+
"oxlint": "1.87.0",
|
|
79
|
+
"oxlint-tsgolint": "7.0.2004",
|
|
79
80
|
"pg": "^8.23.0",
|
|
80
81
|
"testcontainers": "^12.1.0",
|
|
81
82
|
"typescript": "7.0.2"
|