@batadata/cli 0.2.7 → 0.2.8
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/dist/commands/powdb.d.ts +11 -3
- package/dist/commands/powdb.js +44 -18
- package/package.json +1 -1
package/dist/commands/powdb.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ interface IndexInfo {
|
|
|
37
37
|
name: string;
|
|
38
38
|
definition: string;
|
|
39
39
|
}
|
|
40
|
-
interface TableSchema {
|
|
40
|
+
export interface TableSchema {
|
|
41
41
|
schema: string;
|
|
42
42
|
name: string;
|
|
43
43
|
columns: ColumnInfo[];
|
|
@@ -62,14 +62,22 @@ export declare function mapPgType(dataType: string): TypeMapping;
|
|
|
62
62
|
/**
|
|
63
63
|
* Sanitize a Postgres identifier into a valid PowQL identifier (leading
|
|
64
64
|
* alpha/underscore, then alphanumeric/underscore). Reports whether it had to be
|
|
65
|
-
* changed and whether it collides with a PowQL keyword
|
|
66
|
-
*
|
|
65
|
+
* changed and whether it collides with a PowQL keyword. A keyword collision is
|
|
66
|
+
* NOT renamed — the name is kept and `renderPowqlIdent` backtick-quotes it at
|
|
67
|
+
* emit time (PowDB 0.10+ syntax), so exported columns keep their source names.
|
|
67
68
|
*/
|
|
68
69
|
export declare function powqlIdentifier(name: string): {
|
|
69
70
|
ident: string;
|
|
70
71
|
changed: boolean;
|
|
71
72
|
keyword: boolean;
|
|
72
73
|
};
|
|
74
|
+
/**
|
|
75
|
+
* Render an identifier for emitted PowQL: backtick-quoted when it collides
|
|
76
|
+
* with a reserved word (the 0.10 lexer accepts `` `name` `` in every
|
|
77
|
+
* identifier position), bare otherwise. Identifiers are pre-sanitized by
|
|
78
|
+
* `powqlIdentifier`, so no other escaping is needed inside the backticks.
|
|
79
|
+
*/
|
|
80
|
+
export declare function renderPowqlIdent(ident: string): string;
|
|
73
81
|
/**
|
|
74
82
|
* Escape a string for a PowQL double-quoted literal. The engine lexer honors
|
|
75
83
|
* `\" \\ \n \t`; every other character passes through verbatim. Returns the
|
package/dist/commands/powdb.js
CHANGED
|
@@ -5,14 +5,26 @@ import { requireToken, isJsonMode, loadConfig } from "../config.js";
|
|
|
5
5
|
import { colors, log, json, spinner, heading, table } from "../utils/logger.js";
|
|
6
6
|
import { emitError, isRetryable } from "../utils/errors.js";
|
|
7
7
|
import { resolveProjectId, resolveBranchId } from "../link.js";
|
|
8
|
-
// PowQL reserved words a column/table name must not collide with
|
|
9
|
-
// engine lexer keyword set
|
|
10
|
-
//
|
|
8
|
+
// PowQL reserved words a column/table name must not collide with. Mirrors the
|
|
9
|
+
// FULL engine lexer keyword set (crates/query/src/lexer.rs POWQL_KEYWORDS as
|
|
10
|
+
// of PowDB 0.10.0 — which added `schema`/`describe`). A colliding name is
|
|
11
|
+
// emitted backtick-quoted (0.10+ syntax) rather than renamed, so the exported
|
|
12
|
+
// column keeps its source name. Keep this list in sync on PowDB upgrades: a
|
|
13
|
+
// missing word here means a bare identifier that fails to parse on load.
|
|
11
14
|
const POWQL_KEYWORDS = new Set([
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
15
|
+
"abs", "add", "alter", "and", "as", "asc", "auto", "avg", "begin",
|
|
16
|
+
"between", "case", "cast", "ceil", "column", "commit", "concat", "conflict",
|
|
17
|
+
"count", "cross", "date_add", "date_diff", "default", "delete",
|
|
18
|
+
"dense_rank", "desc", "describe", "distinct", "drop", "else", "end",
|
|
19
|
+
"exists", "explain", "extract", "false", "filter", "floor", "group",
|
|
20
|
+
"having", "in", "index", "inner", "insert", "is", "join", "left", "length",
|
|
21
|
+
"let", "like", "limit", "link", "lower", "match", "materialize",
|
|
22
|
+
"materialized", "max", "min", "multi", "not", "now", "null", "offset", "on",
|
|
23
|
+
"or", "order", "outer", "over", "partition", "pow", "rank", "refresh",
|
|
24
|
+
"required", "returning", "right", "rollback", "round", "row_number",
|
|
25
|
+
"schema", "select", "sqrt", "substring", "sum", "then", "transaction",
|
|
26
|
+
"trim", "true", "type", "union", "unique", "update", "upper", "upsert",
|
|
27
|
+
"view", "when",
|
|
16
28
|
]);
|
|
17
29
|
/**
|
|
18
30
|
* Map a Postgres data type (as reported by schema introspection) to the PowDB
|
|
@@ -73,8 +85,9 @@ export function mapPgType(dataType) {
|
|
|
73
85
|
/**
|
|
74
86
|
* Sanitize a Postgres identifier into a valid PowQL identifier (leading
|
|
75
87
|
* alpha/underscore, then alphanumeric/underscore). Reports whether it had to be
|
|
76
|
-
* changed and whether it collides with a PowQL keyword
|
|
77
|
-
*
|
|
88
|
+
* changed and whether it collides with a PowQL keyword. A keyword collision is
|
|
89
|
+
* NOT renamed — the name is kept and `renderPowqlIdent` backtick-quotes it at
|
|
90
|
+
* emit time (PowDB 0.10+ syntax), so exported columns keep their source names.
|
|
78
91
|
*/
|
|
79
92
|
export function powqlIdentifier(name) {
|
|
80
93
|
let ident = name.replace(/[^A-Za-z0-9_]/g, "_");
|
|
@@ -82,11 +95,17 @@ export function powqlIdentifier(name) {
|
|
|
82
95
|
ident = "_" + ident;
|
|
83
96
|
}
|
|
84
97
|
const keyword = POWQL_KEYWORDS.has(ident.toLowerCase());
|
|
85
|
-
if (keyword) {
|
|
86
|
-
ident = ident + "_";
|
|
87
|
-
}
|
|
88
98
|
return { ident, changed: ident !== name, keyword };
|
|
89
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Render an identifier for emitted PowQL: backtick-quoted when it collides
|
|
102
|
+
* with a reserved word (the 0.10 lexer accepts `` `name` `` in every
|
|
103
|
+
* identifier position), bare otherwise. Identifiers are pre-sanitized by
|
|
104
|
+
* `powqlIdentifier`, so no other escaping is needed inside the backticks.
|
|
105
|
+
*/
|
|
106
|
+
export function renderPowqlIdent(ident) {
|
|
107
|
+
return POWQL_KEYWORDS.has(ident.toLowerCase()) ? `\`${ident}\`` : ident;
|
|
108
|
+
}
|
|
90
109
|
/**
|
|
91
110
|
* Escape a string for a PowQL double-quoted literal. The engine lexer honors
|
|
92
111
|
* `\" \\ \n \t`; every other character passes through verbatim. Returns the
|
|
@@ -221,7 +240,10 @@ export function planTable(t) {
|
|
|
221
240
|
const warnings = [];
|
|
222
241
|
const { ident: tPowName, changed: nameChanged, keyword } = powqlIdentifier(t.name);
|
|
223
242
|
if (nameChanged) {
|
|
224
|
-
warnings.push(`table renamed to \`${tPowName}
|
|
243
|
+
warnings.push(`table renamed to \`${tPowName}\` (name not a valid PowQL identifier)`);
|
|
244
|
+
}
|
|
245
|
+
else if (keyword) {
|
|
246
|
+
warnings.push(`table name "${t.name}" is a PowQL reserved word — emitted backtick-quoted (requires PowDB 0.10+)`);
|
|
225
247
|
}
|
|
226
248
|
// Single-column UNIQUE constraints → the PowQL `unique` modifier.
|
|
227
249
|
const singleUniqueCols = new Set();
|
|
@@ -263,7 +285,10 @@ export function planTable(t) {
|
|
|
263
285
|
}
|
|
264
286
|
const { ident: colPowName, changed: colChanged, keyword: colKeyword } = powqlIdentifier(col.name);
|
|
265
287
|
if (colChanged) {
|
|
266
|
-
warnings.push(`column ${col.name} renamed to \`${colPowName}
|
|
288
|
+
warnings.push(`column ${col.name} renamed to \`${colPowName}\` (name not a valid PowQL identifier)`);
|
|
289
|
+
}
|
|
290
|
+
else if (colKeyword) {
|
|
291
|
+
warnings.push(`column "${col.name}" is a PowQL reserved word — emitted backtick-quoted (requires PowDB 0.10+)`);
|
|
267
292
|
}
|
|
268
293
|
const def = parsePgDefault(col.defaultValue, mapping.powType);
|
|
269
294
|
let auto = false;
|
|
@@ -297,7 +322,7 @@ export function planTable(t) {
|
|
|
297
322
|
}
|
|
298
323
|
/** Render a table plan as a PowQL `type` DDL block. */
|
|
299
324
|
export function renderTypeDdl(plan) {
|
|
300
|
-
const lines = [`type ${plan.powName} {`];
|
|
325
|
+
const lines = [`type ${renderPowqlIdent(plan.powName)} {`];
|
|
301
326
|
const fieldLines = plan.columns.map((c) => {
|
|
302
327
|
const mods = [];
|
|
303
328
|
if (c.required)
|
|
@@ -308,7 +333,7 @@ export function renderTypeDdl(plan) {
|
|
|
308
333
|
mods.push("auto");
|
|
309
334
|
const prefix = mods.length ? mods.join(" ") + " " : "";
|
|
310
335
|
const def = c.defaultLiteral ? ` default ${c.defaultLiteral}` : "";
|
|
311
|
-
return ` ${prefix}${c.powName}: ${c.powType}${def}`;
|
|
336
|
+
return ` ${prefix}${renderPowqlIdent(c.powName)}: ${c.powType}${def}`;
|
|
312
337
|
});
|
|
313
338
|
lines.push(fieldLines.join(",\n"));
|
|
314
339
|
lines.push("}");
|
|
@@ -337,14 +362,14 @@ export function buildInserts(plan, rows) {
|
|
|
337
362
|
}
|
|
338
363
|
if (res.risky)
|
|
339
364
|
loadRisk = true;
|
|
340
|
-
assigns.push(`${col.powName} := ${res.literal}`);
|
|
365
|
+
assigns.push(`${renderPowqlIdent(col.powName)} := ${res.literal}`);
|
|
341
366
|
anyField = true;
|
|
342
367
|
}
|
|
343
368
|
if (!anyField) {
|
|
344
369
|
skippedRows++;
|
|
345
370
|
continue;
|
|
346
371
|
}
|
|
347
|
-
statements.push(`insert ${plan.powName} { ${assigns.join(", ")} };`);
|
|
372
|
+
statements.push(`insert ${renderPowqlIdent(plan.powName)} { ${assigns.join(", ")} };`);
|
|
348
373
|
}
|
|
349
374
|
const warnings = [];
|
|
350
375
|
for (const [col, reason] of skipNotes) {
|
|
@@ -603,6 +628,7 @@ function buildArtifactHeader(o) {
|
|
|
603
628
|
// which lexes as two minus signs and fails to parse).
|
|
604
629
|
const lines = [
|
|
605
630
|
"# PowDB Stage A export — generated by `bata powdb pull`",
|
|
631
|
+
"# Target: PowDB 0.10+ (reserved identifiers are backtick-quoted)",
|
|
606
632
|
"#",
|
|
607
633
|
`# Source project : ${o.projectName} (${o.projectId})`,
|
|
608
634
|
`# Source branch : ${o.branchName} (${o.branchId})`,
|