@tablecraft-app/plugin-postgres 1.10.4 → 1.12.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/index.js +68 -11
- package/package.json +2 -2
- package/table-craft-plugin.json +2 -2
package/index.js
CHANGED
|
@@ -10937,7 +10937,12 @@ var connectionUrlSchema = strictObject({
|
|
|
10937
10937
|
string$1(),
|
|
10938
10938
|
number$1(),
|
|
10939
10939
|
boolean()
|
|
10940
|
-
]))).optional()
|
|
10940
|
+
]))).optional(),
|
|
10941
|
+
/**
|
|
10942
|
+
* The JDBC SQL Server form, `scheme://host[\instance][:port][;name=value…]` (plan 055): parameters
|
|
10943
|
+
* follow `;`, a `{…}` value may hold one, and `\instance` is the parameter `instanceName`.
|
|
10944
|
+
*/
|
|
10945
|
+
semicolonParams: boolean().optional()
|
|
10941
10946
|
});
|
|
10942
10947
|
/**
|
|
10943
10948
|
* Which fields hold the server's address (decision 070), so the host can open an SSH tunnel and
|
|
@@ -11503,6 +11508,7 @@ var Q_QUOTE_PAIRS = /* @__PURE__ */ new Map([
|
|
|
11503
11508
|
var STRING_QUOTE$1 = "'";
|
|
11504
11509
|
var BRACKET_OPEN$1 = "[";
|
|
11505
11510
|
var BRACKET_CLOSE$1 = "]";
|
|
11511
|
+
var VARIABLE_CHARS = /* @__PURE__ */ new Set(["@", "#"]);
|
|
11506
11512
|
function isSpace(char) {
|
|
11507
11513
|
return char === " " || char === " " || char === "\n" || char === "\r" || char === "\f" || char === "\v";
|
|
11508
11514
|
}
|
|
@@ -11544,7 +11550,7 @@ var Lexer = class {
|
|
|
11544
11550
|
else if (char === "`") token = this.#quoted(at, "`", "quoted", false);
|
|
11545
11551
|
else if (char === BRACKET_OPEN$1 && this.options.bracketIdentifiers === true) token = this.#bracketed(at);
|
|
11546
11552
|
else if (char === "$" && this.options.dollarQuotes === true && this.#dollarTag(at) !== null) token = this.#dollarQuoted(at, this.#dollarTag(at) ?? "");
|
|
11547
|
-
else if (isWordChar(char)) token = this.#word(at, delimiter);
|
|
11553
|
+
else if (this.#isWordChar(char)) token = this.#word(at, delimiter);
|
|
11548
11554
|
else token = {
|
|
11549
11555
|
kind: "symbol",
|
|
11550
11556
|
from: at,
|
|
@@ -11553,6 +11559,9 @@ var Lexer = class {
|
|
|
11553
11559
|
this.position = token.to;
|
|
11554
11560
|
return token;
|
|
11555
11561
|
}
|
|
11562
|
+
#isWordChar(char) {
|
|
11563
|
+
return isWordChar(char) || this.options.variables === true && VARIABLE_CHARS.has(char);
|
|
11564
|
+
}
|
|
11556
11565
|
#lineComment(from) {
|
|
11557
11566
|
const end = this.text.indexOf(NEWLINE$2, from);
|
|
11558
11567
|
return {
|
|
@@ -11648,7 +11657,7 @@ var Lexer = class {
|
|
|
11648
11657
|
const text = this.text;
|
|
11649
11658
|
const customDelimiter = delimiter !== ";";
|
|
11650
11659
|
let at = from;
|
|
11651
|
-
while (at < text.length && isWordChar(text.charAt(at))) {
|
|
11660
|
+
while (at < text.length && this.#isWordChar(text.charAt(at))) {
|
|
11652
11661
|
if (customDelimiter && at > from && text.startsWith(delimiter, at)) break;
|
|
11653
11662
|
at += 1;
|
|
11654
11663
|
}
|
|
@@ -12781,6 +12790,25 @@ function searchPathTarget(text, tokens) {
|
|
|
12781
12790
|
candidates: names
|
|
12782
12791
|
};
|
|
12783
12792
|
}
|
|
12793
|
+
var ALTER_SESSION_PREFIX = [
|
|
12794
|
+
"ALTER",
|
|
12795
|
+
"SESSION",
|
|
12796
|
+
"SET",
|
|
12797
|
+
"CURRENT_SCHEMA",
|
|
12798
|
+
"="
|
|
12799
|
+
];
|
|
12800
|
+
function alterSessionPrefix(text, tokens) {
|
|
12801
|
+
return ALTER_SESSION_PREFIX.every((word, at) => wordAt$1(text, tokens, at) === word);
|
|
12802
|
+
}
|
|
12803
|
+
function alterSessionTarget(text, tokens) {
|
|
12804
|
+
if (tokens.length !== ALTER_SESSION_PREFIX.length + 1 || !alterSessionPrefix(text, tokens)) return null;
|
|
12805
|
+
const token = tokens[ALTER_SESSION_PREFIX.length];
|
|
12806
|
+
const name = identifier$1(text, token);
|
|
12807
|
+
return name === null || token?.kind === "string" ? null : {
|
|
12808
|
+
kind: "schema",
|
|
12809
|
+
candidates: [name]
|
|
12810
|
+
};
|
|
12811
|
+
}
|
|
12784
12812
|
var NAME_TOKENS = /* @__PURE__ */ new Set([
|
|
12785
12813
|
"word",
|
|
12786
12814
|
"quoted",
|
|
@@ -12836,7 +12864,8 @@ function searchPathListStart(text, tokens) {
|
|
|
12836
12864
|
}
|
|
12837
12865
|
/**
|
|
12838
12866
|
* Where the caret at `offset` names a namespace a session-namespace statement of the dialect moves
|
|
12839
|
-
* to: `USE |` or the elements of `SET search_path TO a, |`
|
|
12867
|
+
* to: `USE |`, `ALTER SESSION SET CURRENT_SCHEMA = |` or the elements of `SET search_path TO a, |`
|
|
12868
|
+
* and `SET SCHEMA |`. Null anywhere else,
|
|
12840
12869
|
* and after a name whose closing quote is typed.
|
|
12841
12870
|
*/
|
|
12842
12871
|
function namespaceSlotAt(text, offset, dialect) {
|
|
@@ -12872,6 +12901,17 @@ function namespaceSlotAt(text, offset, dialect) {
|
|
|
12872
12901
|
listed: []
|
|
12873
12902
|
};
|
|
12874
12903
|
}
|
|
12904
|
+
if (form === "alterSessionSchema") {
|
|
12905
|
+
if (prefix?.kind === "string" || before.length !== ALTER_SESSION_PREFIX.length) continue;
|
|
12906
|
+
if (!alterSessionPrefix(text, before)) continue;
|
|
12907
|
+
return {
|
|
12908
|
+
kind: "schema",
|
|
12909
|
+
from,
|
|
12910
|
+
to: offset,
|
|
12911
|
+
quote,
|
|
12912
|
+
listed: []
|
|
12913
|
+
};
|
|
12914
|
+
}
|
|
12875
12915
|
const start = searchPathListStart(text, before);
|
|
12876
12916
|
if (start === null) continue;
|
|
12877
12917
|
if (start.single && before.length !== start.at) continue;
|
|
@@ -12896,14 +12936,25 @@ function namespaceTarget(sql, dialect) {
|
|
|
12896
12936
|
if (forms.length === 0) return null;
|
|
12897
12937
|
const tokens = significantTokens(sql, dialect).filter((token) => token.kind !== "delimiter");
|
|
12898
12938
|
for (const form of forms) {
|
|
12899
|
-
const target = form
|
|
12939
|
+
const target = TARGET_READERS[form](sql, tokens);
|
|
12900
12940
|
if (target !== null) return target;
|
|
12901
12941
|
}
|
|
12902
12942
|
return null;
|
|
12903
12943
|
}
|
|
12944
|
+
var TARGET_READERS = {
|
|
12945
|
+
use: useTarget,
|
|
12946
|
+
searchPath: searchPathTarget,
|
|
12947
|
+
alterSessionSchema: alterSessionTarget
|
|
12948
|
+
};
|
|
12904
12949
|
var SWITCH_TARGETS = {
|
|
12905
12950
|
use: "topLevel",
|
|
12906
|
-
searchPath: "schema"
|
|
12951
|
+
searchPath: "schema",
|
|
12952
|
+
alterSessionSchema: "schema"
|
|
12953
|
+
};
|
|
12954
|
+
var SWITCH_STATEMENTS = {
|
|
12955
|
+
use: (quoted) => `USE ${quoted}`,
|
|
12956
|
+
searchPath: (quoted) => `SET search_path TO ${quoted}`,
|
|
12957
|
+
alterSessionSchema: (quoted) => `ALTER SESSION SET CURRENT_SCHEMA = ${quoted}`
|
|
12907
12958
|
};
|
|
12908
12959
|
/**
|
|
12909
12960
|
* The console's namespace switch for a dialect moving its namespace by `form` (decision 060):
|
|
@@ -12917,7 +12968,7 @@ function namespaceSwitcher(form, quoteIdentifier) {
|
|
|
12917
12968
|
statement(path) {
|
|
12918
12969
|
const name = path.at(-1);
|
|
12919
12970
|
if (name === void 0) throw new PluginError("statementFailed", "A namespace switch names no namespace; pick one from the list.");
|
|
12920
|
-
return form
|
|
12971
|
+
return SWITCH_STATEMENTS[form](quoteIdentifier(name));
|
|
12921
12972
|
}
|
|
12922
12973
|
};
|
|
12923
12974
|
}
|
|
@@ -13420,6 +13471,8 @@ var BOOST = {
|
|
|
13420
13471
|
keyword: -10
|
|
13421
13472
|
};
|
|
13422
13473
|
var UNQUOTED_WORD = "^[A-Za-z0-9_$]*$";
|
|
13474
|
+
/** Where `@` and `#` start a name (`variables`), the typed `@@` stays part of what is filtered. */
|
|
13475
|
+
var VARIABLE_WORD = "^[@#]*[A-Za-z0-9_$]*$";
|
|
13423
13476
|
var ALIAS_WORD_BREAK = /[^A-Za-z0-9]+|(?<=[a-z0-9])(?=[A-Z])/;
|
|
13424
13477
|
var FALLBACK_ALIAS = "t";
|
|
13425
13478
|
var QUOTES = /* @__PURE__ */ new Set([
|
|
@@ -13477,6 +13530,7 @@ function relationKind(relation) {
|
|
|
13477
13530
|
/** The shared completion and navigation every built-in plugin spreads into its `SqlLanguage` (decision 028). */
|
|
13478
13531
|
function sqlCompleter(options) {
|
|
13479
13532
|
const reserved = new Set(options.keywords.map((keyword) => keyword.toUpperCase()));
|
|
13533
|
+
const unquotedWord = options.dialect.variables === true ? VARIABLE_WORD : UNQUOTED_WORD;
|
|
13480
13534
|
const { denotes, sameIdentifier, cteNamed, sourceNamed, serverOf, Lookup } = nameRules(options);
|
|
13481
13535
|
const specs = /* @__PURE__ */ new Map();
|
|
13482
13536
|
for (const spec of options.functions) {
|
|
@@ -13560,7 +13614,8 @@ function sqlCompleter(options) {
|
|
|
13560
13614
|
}
|
|
13561
13615
|
function aliasFor(name, taken) {
|
|
13562
13616
|
const initials = name.split(ALIAS_WORD_BREAK).filter((word) => word !== "").map((word) => word.charAt(0).toLowerCase()).join("");
|
|
13563
|
-
const
|
|
13617
|
+
const folded = options.identifierFolding === "upper" ? initials.toUpperCase() : initials;
|
|
13618
|
+
const base = initials === "" || !options.plainIdentifier.test(folded) ? FALLBACK_ALIAS : initials;
|
|
13564
13619
|
let alias = base;
|
|
13565
13620
|
for (let suffix = 1; taken.has(alias) || reserved.has(alias.toUpperCase()); suffix += 1) alias = `${base}${String(suffix)}`;
|
|
13566
13621
|
taken.add(alias);
|
|
@@ -13585,7 +13640,7 @@ function sqlCompleter(options) {
|
|
|
13585
13640
|
if (source.qualifier.length === 0 && cteNamed(scope.query, source.name) !== void 0) continue;
|
|
13586
13641
|
const found = await lookup.relation(source.qualifier, source.name);
|
|
13587
13642
|
if (found === null) continue;
|
|
13588
|
-
const near = source.alias === null ? relationReference(found.path, found.relation.name, lookup.current) : quoted(source.alias.name);
|
|
13643
|
+
const near = source.alias === null ? relationReference(found.path, found.relation.name, lookup.current) : source.alias.quoted ? options.quoteIdentifier(source.alias.name) : source.alias.name;
|
|
13589
13644
|
for (const key of found.relation.foreignKeys) {
|
|
13590
13645
|
const alias = aliasFor(key.target.relation, new Set(taken));
|
|
13591
13646
|
const on = key.columns.map((column, at) => `${alias}.${quoted(key.target.columns[at] ?? column)} = ${near}.${quoted(column)}`).join(" AND ");
|
|
@@ -13695,7 +13750,7 @@ function sqlCompleter(options) {
|
|
|
13695
13750
|
from: slot.from,
|
|
13696
13751
|
to: slot.to,
|
|
13697
13752
|
items,
|
|
13698
|
-
validFor: slot.quote === null ?
|
|
13753
|
+
validFor: slot.quote === null ? unquotedWord : null
|
|
13699
13754
|
};
|
|
13700
13755
|
}
|
|
13701
13756
|
}
|
|
@@ -13709,7 +13764,7 @@ function sqlCompleter(options) {
|
|
|
13709
13764
|
from: scope.prefixFrom - shift,
|
|
13710
13765
|
to: offset - shift,
|
|
13711
13766
|
items: typedQuote ? quotedLabels(items) : items,
|
|
13712
|
-
validFor: typedQuote ? null :
|
|
13767
|
+
validFor: typedQuote ? null : unquotedWord
|
|
13713
13768
|
};
|
|
13714
13769
|
}
|
|
13715
13770
|
function sourceDeclaring(query, word) {
|
|
@@ -14281,6 +14336,7 @@ var PARAMETER_MARKS = /* @__PURE__ */ new Set([
|
|
|
14281
14336
|
"?"
|
|
14282
14337
|
]);
|
|
14283
14338
|
var PARAMETER_START = /^[$@:]/;
|
|
14339
|
+
var PARAMETER_OR_TEMPORARY = /^[@#]/;
|
|
14284
14340
|
/** Rows a statement may name without declaring them: PostgreSQL's `EXCLUDED`, a trigger's `NEW` and `OLD`. */
|
|
14285
14341
|
var PSEUDO_RELATIONS = /* @__PURE__ */ new Set([
|
|
14286
14342
|
"EXCLUDED",
|
|
@@ -14399,6 +14455,7 @@ async function unresolvedRelation(view, query, source) {
|
|
|
14399
14455
|
if (view.verb === "SELECT" && view.roleOf(source) === "target") return [];
|
|
14400
14456
|
if (source.qualifier.length === 0 && view.rules.cteNamed(query, source.name) !== void 0) return [];
|
|
14401
14457
|
if (!source.name.quoted && NOT_RELATION_NAMES.has(source.name.name.toUpperCase())) return [];
|
|
14458
|
+
if (!source.name.quoted && PARAMETER_OR_TEMPORARY.test(source.name.name)) return [];
|
|
14402
14459
|
const { lookup } = view;
|
|
14403
14460
|
let path = lookup.current;
|
|
14404
14461
|
if (source.qualifier.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tablecraft-app/plugin-postgres",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"description": "The PostgreSQL datasource plugin for TableCraft, downloaded by the app when a data source needs it.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,6 +24,6 @@
|
|
|
24
24
|
},
|
|
25
25
|
"tableCraft": {
|
|
26
26
|
"id": "postgres",
|
|
27
|
-
"apiVersion": "1.
|
|
27
|
+
"apiVersion": "1.5.0"
|
|
28
28
|
}
|
|
29
29
|
}
|