sql-typechecker 0.0.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.
- package/.envrc +2 -0
- package/esbuild.js +12 -0
- package/package.json +28 -0
- package/sample/nested/sample2.sql +7 -0
- package/sample/out.ts +13 -0
- package/sample/sample1.sql +10 -0
- package/school/out.ts +59 -0
- package/school/sql.sql +985 -0
- package/shell.nix +16 -0
- package/src/builtincasts.ts +277 -0
- package/src/builtinoperators.ts +5144 -0
- package/src/builtinunaryoperators.ts +291 -0
- package/src/cli.ts +187 -0
- package/src/readme.md +23 -0
- package/src/typecheck.ts +1869 -0
- package/template1.sql +43 -0
- package/test/test.ts +1378 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { unaryOp } from "./typecheck";
|
|
2
|
+
|
|
3
|
+
const builtinunaryoperatorsFromSyntax: unaryOp[] = [
|
|
4
|
+
// {
|
|
5
|
+
// name: { name: "IS NULL" },
|
|
6
|
+
// operand: { kind: "nullable", typevar: { kind: "anyscalar" } },
|
|
7
|
+
// result: { kind: "scalar", name: { name: "boolean" } },
|
|
8
|
+
// description: "is NULL check",
|
|
9
|
+
// },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const builtinunaryoperatorsFromSchema: unaryOp[] = [
|
|
13
|
+
{
|
|
14
|
+
name: { name: "!" },
|
|
15
|
+
operand: { kind: "scalar", name: { name: "bigint" } },
|
|
16
|
+
result: { kind: "scalar", name: { name: "numeric" } },
|
|
17
|
+
description: "factorial",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: { name: "!!" },
|
|
21
|
+
operand: { kind: "scalar", name: { name: "bigint" } },
|
|
22
|
+
result: { kind: "scalar", name: { name: "numeric" } },
|
|
23
|
+
description: "deprecated, use ! instead",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: { name: "!!" },
|
|
27
|
+
operand: { kind: "scalar", name: { name: "tsquery" } },
|
|
28
|
+
result: { kind: "scalar", name: { name: "tsquery" } },
|
|
29
|
+
description: "NOT tsquery",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: { name: "#" },
|
|
33
|
+
operand: { kind: "scalar", name: { name: "path" } },
|
|
34
|
+
result: { kind: "scalar", name: { name: "integer" } },
|
|
35
|
+
description: "number of points",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: { name: "#" },
|
|
39
|
+
operand: { kind: "scalar", name: { name: "polygon" } },
|
|
40
|
+
result: { kind: "scalar", name: { name: "integer" } },
|
|
41
|
+
description: "number of points",
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
name: { name: "+" },
|
|
46
|
+
operand: { kind: "scalar", name: { name: "bigint" } },
|
|
47
|
+
result: { kind: "scalar", name: { name: "bigint" } },
|
|
48
|
+
description: "unary plus",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: { name: "+" },
|
|
52
|
+
operand: { kind: "scalar", name: { name: "double precision" } },
|
|
53
|
+
result: { kind: "scalar", name: { name: "double precision" } },
|
|
54
|
+
description: "unary plus",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: { name: "+" },
|
|
58
|
+
operand: { kind: "scalar", name: { name: "integer" } },
|
|
59
|
+
result: { kind: "scalar", name: { name: "integer" } },
|
|
60
|
+
description: "unary plus",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: { name: "+" },
|
|
64
|
+
operand: { kind: "scalar", name: { name: "numeric" } },
|
|
65
|
+
result: { kind: "scalar", name: { name: "numeric" } },
|
|
66
|
+
description: "unary plus",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: { name: "+" },
|
|
70
|
+
operand: { kind: "scalar", name: { name: "real" } },
|
|
71
|
+
result: { kind: "scalar", name: { name: "real" } },
|
|
72
|
+
description: "unary plus",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: { name: "+" },
|
|
76
|
+
operand: { kind: "scalar", name: { name: "smallint" } },
|
|
77
|
+
result: { kind: "scalar", name: { name: "smallint" } },
|
|
78
|
+
description: "unary plus",
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
{
|
|
82
|
+
name: { name: "-" },
|
|
83
|
+
operand: { kind: "scalar", name: { name: "bigint" } },
|
|
84
|
+
result: { kind: "scalar", name: { name: "bigint" } },
|
|
85
|
+
description: "negate",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: { name: "-" },
|
|
89
|
+
operand: { kind: "scalar", name: { name: "double precision" } },
|
|
90
|
+
result: { kind: "scalar", name: { name: "double precision" } },
|
|
91
|
+
description: "negate",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: { name: "-" },
|
|
95
|
+
operand: { kind: "scalar", name: { name: "integer" } },
|
|
96
|
+
result: { kind: "scalar", name: { name: "integer" } },
|
|
97
|
+
description: "negate",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: { name: "-" },
|
|
101
|
+
operand: { kind: "scalar", name: { name: "interval" } },
|
|
102
|
+
result: { kind: "scalar", name: { name: "interval" } },
|
|
103
|
+
description: "negate",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: { name: "-" },
|
|
107
|
+
operand: { kind: "scalar", name: { name: "numeric" } },
|
|
108
|
+
result: { kind: "scalar", name: { name: "numeric" } },
|
|
109
|
+
description: "negate",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: { name: "-" },
|
|
113
|
+
operand: { kind: "scalar", name: { name: "real" } },
|
|
114
|
+
result: { kind: "scalar", name: { name: "real" } },
|
|
115
|
+
description: "negate",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: { name: "-" },
|
|
119
|
+
operand: { kind: "scalar", name: { name: "smallint" } },
|
|
120
|
+
result: { kind: "scalar", name: { name: "smallint" } },
|
|
121
|
+
description: "negate",
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
{
|
|
125
|
+
name: { name: "?-" },
|
|
126
|
+
operand: { kind: "scalar", name: { name: "line" } },
|
|
127
|
+
result: { kind: "scalar", name: { name: "boolean" } },
|
|
128
|
+
description: "horizontal",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: { name: "?-" },
|
|
132
|
+
operand: { kind: "scalar", name: { name: "lseg" } },
|
|
133
|
+
result: { kind: "scalar", name: { name: "boolean" } },
|
|
134
|
+
description: "horizontal",
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
{
|
|
138
|
+
name: { name: "?|" },
|
|
139
|
+
operand: { kind: "scalar", name: { name: "line" } },
|
|
140
|
+
result: { kind: "scalar", name: { name: "boolean" } },
|
|
141
|
+
description: "vertical",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: { name: "?|" },
|
|
145
|
+
operand: { kind: "scalar", name: { name: "lseg" } },
|
|
146
|
+
result: { kind: "scalar", name: { name: "boolean" } },
|
|
147
|
+
description: "vertical",
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
{
|
|
151
|
+
name: { name: "@" },
|
|
152
|
+
operand: { kind: "scalar", name: { name: "bigint" } },
|
|
153
|
+
result: { kind: "scalar", name: { name: "bigint" } },
|
|
154
|
+
description: "absolute value",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: { name: "@" },
|
|
158
|
+
operand: { kind: "scalar", name: { name: "double precision" } },
|
|
159
|
+
result: { kind: "scalar", name: { name: "double precision" } },
|
|
160
|
+
description: "absolute value",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: { name: "@" },
|
|
164
|
+
operand: { kind: "scalar", name: { name: "integer" } },
|
|
165
|
+
result: { kind: "scalar", name: { name: "integer" } },
|
|
166
|
+
description: "absolute value",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: { name: "@" },
|
|
170
|
+
operand: { kind: "scalar", name: { name: "numeric" } },
|
|
171
|
+
result: { kind: "scalar", name: { name: "numeric" } },
|
|
172
|
+
description: "absolute value",
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: { name: "@" },
|
|
176
|
+
operand: { kind: "scalar", name: { name: "real" } },
|
|
177
|
+
result: { kind: "scalar", name: { name: "real" } },
|
|
178
|
+
description: "absolute value",
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: { name: "@" },
|
|
182
|
+
operand: { kind: "scalar", name: { name: "smallint" } },
|
|
183
|
+
result: { kind: "scalar", name: { name: "smallint" } },
|
|
184
|
+
description: "absolute value",
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: { name: "@-@" },
|
|
188
|
+
operand: { kind: "scalar", name: { name: "lseg" } },
|
|
189
|
+
result: { kind: "scalar", name: { name: "double precision" } },
|
|
190
|
+
description: "distance between endpoints",
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: { name: "@-@" },
|
|
194
|
+
operand: { kind: "scalar", name: { name: "path" } },
|
|
195
|
+
result: { kind: "scalar", name: { name: "double precision" } },
|
|
196
|
+
description: "sum of path segment lengths",
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
{
|
|
200
|
+
name: { name: "@@" },
|
|
201
|
+
operand: { kind: "scalar", name: { name: "box" } },
|
|
202
|
+
result: { kind: "scalar", name: { name: "point" } },
|
|
203
|
+
description: "center of",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: { name: "@@" },
|
|
207
|
+
operand: { kind: "scalar", name: { name: "circle" } },
|
|
208
|
+
result: { kind: "scalar", name: { name: "point" } },
|
|
209
|
+
description: "center of",
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: { name: "@@" },
|
|
213
|
+
operand: { kind: "scalar", name: { name: "lseg" } },
|
|
214
|
+
result: { kind: "scalar", name: { name: "point" } },
|
|
215
|
+
description: "center of",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: { name: "@@" },
|
|
219
|
+
operand: { kind: "scalar", name: { name: "path" } },
|
|
220
|
+
result: { kind: "scalar", name: { name: "point" } },
|
|
221
|
+
description: "center of",
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: { name: "@@" },
|
|
225
|
+
operand: { kind: "scalar", name: { name: "polygon" } },
|
|
226
|
+
result: { kind: "scalar", name: { name: "point" } },
|
|
227
|
+
description: "center of",
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
{
|
|
231
|
+
name: { name: "|" },
|
|
232
|
+
operand: { kind: "scalar", name: { name: "tinterval" } },
|
|
233
|
+
result: { kind: "scalar", name: { name: "abstime" } },
|
|
234
|
+
description: "start of interval",
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
{
|
|
238
|
+
name: { name: "|/" },
|
|
239
|
+
operand: { kind: "scalar", name: { name: "double precision" } },
|
|
240
|
+
result: { kind: "scalar", name: { name: "double precision" } },
|
|
241
|
+
description: "square root",
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
{
|
|
245
|
+
name: { name: "||/" },
|
|
246
|
+
operand: { kind: "scalar", name: { name: "double precision" } },
|
|
247
|
+
result: { kind: "scalar", name: { name: "double precision" } },
|
|
248
|
+
description: "cube root",
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
{
|
|
252
|
+
name: { name: "~" },
|
|
253
|
+
operand: { kind: "scalar", name: { name: "bigint" } },
|
|
254
|
+
result: { kind: "scalar", name: { name: "bigint" } },
|
|
255
|
+
description: "bitwise not",
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: { name: "~" },
|
|
259
|
+
operand: { kind: "scalar", name: { name: "bit" } },
|
|
260
|
+
result: { kind: "scalar", name: { name: "bit" } },
|
|
261
|
+
description: "bitwise not",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: { name: "~" },
|
|
265
|
+
operand: { kind: "scalar", name: { name: "inet" } },
|
|
266
|
+
result: { kind: "scalar", name: { name: "inet" } },
|
|
267
|
+
description: "bitwise not",
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: { name: "~" },
|
|
271
|
+
operand: { kind: "scalar", name: { name: "integer" } },
|
|
272
|
+
result: { kind: "scalar", name: { name: "integer" } },
|
|
273
|
+
description: "bitwise not",
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: { name: "~" },
|
|
277
|
+
operand: { kind: "scalar", name: { name: "macaddr" } },
|
|
278
|
+
result: { kind: "scalar", name: { name: "macaddr" } },
|
|
279
|
+
description: "bitwise not",
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
name: { name: "~" },
|
|
283
|
+
operand: { kind: "scalar", name: { name: "smallint" } },
|
|
284
|
+
result: { kind: "scalar", name: { name: "smallint" } },
|
|
285
|
+
description: "bitwise not",
|
|
286
|
+
},
|
|
287
|
+
];
|
|
288
|
+
|
|
289
|
+
export const builtinUnaryOperators = builtinunaryoperatorsFromSyntax.concat(
|
|
290
|
+
builtinunaryoperatorsFromSchema
|
|
291
|
+
);
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import * as fs from "fs/promises";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { CreateFunctionStatement, parse, Statement } from "pgsql-ast-parser";
|
|
4
|
+
import {
|
|
5
|
+
checkAllCasesHandled,
|
|
6
|
+
doCreateFunction,
|
|
7
|
+
functionType,
|
|
8
|
+
parseSetupScripts,
|
|
9
|
+
showSqlType,
|
|
10
|
+
showType,
|
|
11
|
+
Type,
|
|
12
|
+
} from "./typecheck";
|
|
13
|
+
import * as prettier from "prettier";
|
|
14
|
+
|
|
15
|
+
go();
|
|
16
|
+
|
|
17
|
+
async function findSqlFiles(dir: string): Promise<string[]> {
|
|
18
|
+
const inThisDir = await fs.readdir(dir);
|
|
19
|
+
const res: string[] = [];
|
|
20
|
+
for (let p of inThisDir) {
|
|
21
|
+
const fullP = path.join(dir, p);
|
|
22
|
+
if (fullP.endsWith(".sql")) {
|
|
23
|
+
res.push(fullP);
|
|
24
|
+
} else {
|
|
25
|
+
const stat = await fs.stat(fullP);
|
|
26
|
+
if (stat.isDirectory()) {
|
|
27
|
+
const inSubFolder = await findSqlFiles(fullP);
|
|
28
|
+
res.push(...inSubFolder);
|
|
29
|
+
} else {
|
|
30
|
+
// not a sql file, not a directory
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return res;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isCreateFunctionStatement(
|
|
38
|
+
st: Statement
|
|
39
|
+
): st is CreateFunctionStatement {
|
|
40
|
+
return st.type === "create function";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function showTypeAsTypescriptType(t: Type): string {
|
|
44
|
+
if (t.kind === "set") {
|
|
45
|
+
return (
|
|
46
|
+
"{" +
|
|
47
|
+
t.fields
|
|
48
|
+
.map(
|
|
49
|
+
(f) =>
|
|
50
|
+
(f.name === null ? `"?": ` : `"${f.name.name}": `) +
|
|
51
|
+
showTypeAsTypescriptType(f.type)
|
|
52
|
+
)
|
|
53
|
+
.join(", ") +
|
|
54
|
+
"}"
|
|
55
|
+
);
|
|
56
|
+
} else {
|
|
57
|
+
if (t.kind === "array") {
|
|
58
|
+
return "(" + showTypeAsTypescriptType(t.typevar) + ")" + "[]";
|
|
59
|
+
} else if (t.kind === "nullable") {
|
|
60
|
+
return showTypeAsTypescriptType(t.typevar) + " | null";
|
|
61
|
+
} else if (t.kind === "scalar") {
|
|
62
|
+
if (
|
|
63
|
+
["numeric", "bigint", "smallint", "integer", "real", "double"].includes(
|
|
64
|
+
t.name.name
|
|
65
|
+
)
|
|
66
|
+
) {
|
|
67
|
+
return "number";
|
|
68
|
+
} else if (
|
|
69
|
+
["text", "name", "char", "character", "varchar", "nvarchar"].includes(
|
|
70
|
+
t.name.name
|
|
71
|
+
)
|
|
72
|
+
) {
|
|
73
|
+
return "string";
|
|
74
|
+
} else if (["bytea"].includes(t.name.name)) {
|
|
75
|
+
return "Buffer";
|
|
76
|
+
} else {
|
|
77
|
+
return t.name.name;
|
|
78
|
+
}
|
|
79
|
+
} else if (t.kind === "anyscalar") {
|
|
80
|
+
return "anyscalar";
|
|
81
|
+
} else {
|
|
82
|
+
return checkAllCasesHandled(t);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function functionToTypescript(f: functionType): string {
|
|
88
|
+
const returnTypeAsString =
|
|
89
|
+
f.returns.kind === "void"
|
|
90
|
+
? "void"
|
|
91
|
+
: showTypeAsTypescriptType(f.returns) + "[]";
|
|
92
|
+
|
|
93
|
+
const argsType =
|
|
94
|
+
"{" +
|
|
95
|
+
f.inputs
|
|
96
|
+
.map((k) => {
|
|
97
|
+
const paramTypeAsString = showTypeAsTypescriptType(k.type);
|
|
98
|
+
|
|
99
|
+
// console.log(`Param \$${k.name.name}:\n`, paramTypeAsString, "\n");
|
|
100
|
+
return k.name.name + ": " + paramTypeAsString;
|
|
101
|
+
})
|
|
102
|
+
.join(", ") +
|
|
103
|
+
"}";
|
|
104
|
+
|
|
105
|
+
const argsAsList = f.inputs
|
|
106
|
+
.map((i) => "${args." + i.name.name + "}")
|
|
107
|
+
.join(", ");
|
|
108
|
+
|
|
109
|
+
const argsForCreateFunction = f.inputs
|
|
110
|
+
.map((k) => k.name.name + showSqlType(k.type))
|
|
111
|
+
.join(", ");
|
|
112
|
+
|
|
113
|
+
return `
|
|
114
|
+
export function ${
|
|
115
|
+
f.name.name
|
|
116
|
+
}(pg: postgres.Sql<any>, args: ${argsType}): Promise<${returnTypeAsString}>{
|
|
117
|
+
return pg\`select ${f.name.name}(${argsAsList})\`;
|
|
118
|
+
/*
|
|
119
|
+
CREATE FUNCTION ${f.name.name}(${argsForCreateFunction}) RETURNS ${
|
|
120
|
+
f.multipleRows ? "SETOF " : ""
|
|
121
|
+
}__todo__ AS
|
|
122
|
+
$$${f.code}$$ LANGUAGE ${f.language};
|
|
123
|
+
*/
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function go() {
|
|
129
|
+
const dir = process.argv[2];
|
|
130
|
+
if (!dir) {
|
|
131
|
+
throw new Error("Please provide directory with SQL files");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const outArg = findOutArg(process.argv);
|
|
135
|
+
if (!outArg) {
|
|
136
|
+
throw new Error("Please provide -o/--out parameter");
|
|
137
|
+
}
|
|
138
|
+
const allSqlFiles = await findSqlFiles(path.resolve(process.cwd(), dir));
|
|
139
|
+
|
|
140
|
+
// console.log(`Processing files: ${allSqlFiles.join(", ")}`);
|
|
141
|
+
|
|
142
|
+
const allStatements: Statement[] = [];
|
|
143
|
+
for (let sqlFile of allSqlFiles) {
|
|
144
|
+
console.log("Processing file ${sqlFile}");
|
|
145
|
+
const fileContents = await fs.readFile(sqlFile, "utf-8");
|
|
146
|
+
const statements: Statement[] = parse(fileContents);
|
|
147
|
+
allStatements.push(...statements);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
console.log(`Processing ${allStatements.length} statements`);
|
|
151
|
+
|
|
152
|
+
const g = parseSetupScripts(allStatements);
|
|
153
|
+
|
|
154
|
+
// console.log("Global:\n", JSON.stringify(g, null, 2), "\n");
|
|
155
|
+
|
|
156
|
+
const createFunctionStatements = allStatements.filter(
|
|
157
|
+
isCreateFunctionStatement
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const outfile = await prepOutFile(path.resolve(process.cwd(), outArg));
|
|
161
|
+
|
|
162
|
+
for (let st of createFunctionStatements) {
|
|
163
|
+
const res = doCreateFunction(g, { decls: [], froms: [] }, st);
|
|
164
|
+
const writing = prettier.format(functionToTypescript(res), {
|
|
165
|
+
parser: "typescript",
|
|
166
|
+
});
|
|
167
|
+
// console.log(`Writing: ${writing}`);
|
|
168
|
+
await fs.appendFile(outfile, writing, "utf-8");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function prepOutFile(path: string): Promise<string> {
|
|
173
|
+
// const stat = await fs.stat(path);
|
|
174
|
+
// if (!stat.isFile)
|
|
175
|
+
// await fs.truncate(path);
|
|
176
|
+
await fs.writeFile(path, `import postgres from "postgres";\n`, "utf-8");
|
|
177
|
+
return path;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function findOutArg(args: string[]): string | null {
|
|
181
|
+
const flagIndex = args.findIndex((arg) => arg === "-o" || arg === "--out");
|
|
182
|
+
if (!flagIndex) {
|
|
183
|
+
return null;
|
|
184
|
+
} else {
|
|
185
|
+
return args[flagIndex + 1] || null;
|
|
186
|
+
}
|
|
187
|
+
}
|
package/src/readme.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Huidige plan:
|
|
2
|
+
|
|
3
|
+
We werken niet meer met positionele parameters (da's toch maar een lapmiddel, niet echt deel van Postgres) maar we gaan enkel functies declareren en die typechecken en daar (typescript) bindings van maken.
|
|
4
|
+
|
|
5
|
+
Daarmee weet je dus op voorhand welke parameters je hebt. Let bindings, from's etc, kunnen ook wel dingen in de context steken, maar da's wel beter afgelijnd. Die blocks zorgen er wel voor dat immutable Context's wel een goed idee zijn, zo volgen die de flow meteen mee.
|
|
6
|
+
|
|
7
|
+
Idealiter zouden we LANGUAGE plpgsql en LANGUAGE sql moeten ondersteunen!
|
|
8
|
+
-> Als we beginnen met LANGUAGE sql, dan moeten we (nog) geen parser schrijven!
|
|
9
|
+
|
|
10
|
+
Type inference:
|
|
11
|
+
* Type is mandatory in DECLARE blocks
|
|
12
|
+
* Type is mandatory in CREATE FUNCTION parameters
|
|
13
|
+
* We kunnen dus aan alle Context.decls meteen een type geven. Enkel nullability heb je niet.
|
|
14
|
+
* Of wat als we gewoon alle (user-defined) functie parameters not-nullable by default zetten, en je moet "default NULL" meegeven om ze nullable te definiëren? -> Dit is volgens mij eigenlijk het beste, maar het staat redelijk ver af van hoe Postgres het zelf doet. Op zich voor Aperi zou dit wel goed werken... YUP WE GAAN DIT DOEN
|
|
15
|
+
* Oude discussie:
|
|
16
|
+
* Als we dat immutable willen bijhouden, dan moeten we dus ook weer heel de context de hele tijd meesleuren
|
|
17
|
+
* Als we dat mutable maken, volg je niet meer de volledige control flow, maar da's ook niet echt nodig denk ik want die moeten altijd "kloppen"
|
|
18
|
+
* Oude discussie: Moeten we parameters eerste als nullable, of als not-nullable beschouwen?
|
|
19
|
+
* Indien CALLED ON NULL INPUT (=default): Alles is nullable. (NOPE ZIE VERDER)
|
|
20
|
+
* Indien RETURNS NULL ON NULL INPUT of STRICT: Niks is nullable? . (NOPE ZIE VERDER)
|
|
21
|
+
* Eigenlijk betekent dit: Als je mij ergens een NULL geeft, geef ik NULL terug. De body wordt niet uitgevoerd. Dus inderdaad, je gaat altijd in de function body zelf not-nullable zijn! Als je zo'n functie aanroept kan je echter wel NULL terugkrijgen, als een van de argumenten NULL is. Je kan dat als speciale modifier op die functie bijhouden, en als een van de argumenten nullable is, dan is het return type ook nullable.. (NOPE ZIE VERDER)
|
|
22
|
+
* Optional parameters kunnen we wel nog ondersteunen met "myvar int default NULL". NOPE toch niet, eens STRICT kan je nooit nullable parameters binnenkrijgen. . (NOPE ZIE VERDER)
|
|
23
|
+
* Moeten we een optie voorzien (of gewoon default zo doen) dat input params aan STRICT functions nooit NULL mogen zijn?
|