true-pg 0.2.3 → 0.3.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.
Files changed (49) hide show
  1. package/README.md +12 -8
  2. package/lib/bin.js +3 -7
  3. package/lib/extractor/adapter.d.ts +15 -0
  4. package/lib/extractor/adapter.js +53 -0
  5. package/lib/extractor/canonicalise.d.ts +64 -0
  6. package/lib/extractor/canonicalise.js +245 -0
  7. package/lib/extractor/fetchExtensionItemIds.d.ts +12 -0
  8. package/lib/extractor/fetchExtensionItemIds.js +43 -0
  9. package/lib/extractor/fetchTypes.d.ts +4 -0
  10. package/lib/extractor/fetchTypes.js +65 -0
  11. package/lib/extractor/index.d.ts +95 -0
  12. package/lib/extractor/index.js +140 -0
  13. package/lib/extractor/kinds/composite.d.ts +15 -0
  14. package/lib/extractor/kinds/composite.js +13 -0
  15. package/lib/extractor/kinds/domain.d.ts +15 -0
  16. package/lib/extractor/kinds/domain.js +13 -0
  17. package/lib/extractor/kinds/enum.d.ts +9 -0
  18. package/lib/extractor/kinds/enum.js +20 -0
  19. package/lib/extractor/kinds/function.d.ts +73 -0
  20. package/lib/extractor/kinds/function.js +179 -0
  21. package/lib/extractor/kinds/materialized-view.d.ts +17 -0
  22. package/lib/extractor/kinds/materialized-view.js +64 -0
  23. package/lib/extractor/kinds/parts/commentMapQueryPart.d.ts +2 -0
  24. package/lib/extractor/kinds/parts/commentMapQueryPart.js +14 -0
  25. package/lib/extractor/kinds/parts/indexMapQueryPart.d.ts +2 -0
  26. package/lib/extractor/kinds/parts/indexMapQueryPart.js +27 -0
  27. package/lib/extractor/kinds/range.d.ts +15 -0
  28. package/lib/extractor/kinds/range.js +13 -0
  29. package/lib/extractor/kinds/table.d.ts +212 -0
  30. package/lib/extractor/kinds/table.js +217 -0
  31. package/lib/extractor/kinds/util/parseInlineTable.d.ts +9 -0
  32. package/lib/extractor/kinds/util/parseInlineTable.js +135 -0
  33. package/lib/extractor/kinds/util/parseInlineTable.test.d.ts +1 -0
  34. package/lib/extractor/kinds/util/parseInlineTable.test.js +26 -0
  35. package/lib/extractor/kinds/view.d.ts +17 -0
  36. package/lib/extractor/kinds/view.js +63 -0
  37. package/lib/extractor/pgtype.d.ts +41 -0
  38. package/lib/extractor/pgtype.js +30 -0
  39. package/lib/index.d.ts +2 -2
  40. package/lib/index.js +38 -28
  41. package/lib/kysely/builtins.js +6 -4
  42. package/lib/kysely/index.js +103 -59
  43. package/lib/types.d.ts +38 -10
  44. package/lib/types.js +14 -3
  45. package/lib/util.d.ts +11 -0
  46. package/lib/util.js +6 -0
  47. package/lib/zod/builtins.js +11 -9
  48. package/lib/zod/index.js +107 -60
  49. package/package.json +3 -4
@@ -4,12 +4,11 @@ export const builtins = {
4
4
  "pg_catalog.int4": "z.number()",
5
5
  // JS numbers are always floating point, so there is only 53 bits of precision
6
6
  // for the integer part. Thus, storing a 64-bit integer in a JS number will
7
- // result in potential data loss. We therefore use strings for 64-bit integers
8
- // the same way that the pg driver does.
9
- "pg_catalog.int8": "z.string()",
7
+ // result in potential data loss.
8
+ "pg_catalog.int8": "z.bigint()",
9
+ "pg_catalog.numeric": "z.bigint()",
10
10
  "pg_catalog.float4": "z.number()",
11
11
  "pg_catalog.float8": "z.number()",
12
- "pg_catalog.numeric": "z.string()",
13
12
  "pg_catalog.bool": "z.boolean()",
14
13
  "pg_catalog.json": "z.unknown()",
15
14
  "pg_catalog.jsonb": "z.unknown()",
@@ -19,11 +18,11 @@ export const builtins = {
19
18
  "pg_catalog.text": "z.string()",
20
19
  "pg_catalog.uuid": "z.string()",
21
20
  "pg_catalog.inet": "z.string()",
22
- "pg_catalog.date": "z.date()",
23
- "pg_catalog.time": "z.date()",
24
- "pg_catalog.timetz": "z.date()",
25
- "pg_catalog.timestamp": "z.date()",
26
- "pg_catalog.timestamptz": "z.date()",
21
+ "pg_catalog.date": "z.coerce.date()",
22
+ "pg_catalog.time": "z.coerce.date()",
23
+ "pg_catalog.timetz": "z.coerce.date()",
24
+ "pg_catalog.timestamp": "z.coerce.date()",
25
+ "pg_catalog.timestamptz": "z.coerce.date()",
27
26
  "pg_catalog.int4range": "z.string()",
28
27
  "pg_catalog.int8range": "z.string()",
29
28
  "pg_catalog.numrange": "z.string()",
@@ -32,4 +31,7 @@ export const builtins = {
32
31
  "pg_catalog.daterange": "z.string()",
33
32
  "pg_catalog.record": "z.record(z.string(), z.unknown())",
34
33
  "pg_catalog.void": "z.void()",
34
+ "pg_catalog.bytea": "z.string()",
35
+ "pg_catalog.vector": "z.number().array()",
36
+ "pg_catalog.tsvector": "z.string().array()",
35
37
  };
package/lib/zod/index.js CHANGED
@@ -1,10 +1,7 @@
1
+ import { FunctionReturnTypeKind, } from "../extractor/index.js";
1
2
  import { allowed_kind_names, createGenerator, Nodes } from "../types.js";
2
3
  import { builtins } from "./builtins.js";
3
- import { join } from "../util.js";
4
- const isIdentifierInvalid = (str) => {
5
- const invalid = str.match(/[^a-zA-Z0-9_]/);
6
- return invalid !== null;
7
- };
4
+ import { join, quote, quoteI } from "../util.js";
8
5
  const to_snake_case = (str) => str
9
6
  .replace(/^[^a-zA-Z]+/, "") // remove leading non-alphabetic characters
10
7
  .replace(/[^a-zA-Z0-9]+/g, "_") // replace non-alphanumeric characters with underscores
@@ -37,7 +34,7 @@ export const Zod = createGenerator(opts => {
37
34
  if (col.generated === "ALWAYS")
38
35
  return "";
39
36
  let out = col.comment ? `/** ${col.comment} */\n\t` : "";
40
- out += col.name;
37
+ out += quoteI(col.name);
41
38
  let type = generator.formatType(col.type);
42
39
  add(imports, col.type);
43
40
  if (col.type.dimensions > 0)
@@ -48,7 +45,7 @@ export const Zod = createGenerator(opts => {
48
45
  return `\t${out},\n`;
49
46
  };
50
47
  const composite_attribute = (imports, attr) => {
51
- let out = attr.name;
48
+ let out = quoteI(attr.name);
52
49
  out += `: ${generator.formatType(attr.type)}`;
53
50
  add(imports, attr.type);
54
51
  if (attr.type.dimensions > 0)
@@ -65,12 +62,15 @@ export const Zod = createGenerator(opts => {
65
62
  return to_snake_case(type.name);
66
63
  },
67
64
  formatType(type) {
68
- if (type.schema === "pg_catalog") {
65
+ if (type.kind === FunctionReturnTypeKind.ExistingTable) {
66
+ return to_snake_case(type.name);
67
+ }
68
+ else if (type.schema === "pg_catalog") {
69
69
  const name = type.canonical_name;
70
70
  const format = builtins[name];
71
71
  if (format)
72
72
  return format;
73
- opts?.warnings?.push(`Unknown builtin type: ${name}! Pass customBuiltinMap to map this type. Defaulting to "z.unknown()".`);
73
+ opts?.warnings?.push(`(zod) Unknown builtin type: ${name}. Pass customBuiltinMap to map this type. Defaulting to "z.unknown()".`);
74
74
  return "z.unknown()";
75
75
  }
76
76
  return to_snake_case(type.name);
@@ -86,6 +86,28 @@ export const Zod = createGenerator(opts => {
86
86
  out += "});";
87
87
  return out;
88
88
  },
89
+ view(imports, view) {
90
+ let out = "";
91
+ if (view.comment)
92
+ out += `/** ${view.comment} */\n`;
93
+ zod(imports, "z");
94
+ out += `export const ${this.formatSchemaType(view)} = z.object({\n`;
95
+ for (const col of view.columns)
96
+ out += column(imports, col);
97
+ out += "});";
98
+ return out;
99
+ },
100
+ materializedView(imports, materializedView) {
101
+ let out = "";
102
+ if (materializedView.comment)
103
+ out += `/** ${materializedView.comment} */\n`;
104
+ zod(imports, "z");
105
+ out += `export const ${this.formatSchemaType(materializedView)} = z.object({\n`;
106
+ for (const col of materializedView.columns)
107
+ out += column(imports, col);
108
+ out += "});";
109
+ return out;
110
+ },
89
111
  enum(imports, en) {
90
112
  let out = "";
91
113
  if (en.comment)
@@ -106,6 +128,18 @@ export const Zod = createGenerator(opts => {
106
128
  out += "\n});";
107
129
  return out;
108
130
  },
131
+ domain(imports, type) {
132
+ let out = "";
133
+ out += `export const ${this.formatSchemaType(type)} = ${this.formatType(type.canonical.domain_base_type)};`;
134
+ zod(imports, "z");
135
+ return out;
136
+ },
137
+ range(imports, type) {
138
+ let out = "";
139
+ out += `export const ${this.formatSchemaType(type)} = z.string();`;
140
+ zod(imports, "z");
141
+ return out;
142
+ },
109
143
  function(imports, type) {
110
144
  let out = "export const ";
111
145
  out += this.formatSchemaType(type);
@@ -142,17 +176,25 @@ export const Zod = createGenerator(opts => {
142
176
  else
143
177
  out += ",\n";
144
178
  out += "\treturnType: ";
145
- if (type.returnType.kind === "table") {
146
- out += "z.object({\n";
147
- for (const col of type.returnType.columns) {
148
- out += `\t\t${col.name}: `;
149
- out += this.formatType(col.type);
150
- add(imports, col.type);
151
- if (col.type.dimensions > 0)
152
- out += ".array()".repeat(col.type.dimensions);
153
- out += `,\n`;
179
+ if (type.returnType.kind === FunctionReturnTypeKind.InlineTable) {
180
+ if (type.returnType.columns.length === 0)
181
+ out += "z.void()/* RETURNS TABLE with no columns */";
182
+ else {
183
+ out += "z.object({\n";
184
+ for (const col of type.returnType.columns) {
185
+ out += `\t\t"${col.name}": `;
186
+ out += this.formatType(col.type);
187
+ add(imports, col.type);
188
+ if (col.type.dimensions > 0)
189
+ out += ".array()".repeat(col.type.dimensions);
190
+ out += `,\n`;
191
+ }
192
+ out += "\t})";
154
193
  }
155
- out += "\t})";
194
+ }
195
+ else if (type.returnType.kind === FunctionReturnTypeKind.ExistingTable) {
196
+ out += this.formatType(type.returnType);
197
+ add(imports, type.returnType);
156
198
  }
157
199
  else {
158
200
  out += this.formatType(type.returnType.type);
@@ -164,6 +206,7 @@ export const Zod = createGenerator(opts => {
164
206
  if (type.returnType.isSet)
165
207
  out += ".array()";
166
208
  out += ",\n};";
209
+ zod(imports, "z");
167
210
  return out;
168
211
  },
169
212
  schemaKindIndex(schema, kind, main_generator) {
@@ -180,10 +223,11 @@ export const Zod = createGenerator(opts => {
180
223
  .join("\n");
181
224
  },
182
225
  schemaIndex(schema, main_generator) {
183
- let out = allowed_kind_names.map(kind => `import * as zod_${kind} from "./${kind}/index.ts";`).join("\n");
226
+ const actual_kinds = allowed_kind_names.filter(kind => schema[kind].length);
227
+ let out = actual_kinds.map(kind => `import * as zod_${kind} from "./${kind}/index.ts";`).join("\n");
184
228
  out += "\n\n";
185
229
  out += `export const ${this.formatSchema(schema.name)} = {\n`;
186
- for (const kind of allowed_kind_names) {
230
+ for (const kind of actual_kinds) {
187
231
  const items = schema[kind];
188
232
  if (items.length === 0)
189
233
  continue;
@@ -196,9 +240,7 @@ export const Zod = createGenerator(opts => {
196
240
  .filter(x => x !== undefined);
197
241
  out += formatted
198
242
  .map(t => {
199
- let name = t.name;
200
- if (isIdentifierInvalid(name))
201
- name = `"${name}"`;
243
+ let name = quoteI(t.name);
202
244
  return `\t\t${name}: zod_${t.kind}s.${t.formatted},`;
203
245
  })
204
246
  .join("\n");
@@ -209,44 +251,49 @@ export const Zod = createGenerator(opts => {
209
251
  },
210
252
  fullIndex(schemas, main_generator) {
211
253
  const generator = main_generator ?? this;
212
- let out = "";
213
- out += schemas
254
+ const parts = [];
255
+ parts.push(schemas
214
256
  .map(s => `import { ${generator.formatSchema(s.name)} } from "./${s.name}/index.ts";`)
215
- .join("\n");
216
- out += "\n\n";
217
- out += `export const Validators = {\n`;
218
- out += join(schemas.map(schema => {
219
- const schema_validators = join(allowed_kind_names.map(kind => {
220
- const current = schema[kind];
221
- const seen = new Set();
222
- const formatted = current
223
- .map(each => {
224
- const formatted = generator.formatSchemaType(each);
225
- // skip clashing names
226
- if (seen.has(formatted))
227
- return;
228
- seen.add(formatted);
229
- return { ...each, formatted };
230
- })
231
- .filter(x => x !== undefined);
232
- if (!formatted.length)
233
- return "";
234
- let out = "";
235
- out += "\t// " + kind + "\n";
236
- out += join(formatted.map(t => {
237
- const prefix = defaultSchema === schema.name ? "" : schema.name + ".";
238
- let qualified = prefix + t.name;
239
- if (isIdentifierInvalid(qualified))
240
- qualified = `"${qualified}"`;
241
- return `\t${qualified}: ${this.formatSchema(schema.name)}["${t.kind}s"]["${t.name}"],`;
242
- }), "\n");
243
- return out;
257
+ .join("\n"));
258
+ {
259
+ let validator = `export const Validators = {\n`;
260
+ validator += join(schemas.map(schema => {
261
+ const schema_validators = join(allowed_kind_names.map(kind => {
262
+ const current = schema[kind];
263
+ const seen = new Set();
264
+ const formatted = current
265
+ .map(each => {
266
+ const formatted = generator.formatSchemaType(each);
267
+ // skip clashing names
268
+ if (seen.has(formatted))
269
+ return;
270
+ seen.add(formatted);
271
+ return { ...each, formatted };
272
+ })
273
+ .filter(x => x !== undefined);
274
+ if (!formatted.length)
275
+ return "";
276
+ let out = "";
277
+ out += "\t// " + kind + "\n";
278
+ out += join(formatted.map(t => {
279
+ const isDefault = defaultSchema === schema.name;
280
+ let qualified = "";
281
+ if (!isDefault)
282
+ qualified = schema.name + "." + t.name;
283
+ else
284
+ qualified = t.name;
285
+ qualified = quoteI(qualified);
286
+ return `\t${qualified}: ${this.formatSchema(schema.name)}[${quote(t.kind + "s")}][${quote(t.name)}],`;
287
+ }), "\n");
288
+ return out;
289
+ }));
290
+ return `\t/* -- ${schema.name} --*/\n\n` + schema_validators || "\t-- no validators\n\n";
244
291
  }));
245
- return `\t/* -- ${schema.name} --*/\n\n` + schema_validators || "\t-- no validators\n\n";
246
- }));
247
- out += "\n};\n\n";
248
- out += schemas.map(s => `export type { ${this.formatSchema(s.name)} };`).join("\n");
249
- return out;
292
+ validator += "\n};";
293
+ parts.push(validator);
294
+ }
295
+ parts.push(schemas.map(s => `export type { ${this.formatSchema(s.name)} };`).join("\n"));
296
+ return join(parts);
250
297
  },
251
298
  };
252
299
  return generator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "true-pg",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "module": "lib/index.js",
6
6
  "main": "lib/index.js",
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "scripts": {
19
19
  "check": "tsc --noEmit",
20
- "build": "tsc",
20
+ "build": "rm -rf lib && tsc",
21
21
  "prepare": "bun run build"
22
22
  },
23
23
  "devDependencies": {
@@ -30,7 +30,6 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "cosmiconfig": "^9.0.0",
33
- "mri": "^1.2.0",
34
- "pg-extract": "^0.0.3"
33
+ "mri": "^1.2.0"
35
34
  }
36
35
  }