true-pg 0.7.0 → 0.8.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/lib/extractor/adapter.d.ts +8 -5
- package/lib/extractor/adapter.js +27 -12
- package/lib/extractor/canonicalise/composite.d.ts +7 -0
- package/lib/extractor/canonicalise/composite.js +53 -0
- package/lib/extractor/canonicalise/domain.d.ts +12 -0
- package/lib/extractor/canonicalise/domain.js +77 -0
- package/lib/extractor/canonicalise/enum.d.ts +8 -0
- package/lib/extractor/canonicalise/enum.js +22 -0
- package/lib/extractor/canonicalise/index.d.ts +11 -0
- package/lib/extractor/canonicalise/index.js +148 -0
- package/lib/extractor/canonicalise/parse.d.ts +43 -0
- package/lib/extractor/canonicalise/parse.js +50 -0
- package/lib/extractor/canonicalise/range.d.ts +11 -0
- package/lib/extractor/canonicalise/range.js +36 -0
- package/lib/extractor/canonicalise/resolve.d.ts +19 -0
- package/lib/extractor/canonicalise/resolve.js +59 -0
- package/lib/extractor/canonicalise/types.d.ts +70 -0
- package/lib/extractor/canonicalise/types.js +13 -0
- package/lib/extractor/index.d.ts +5 -2
- package/lib/extractor/index.js +5 -7
- package/lib/extractor/kinds/composite.d.ts +1 -1
- package/lib/extractor/kinds/composite.js +1 -1
- package/lib/extractor/kinds/domain.d.ts +1 -1
- package/lib/extractor/kinds/domain.js +1 -1
- package/lib/extractor/kinds/function.d.ts +1 -1
- package/lib/extractor/kinds/function.js +5 -7
- package/lib/extractor/kinds/materialized-view.d.ts +1 -1
- package/lib/extractor/kinds/materialized-view.js +4 -7
- package/lib/extractor/kinds/range.d.ts +1 -1
- package/lib/extractor/kinds/range.js +1 -2
- package/lib/extractor/kinds/table.d.ts +1 -1
- package/lib/extractor/kinds/table.js +2 -7
- package/lib/extractor/kinds/view.d.ts +1 -1
- package/lib/extractor/kinds/view.js +4 -7
- package/lib/imports.test.js +6 -14
- package/lib/index.js +2 -2
- package/lib/util.d.ts +3 -6
- package/lib/util.js +15 -11
- package/package.json +1 -1
- package/lib/extractor/canonicalise.d.ts +0 -110
- package/lib/extractor/canonicalise.js +0 -384
@@ -0,0 +1,70 @@
|
|
1
|
+
export declare namespace Canonical {
|
2
|
+
enum Kind {
|
3
|
+
Base = "base",
|
4
|
+
Composite = "composite",
|
5
|
+
Domain = "domain",
|
6
|
+
Enum = "enum",
|
7
|
+
Range = "range",
|
8
|
+
Pseudo = "pseudo",
|
9
|
+
Unknown = "unknown"
|
10
|
+
}
|
11
|
+
interface Abstract {
|
12
|
+
original_type: string;
|
13
|
+
canonical_name: string;
|
14
|
+
schema: string;
|
15
|
+
name: string;
|
16
|
+
kind: Kind;
|
17
|
+
dimensions: number;
|
18
|
+
modifiers?: string | null;
|
19
|
+
}
|
20
|
+
interface Base extends Abstract {
|
21
|
+
kind: Kind.Base;
|
22
|
+
}
|
23
|
+
interface Enum extends Abstract {
|
24
|
+
kind: Kind.Enum;
|
25
|
+
enum_values: string[];
|
26
|
+
}
|
27
|
+
interface CompositeAttribute {
|
28
|
+
name: string;
|
29
|
+
index: number;
|
30
|
+
type: Canonical;
|
31
|
+
comment: string | null;
|
32
|
+
defaultValue: any;
|
33
|
+
isNullable: boolean;
|
34
|
+
/**
|
35
|
+
* Whether the attribute is an identity attribute.
|
36
|
+
*/
|
37
|
+
isIdentity: boolean;
|
38
|
+
/**
|
39
|
+
* Behavior of the generated attribute. "ALWAYS" if always generated,
|
40
|
+
* "NEVER" if never generated, "BY DEFAULT" if generated when a value
|
41
|
+
* is not provided.
|
42
|
+
*/
|
43
|
+
generated: "ALWAYS" | "NEVER" | "BY DEFAULT";
|
44
|
+
}
|
45
|
+
interface Composite extends Abstract {
|
46
|
+
kind: Kind.Composite;
|
47
|
+
attributes: CompositeAttribute[];
|
48
|
+
}
|
49
|
+
interface Domain extends Abstract {
|
50
|
+
kind: Kind.Domain;
|
51
|
+
domain_base_type: Canonical;
|
52
|
+
}
|
53
|
+
interface Range extends Abstract {
|
54
|
+
kind: Kind.Range;
|
55
|
+
range_subtype: Canonical;
|
56
|
+
}
|
57
|
+
interface Pseudo extends Abstract {
|
58
|
+
kind: Kind.Pseudo;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
export type Canonical = Canonical.Base | Canonical.Enum | Canonical.Composite | Canonical.Domain | Canonical.Range | Canonical.Pseudo;
|
62
|
+
type Exclusive<T> = Omit<T, Exclude<keyof Canonical.Abstract, "kind" | "canonical_name">>;
|
63
|
+
export type ExclusiveBase = Exclusive<Canonical.Base>;
|
64
|
+
export type ExclusiveEnum = Exclusive<Canonical.Enum>;
|
65
|
+
export type ExclusiveComposite = Exclusive<Canonical.Composite>;
|
66
|
+
export type ExclusiveDomain = Exclusive<Canonical.Domain>;
|
67
|
+
export type ExclusiveRange = Exclusive<Canonical.Range>;
|
68
|
+
export type ExclusivePseudo = Exclusive<Canonical.Pseudo>;
|
69
|
+
export type ExclusiveCanonProps = ExclusiveBase | ExclusiveEnum | ExclusiveComposite | ExclusiveDomain | ExclusiveRange | ExclusivePseudo;
|
70
|
+
export {};
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export var Canonical;
|
2
|
+
(function (Canonical) {
|
3
|
+
let Kind;
|
4
|
+
(function (Kind) {
|
5
|
+
Kind["Base"] = "base";
|
6
|
+
Kind["Composite"] = "composite";
|
7
|
+
Kind["Domain"] = "domain";
|
8
|
+
Kind["Enum"] = "enum";
|
9
|
+
Kind["Range"] = "range";
|
10
|
+
Kind["Pseudo"] = "pseudo";
|
11
|
+
Kind["Unknown"] = "unknown";
|
12
|
+
})(Kind = Canonical.Kind || (Canonical.Kind = {}));
|
13
|
+
})(Canonical || (Canonical = {}));
|
package/lib/extractor/index.d.ts
CHANGED
@@ -11,7 +11,7 @@ import { type DomainDetails } from "./kinds/domain.ts";
|
|
11
11
|
import { type RangeDetails } from "./kinds/range.ts";
|
12
12
|
import type { PgType } from "./pgtype.ts";
|
13
13
|
export { pgTypeKinds, type PgType, type Kind } from "./pgtype.ts";
|
14
|
-
import { Canonical } from "./canonicalise.ts";
|
14
|
+
import { Canonical } from "./canonicalise/index.ts";
|
15
15
|
export { Canonical };
|
16
16
|
export type { TableDetails, ViewDetails, MaterializedViewDetails, EnumDetails, CompositeTypeDetails, FunctionDetails, DomainDetails, RangeDetails, };
|
17
17
|
export type { TableColumn } from "./kinds/table.ts";
|
@@ -92,5 +92,8 @@ export declare class Extractor {
|
|
92
92
|
* @param options - Optional options
|
93
93
|
* @returns A record of all the schemas extracted, indexed by schema name.
|
94
94
|
*/
|
95
|
-
extractSchemas(options?: ExtractSchemaOptions): Promise<
|
95
|
+
extractSchemas(options?: ExtractSchemaOptions): Promise<{
|
96
|
+
schemas: Record<string, Schema>;
|
97
|
+
queryCount: number;
|
98
|
+
}>;
|
96
99
|
}
|
package/lib/extractor/index.js
CHANGED
@@ -11,7 +11,7 @@ import extractDomain, {} from "./kinds/domain.js";
|
|
11
11
|
import extractRange, {} from "./kinds/range.js";
|
12
12
|
import fetchTypes from "./fetchTypes.js";
|
13
13
|
export { pgTypeKinds } from "./pgtype.js";
|
14
|
-
import {
|
14
|
+
import { Canonical } from "./canonicalise/index.js";
|
15
15
|
export { Canonical };
|
16
16
|
export { FunctionReturnTypeKind } from "./kinds/function.js";
|
17
17
|
const emptySchema = {
|
@@ -133,13 +133,11 @@ export class Extractor {
|
|
133
133
|
}
|
134
134
|
schemas[p.schemaName][p.kind] = [...schemas[p.schemaName][p.kind], p];
|
135
135
|
}
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
// :
|
140
|
-
schemas;
|
136
|
+
// resolve all canonical types and patch the results into their placeholders
|
137
|
+
await db.resolve();
|
138
|
+
const queryCount = db.queryCount;
|
141
139
|
options?.onProgressEnd?.();
|
142
140
|
await db.close();
|
143
|
-
return
|
141
|
+
return { schemas, queryCount };
|
144
142
|
}
|
145
143
|
}
|
@@ -2,7 +2,7 @@ const extractComposite = async (db, composite) => {
|
|
2
2
|
// Form the fully qualified type name
|
3
3
|
const fullTypeName = `"${composite.schemaName}"."${composite.name}"`;
|
4
4
|
// Get canonical type information with all the metadata
|
5
|
-
const
|
5
|
+
const canonical = db.enqueue(fullTypeName);
|
6
6
|
// Return the composite type with its canonical representation
|
7
7
|
return {
|
8
8
|
...composite,
|
@@ -2,7 +2,7 @@ const extractDomain = async (db, domain) => {
|
|
2
2
|
// Form the fully qualified type name
|
3
3
|
const fullTypeName = `"${domain.schemaName}"."${domain.name}"`;
|
4
4
|
// Get canonical type information with all the metadata
|
5
|
-
const
|
5
|
+
const canonical = db.enqueue(fullTypeName);
|
6
6
|
// Return the composite type with its canonical representation
|
7
7
|
return {
|
8
8
|
...domain,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import type { DbAdapter } from "../adapter.ts";
|
2
2
|
import type { PgType } from "../pgtype.ts";
|
3
|
-
import type { Canonical } from "../canonicalise.ts";
|
3
|
+
import type { Canonical } from "../canonicalise/index.ts";
|
4
4
|
declare const parameterModeMap: {
|
5
5
|
readonly i: "IN";
|
6
6
|
readonly o: "OUT";
|
@@ -74,13 +74,13 @@ async function extractFunction(db, pgType) {
|
|
74
74
|
if (row.arg_names && !row.arg_modes)
|
75
75
|
row.arg_modes = row.arg_names.map(() => "i");
|
76
76
|
const argModes = row.arg_modes?.map(mode => parameterModeMap[mode]) ?? [];
|
77
|
-
const canonical_arg_types = row.arg_types ?
|
77
|
+
const canonical_arg_types = row.arg_types ? row.arg_types.map(type => db.enqueue(type)) : [];
|
78
78
|
let returnType;
|
79
79
|
const tableMatch = row.declared_return_type.match(/^TABLE\((.*)\)$/i);
|
80
80
|
if (tableMatch) {
|
81
81
|
const columnDefs = parsePostgresTableDefinition(row.declared_return_type);
|
82
82
|
const columnTypes = columnDefs.map(col => col.type);
|
83
|
-
const canonicalColumnTypes =
|
83
|
+
const canonicalColumnTypes = columnTypes.map(type => db.enqueue(type));
|
84
84
|
returnType = {
|
85
85
|
kind: FunctionReturnTypeKind.InlineTable,
|
86
86
|
columns: columnDefs.map((col, i) => ({
|
@@ -110,7 +110,7 @@ async function extractFunction(db, pgType) {
|
|
110
110
|
else if (
|
111
111
|
// "c" = composite type
|
112
112
|
row.return_type_relation_kind === "c") {
|
113
|
-
const canonicalReturnType =
|
113
|
+
const canonicalReturnType = db.enqueue(row.return_type_string);
|
114
114
|
returnType = {
|
115
115
|
kind: FunctionReturnTypeKind.Regular,
|
116
116
|
type: canonicalReturnType,
|
@@ -119,19 +119,17 @@ async function extractFunction(db, pgType) {
|
|
119
119
|
}
|
120
120
|
else {
|
121
121
|
console.warn(`Composite return type '${row.return_type_string}' has unexpected relkind '${row.return_type_relation_kind}' for function ${pgType.schemaName}.${row.name}`);
|
122
|
-
const canonicalReturnType = (await db.canonicalise([row.return_type_string]))[0];
|
123
122
|
returnType = {
|
124
123
|
kind: FunctionReturnTypeKind.Regular,
|
125
|
-
type:
|
124
|
+
type: db.enqueue(row.return_type_string),
|
126
125
|
isSet: row.returns_set,
|
127
126
|
};
|
128
127
|
}
|
129
128
|
}
|
130
129
|
else {
|
131
|
-
const canonicalReturnType = (await db.canonicalise([row.return_type_string]))[0];
|
132
130
|
returnType = {
|
133
131
|
kind: FunctionReturnTypeKind.Regular,
|
134
|
-
type:
|
132
|
+
type: db.enqueue(row.return_type_string),
|
135
133
|
isSet: row.returns_set,
|
136
134
|
};
|
137
135
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import type { DbAdapter } from "../adapter.ts";
|
2
2
|
import type { PgType } from "../pgtype.ts";
|
3
|
-
import type { Canonical } from "../canonicalise.ts";
|
3
|
+
import type { Canonical } from "../canonicalise/index.ts";
|
4
4
|
export interface MaterializedViewColumn {
|
5
5
|
name: string;
|
6
6
|
type: Canonical;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
const extractMaterializedView = async (db, mview) => {
|
2
|
-
//
|
2
|
+
// Query for columns (using pg_attribute for potentially more accurate nullability)
|
3
3
|
const columnQuery = await db.query(`
|
4
4
|
SELECT
|
5
5
|
attr.attname AS "name",
|
@@ -23,17 +23,14 @@ const extractMaterializedView = async (db, mview) => {
|
|
23
23
|
AND NOT attr.attisdropped
|
24
24
|
ORDER BY attr.attnum;
|
25
25
|
`, [mview.name, mview.schemaName]);
|
26
|
-
|
27
|
-
const definedTypes = columnQuery.map(row => row.definedType);
|
28
|
-
const canonicalTypes = await db.canonicalise(definedTypes);
|
29
|
-
const columns = columnQuery.map((row, index) => ({
|
26
|
+
const columns = columnQuery.map(row => ({
|
30
27
|
name: row.name,
|
31
|
-
type:
|
28
|
+
type: db.enqueue(row.definedType),
|
32
29
|
isNullable: row.isNullable,
|
33
30
|
ordinalPosition: row.ordinalPosition,
|
34
31
|
comment: row.comment,
|
35
32
|
}));
|
36
|
-
//
|
33
|
+
// Query for materialized view definition, comment, and properties
|
37
34
|
const mviewInfoQuery = await db.query(`
|
38
35
|
SELECT
|
39
36
|
m.definition,
|
@@ -1,8 +1,7 @@
|
|
1
1
|
const extractRange = async (db, range) => {
|
2
2
|
// Form the fully qualified type name
|
3
3
|
const fullTypeName = `"${range.schemaName}"."${range.name}"`;
|
4
|
-
|
5
|
-
const [canonical] = await db.canonicalise([fullTypeName]);
|
4
|
+
const canonical = db.enqueue(fullTypeName);
|
6
5
|
// Return the composite type with its canonical representation
|
7
6
|
return {
|
8
7
|
...range,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { DbAdapter } from "../adapter.ts";
|
2
2
|
import type { PgType } from "../pgtype.ts";
|
3
|
-
import type { Canonical } from "../canonicalise.ts";
|
3
|
+
import type { Canonical } from "../canonicalise/index.ts";
|
4
4
|
export declare const updateActionMap: {
|
5
5
|
readonly a: "NO ACTION";
|
6
6
|
readonly r: "RESTRICT";
|
@@ -105,14 +105,10 @@ const extractTable = async (db, table) => {
|
|
105
105
|
AND NOT attr.attisdropped
|
106
106
|
ORDER BY col.ordinal_position;
|
107
107
|
`, [table.name, table.schemaName]);
|
108
|
-
// Get the expanded type names from the query result
|
109
|
-
const definedTypes = columnsQuery.map(row => row.definedType);
|
110
|
-
// Use canonicaliseTypes to get detailed type information
|
111
|
-
const canonicalTypes = await db.canonicalise(definedTypes);
|
112
108
|
// Combine the column information with the canonical type information
|
113
|
-
const columns = columnsQuery.map(
|
109
|
+
const columns = columnsQuery.map(row => ({
|
114
110
|
name: row.name,
|
115
|
-
type:
|
111
|
+
type: db.enqueue(row.definedType),
|
116
112
|
comment: row.comment,
|
117
113
|
defaultValue: row.defaultValue,
|
118
114
|
isPrimaryKey: row.isPrimaryKey,
|
@@ -122,7 +118,6 @@ const extractTable = async (db, table) => {
|
|
122
118
|
isIdentity: row.isIdentity,
|
123
119
|
isUpdatable: row.isUpdatable,
|
124
120
|
generated: row.generated,
|
125
|
-
informationSchemaValue: row.informationSchemaValue,
|
126
121
|
}));
|
127
122
|
const indicesQuery = await db.query(`
|
128
123
|
WITH index_columns AS (
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import type { DbAdapter } from "../adapter.ts";
|
2
2
|
import type { PgType } from "../pgtype.ts";
|
3
|
-
import type { Canonical } from "../canonicalise.ts";
|
3
|
+
import type { Canonical } from "../canonicalise/index.ts";
|
4
4
|
export interface ViewColumn {
|
5
5
|
name: string;
|
6
6
|
type: Canonical;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
const extractView = async (db, view) => {
|
2
|
-
//
|
2
|
+
// Query for columns (information_schema.columns + pg_attribute)
|
3
3
|
const columnQuery = await db.query(`
|
4
4
|
SELECT
|
5
5
|
col.column_name AS "name",
|
@@ -22,17 +22,14 @@ const extractView = async (db, view) => {
|
|
22
22
|
AND NOT attr.attisdropped -- Exclude dropped columns
|
23
23
|
ORDER BY col.ordinal_position;
|
24
24
|
`, [view.name, view.schemaName]);
|
25
|
-
|
26
|
-
const definedTypes = columnQuery.map(row => row.definedType);
|
27
|
-
const canonicalTypes = await db.canonicalise(definedTypes);
|
28
|
-
const columns = columnQuery.map((row, index) => ({
|
25
|
+
const columns = columnQuery.map(row => ({
|
29
26
|
name: row.name,
|
30
|
-
type:
|
27
|
+
type: db.enqueue(row.definedType),
|
31
28
|
isNullable: row.isNullable,
|
32
29
|
isUpdatable: row.isUpdatable,
|
33
30
|
ordinalPosition: row.ordinalPosition,
|
34
31
|
}));
|
35
|
-
//
|
32
|
+
// Query for view definition, comment, and other properties
|
36
33
|
const viewInfoQuery = await db.query(`
|
37
34
|
SELECT
|
38
35
|
d.description AS "comment",
|
package/lib/imports.test.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Canonical } from "./extractor/canonicalise.js";
|
1
|
+
import { Canonical } from "./extractor/canonicalise/index.js";
|
2
2
|
import { Import, ImportList } from "./imports.js";
|
3
3
|
import { describe, it, expect } from "bun:test";
|
4
4
|
const files = {
|
@@ -92,8 +92,7 @@ describe("Import Class", () => {
|
|
92
92
|
},
|
93
93
|
});
|
94
94
|
expect(importInstance).toBeInstanceOf(Import);
|
95
|
-
expect(typeof importInstance.from === "function" ||
|
96
|
-
typeof importInstance.from === "string").toBe(true);
|
95
|
+
expect(typeof importInstance.from === "function" || typeof importInstance.from === "string").toBe(true);
|
97
96
|
if (typeof importInstance.from === "function") {
|
98
97
|
const generatedPath = importInstance.from(files);
|
99
98
|
expect(generatedPath).toBe("../enums/testEnum.ts");
|
@@ -113,8 +112,7 @@ describe("Import Class", () => {
|
|
113
112
|
},
|
114
113
|
});
|
115
114
|
expect(importInstance).toBeInstanceOf(Import);
|
116
|
-
expect(typeof importInstance.from === "function" ||
|
117
|
-
typeof importInstance.from === "string").toBe(true);
|
115
|
+
expect(typeof importInstance.from === "function" || typeof importInstance.from === "string").toBe(true);
|
118
116
|
if (typeof importInstance.from === "function") {
|
119
117
|
const generatedPath = importInstance.from(files);
|
120
118
|
expect(generatedPath).toBe("../enums/testEnum.ts");
|
@@ -141,19 +139,13 @@ describe("ImportList Class", () => {
|
|
141
139
|
expect(importList.imports[0]).toBe(newImport);
|
142
140
|
});
|
143
141
|
it("should merge import lists correctly", () => {
|
144
|
-
const list1 = new ImportList([
|
145
|
-
|
146
|
-
]);
|
147
|
-
const list2 = new ImportList([
|
148
|
-
new Import({ from: "module2", namedImports: ["b"] }),
|
149
|
-
]);
|
142
|
+
const list1 = new ImportList([new Import({ from: "module1", namedImports: ["a"] })]);
|
143
|
+
const list2 = new ImportList([new Import({ from: "module2", namedImports: ["b"] })]);
|
150
144
|
const mergedList = ImportList.merge([list1, list2]);
|
151
145
|
expect(mergedList.imports).toHaveLength(2);
|
152
146
|
});
|
153
147
|
it("should merge import lists correctly with empty list", () => {
|
154
|
-
const list1 = new ImportList([
|
155
|
-
new Import({ from: "module1", namedImports: ["a"] }),
|
156
|
-
]);
|
148
|
+
const list1 = new ImportList([new Import({ from: "module1", namedImports: ["a"] })]);
|
157
149
|
const list2 = new ImportList([]);
|
158
150
|
const mergedList = ImportList.merge([list1, list2]);
|
159
151
|
expect(mergedList.imports).toHaveLength(1);
|
package/lib/index.js
CHANGED
@@ -217,8 +217,8 @@ export async function generate(opts, generators) {
|
|
217
217
|
const out = validated.out;
|
218
218
|
const extractor = new Extractor(opts);
|
219
219
|
const start = performance.now();
|
220
|
-
const schemas = await extractor.extractSchemas();
|
221
|
-
console.log("Extracted schemas %s\n", time(start));
|
220
|
+
const { schemas, queryCount } = await extractor.extractSchemas();
|
221
|
+
console.log("Extracted schemas %s (made %s queries)\n", time(start), queryCount);
|
222
222
|
console.info("Generators enabled: %s\n", validated.generators.join(", "));
|
223
223
|
generators = validated.generators.map(generator => builtin_generators[generator]).concat(generators ?? []);
|
224
224
|
console.log("Clearing directory and generating schemas at '%s'\n", out);
|
package/lib/util.d.ts
CHANGED
@@ -1,10 +1,4 @@
|
|
1
1
|
export declare const unreachable: (value: never) => never;
|
2
|
-
export declare class Deferred<T> {
|
3
|
-
resolve: (value: T) => void;
|
4
|
-
reject: (reason?: any) => void;
|
5
|
-
promise: Promise<T>;
|
6
|
-
constructor();
|
7
|
-
}
|
8
2
|
export declare const eq: <T>(a: T, b: T) => boolean;
|
9
3
|
export declare const toPascalCase: (str: string) => string;
|
10
4
|
export declare const to_snake_case: (str: string) => string;
|
@@ -20,4 +14,7 @@ export type Simplify<T> = {
|
|
20
14
|
export declare const parens: (str: string, type?: string) => string;
|
21
15
|
export declare const quote: (str: string, using?: string) => string;
|
22
16
|
export declare const quoteI: (str: string, using?: string) => string;
|
17
|
+
export declare const removeNulls: <T>(o: T) => T;
|
18
|
+
export declare const pos: (num: number) => number | undefined;
|
19
|
+
export declare const minifyQuery: (query: string) => string;
|
23
20
|
export {};
|
package/lib/util.js
CHANGED
@@ -1,17 +1,6 @@
|
|
1
1
|
export const unreachable = (value) => {
|
2
2
|
throw new Error(`Fatal: Reached unreachable code: ${value}`);
|
3
3
|
};
|
4
|
-
export class Deferred {
|
5
|
-
resolve;
|
6
|
-
reject;
|
7
|
-
promise;
|
8
|
-
constructor() {
|
9
|
-
this.promise = new Promise((resolve, reject) => {
|
10
|
-
this.resolve = resolve;
|
11
|
-
this.reject = reject;
|
12
|
-
});
|
13
|
-
}
|
14
|
-
}
|
15
4
|
export const eq = (a, b) => {
|
16
5
|
if (a === b)
|
17
6
|
return true;
|
@@ -142,3 +131,18 @@ const isIdentifierInvalid = (str) => {
|
|
142
131
|
export const parens = (str, type = "()") => `${type[0]}${str}${type[1]}`;
|
143
132
|
export const quote = (str, using = '"') => `${using}${str.replaceAll(using, "\\" + using)}${using}`;
|
144
133
|
export const quoteI = (str, using = '"') => (isIdentifierInvalid(str) ? quote(str, using) : str);
|
134
|
+
export const removeNulls = (o) => {
|
135
|
+
for (const key in o)
|
136
|
+
if (o[key] == null)
|
137
|
+
delete o[key];
|
138
|
+
return o;
|
139
|
+
};
|
140
|
+
export const pos = (num) => (num < 0 ? undefined : num);
|
141
|
+
export const minifyQuery = (query) => {
|
142
|
+
return query
|
143
|
+
.split("\n")
|
144
|
+
.map(line => line.slice(0, pos(line.indexOf("--"))))
|
145
|
+
.join("\n")
|
146
|
+
.replaceAll(/\s+/g, " ")
|
147
|
+
.trim();
|
148
|
+
};
|
package/package.json
CHANGED
@@ -1,110 +0,0 @@
|
|
1
|
-
import { DbAdapter } from "./adapter.ts";
|
2
|
-
interface ParsedTypeName {
|
3
|
-
/** Name after removing modifiers and brackets, e.g. "varchar" in "varchar(50)" */
|
4
|
-
base: string;
|
5
|
-
/** Modifiers, e.g. "50" in "varchar(50)" */
|
6
|
-
modifiers: string | null;
|
7
|
-
/** Number of dimensions from explicit brackets, e.g. 1 in "int[]" */
|
8
|
-
dimensions: number;
|
9
|
-
/** Original type name, e.g. "varchar(50)" */
|
10
|
-
original: string;
|
11
|
-
}
|
12
|
-
/**
|
13
|
-
* Parses a PostgreSQL type name string to extract its base name,
|
14
|
-
* modifiers, and dimensions from explicit '[]' brackets.
|
15
|
-
*
|
16
|
-
* Examples:
|
17
|
-
*
|
18
|
-
* - `parseTypeName("varchar(50)")`
|
19
|
-
*
|
20
|
-
* `⤷ { baseTypeName: "varchar", modifiers: "50", dimensions: 0, originalTypeName: "varchar(50)" }`
|
21
|
-
*
|
22
|
-
* - `parseTypeName("int[]")`
|
23
|
-
*
|
24
|
-
* `⤷ { baseTypeName: "int", modifiers: null, dimensions: 1, originalTypeName: "int[]" }`
|
25
|
-
*
|
26
|
-
* - `parseTypeName("public.my_table[][]")`
|
27
|
-
*
|
28
|
-
* `⤷ { baseTypeName: "public.my_table", modifiers: null, dimensions: 2, originalTypeName: "public.my_table[][]" }`
|
29
|
-
*
|
30
|
-
* - `parseTypeName("numeric(10, 2)[]")`
|
31
|
-
*
|
32
|
-
* `⤷ { baseTypeName: "numeric", modifiers: "10, 2", dimensions: 1, originalTypeName: "numeric(10, 2)[]" }`
|
33
|
-
*
|
34
|
-
* - `parseTypeName("geometry(Point, 4326)")`
|
35
|
-
*
|
36
|
-
* `⤷ { baseTypeName: "geometry", modifiers: "Point, 4326", dimensions: 0, originalTypeName: "geometry(Point, 4326)" }`
|
37
|
-
*
|
38
|
-
* - `parseTypeName("_text")`
|
39
|
-
*
|
40
|
-
* `⤷ { baseTypeName: "_text", modifiers: null, dimensions: 0, originalTypeName: "_text" }`
|
41
|
-
*
|
42
|
-
* Internal arrays aren't handled here
|
43
|
-
*/
|
44
|
-
export declare function parseTypeName(type: string): ParsedTypeName;
|
45
|
-
export declare namespace Canonical {
|
46
|
-
enum Kind {
|
47
|
-
Base = "base",
|
48
|
-
Composite = "composite",
|
49
|
-
Domain = "domain",
|
50
|
-
Enum = "enum",
|
51
|
-
Range = "range",
|
52
|
-
Pseudo = "pseudo",
|
53
|
-
Unknown = "unknown"
|
54
|
-
}
|
55
|
-
interface Abstract {
|
56
|
-
original_type: string;
|
57
|
-
canonical_name: string;
|
58
|
-
schema: string;
|
59
|
-
name: string;
|
60
|
-
kind: Kind;
|
61
|
-
dimensions: number;
|
62
|
-
modifiers?: string | null;
|
63
|
-
}
|
64
|
-
interface Base extends Abstract {
|
65
|
-
kind: Kind.Base;
|
66
|
-
}
|
67
|
-
interface Enum extends Abstract {
|
68
|
-
kind: Kind.Enum;
|
69
|
-
enum_values: string[];
|
70
|
-
}
|
71
|
-
interface CompositeAttribute {
|
72
|
-
name: string;
|
73
|
-
index: number;
|
74
|
-
type: Canonical;
|
75
|
-
comment: string | null;
|
76
|
-
defaultValue: any;
|
77
|
-
isNullable: boolean;
|
78
|
-
/**
|
79
|
-
* Whether the attribute is an identity attribute.
|
80
|
-
*/
|
81
|
-
isIdentity: boolean;
|
82
|
-
/**
|
83
|
-
* Behavior of the generated attribute. "ALWAYS" if always generated,
|
84
|
-
* "NEVER" if never generated, "BY DEFAULT" if generated when a value
|
85
|
-
* is not provided.
|
86
|
-
*/
|
87
|
-
generated: "ALWAYS" | "NEVER" | "BY DEFAULT";
|
88
|
-
}
|
89
|
-
interface Composite extends Abstract {
|
90
|
-
kind: Kind.Composite;
|
91
|
-
attributes: CompositeAttribute[];
|
92
|
-
}
|
93
|
-
interface Domain extends Abstract {
|
94
|
-
kind: Kind.Domain;
|
95
|
-
domain_base_type: Canonical;
|
96
|
-
}
|
97
|
-
interface Range extends Abstract {
|
98
|
-
kind: Kind.Range;
|
99
|
-
range_subtype: Canonical;
|
100
|
-
}
|
101
|
-
interface Pseudo extends Abstract {
|
102
|
-
kind: Kind.Pseudo;
|
103
|
-
}
|
104
|
-
}
|
105
|
-
export type Canonical = Canonical.Base | Canonical.Enum | Canonical.Composite | Canonical.Domain | Canonical.Range | Canonical.Pseudo;
|
106
|
-
type ExclusiveCanonProps = Omit<Canonical, keyof Canonical.Abstract>;
|
107
|
-
export declare const canonicalise: (db: DbAdapter, types: string[], rawTypeCache: Map<string, Promise<Canonical>>, canonicalCache: Map<string, Promise<ExclusiveCanonProps>>) => Promise<Canonical[]>;
|
108
|
-
export declare const oidsToQualifiedNames: (db: DbAdapter, oids: number[]) => Promise<string[]>;
|
109
|
-
export declare const canonicaliseFromOids: (db: DbAdapter, oids: number[]) => Promise<Canonical[]>;
|
110
|
-
export {};
|