@tablecraft-app/plugin-duckdb-darwin-arm64 1.31.0 → 1.35.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 +157 -35
- package/package.json +2 -2
- package/table-craft-plugin.json +4 -3
package/index.js
CHANGED
|
@@ -5537,7 +5537,8 @@ var CAPABILITIES$1 = [
|
|
|
5537
5537
|
"maintenance",
|
|
5538
5538
|
"coordination",
|
|
5539
5539
|
"bulkTransfer",
|
|
5540
|
-
"savepoints"
|
|
5540
|
+
"savepoints",
|
|
5541
|
+
"rowLimit"
|
|
5541
5542
|
];
|
|
5542
5543
|
/**
|
|
5543
5544
|
* Whether a switch over `targets` can name `namespace`. Not by `Namespace.kind` alone: MySQL lists
|
|
@@ -5828,6 +5829,9 @@ strictObject({
|
|
|
5828
5829
|
}).refine((manifest) => !manifest.capabilities.includes("savepoints") || manifest.capabilities.includes("sql") && manifest.capabilities.includes("transactions"), {
|
|
5829
5830
|
message: "the savepoints capability requires sql and transactions",
|
|
5830
5831
|
path: ["capabilities"]
|
|
5832
|
+
}).refine((manifest) => !manifest.capabilities.includes("rowLimit") || manifest.capabilities.includes("sql"), {
|
|
5833
|
+
message: "the rowLimit capability requires sql",
|
|
5834
|
+
path: ["capabilities"]
|
|
5831
5835
|
});
|
|
5832
5836
|
// ../plugin-api/src/services.ts
|
|
5833
5837
|
var SESSION_KEYS = {
|
|
@@ -5858,7 +5862,8 @@ var LANGUAGE_KEYS = {
|
|
|
5858
5862
|
bulkInsert: true,
|
|
5859
5863
|
objects: true,
|
|
5860
5864
|
routineCall: true,
|
|
5861
|
-
savepoints: true
|
|
5865
|
+
savepoints: true,
|
|
5866
|
+
rowLimit: true
|
|
5862
5867
|
};
|
|
5863
5868
|
Object.keys(SESSION_KEYS);
|
|
5864
5869
|
Object.keys(LANGUAGE_KEYS);
|
|
@@ -16440,7 +16445,7 @@ var NOT_A_NAME$1 = /* @__PURE__ */ new Set([
|
|
|
16440
16445
|
"NULL"
|
|
16441
16446
|
]);
|
|
16442
16447
|
var AS$5 = "AS";
|
|
16443
|
-
var WITH$
|
|
16448
|
+
var WITH$6 = "WITH";
|
|
16444
16449
|
var RECURSIVE$1 = "RECURSIVE";
|
|
16445
16450
|
var CTE_MODIFIERS$1 = /* @__PURE__ */ new Set(["NOT", "MATERIALIZED"]);
|
|
16446
16451
|
var SELECT_MODIFIERS$2 = /* @__PURE__ */ new Set(["DISTINCT", "ALL"]);
|
|
@@ -16596,7 +16601,7 @@ var QueryReader = class {
|
|
|
16596
16601
|
}
|
|
16597
16602
|
read() {
|
|
16598
16603
|
const statement = this.#statement;
|
|
16599
|
-
if (statement.word(this.#index()) === WITH$
|
|
16604
|
+
if (statement.word(this.#index()) === WITH$6) this.#readCtes();
|
|
16600
16605
|
let expectRelation = false;
|
|
16601
16606
|
let fromList = false;
|
|
16602
16607
|
let into = false;
|
|
@@ -17052,7 +17057,7 @@ var SELECT_READ_ONLY_REASONS = {
|
|
|
17052
17057
|
derived: "the result reads a subquery or function, not a table",
|
|
17053
17058
|
noTable: "the result reads no table"
|
|
17054
17059
|
};
|
|
17055
|
-
var SELECT$
|
|
17060
|
+
var SELECT$2 = "SELECT";
|
|
17056
17061
|
var FROM = "FROM";
|
|
17057
17062
|
var AS$4 = "AS";
|
|
17058
17063
|
var STAR$1 = "*";
|
|
@@ -17064,7 +17069,7 @@ var OVER = "OVER";
|
|
|
17064
17069
|
var ONLY = "ONLY";
|
|
17065
17070
|
var ON$2 = "ON";
|
|
17066
17071
|
var NOT = "NOT";
|
|
17067
|
-
var WITH$
|
|
17072
|
+
var WITH$5 = "WITH";
|
|
17068
17073
|
var DISTINCT = /* @__PURE__ */ new Set([
|
|
17069
17074
|
"DISTINCT",
|
|
17070
17075
|
"DISTINCTROW",
|
|
@@ -17091,7 +17096,7 @@ var JOINS = /* @__PURE__ */ new Set([
|
|
|
17091
17096
|
"OUTER"
|
|
17092
17097
|
]);
|
|
17093
17098
|
var GROUPING = /* @__PURE__ */ new Set(["GROUP", "HAVING"]);
|
|
17094
|
-
var SET_OPERATIONS = /* @__PURE__ */ new Set([
|
|
17099
|
+
var SET_OPERATIONS$1 = /* @__PURE__ */ new Set([
|
|
17095
17100
|
"UNION",
|
|
17096
17101
|
"INTERSECT",
|
|
17097
17102
|
"EXCEPT",
|
|
@@ -17189,7 +17194,7 @@ var Reader = class {
|
|
|
17189
17194
|
if (symbol === CLOSE$4) subqueries.pop();
|
|
17190
17195
|
depth.push(subqueries.length);
|
|
17191
17196
|
inSubquery.push(subqueries.some(Boolean));
|
|
17192
|
-
if (symbol === OPEN$5) subqueries.push(this.word(this.tokens[index + 1]) === SELECT$
|
|
17197
|
+
if (symbol === OPEN$5) subqueries.push(this.word(this.tokens[index + 1]) === SELECT$2);
|
|
17193
17198
|
});
|
|
17194
17199
|
return {
|
|
17195
17200
|
depth,
|
|
@@ -17257,7 +17262,7 @@ function tailRefusal(reader, from, depth) {
|
|
|
17257
17262
|
if (from < tokens.length && (first === null || !TAIL_CLAUSES.has(first))) {
|
|
17258
17263
|
if (reader.symbol(tokens[from]) === COMMA$7 || first !== null && JOINS.has(first)) return SELECT_READ_ONLY_REASONS.joins;
|
|
17259
17264
|
if (first !== null && GROUPING.has(first)) return SELECT_READ_ONLY_REASONS.aggregates;
|
|
17260
|
-
if (first !== null && SET_OPERATIONS.has(first)) return SELECT_READ_ONLY_REASONS.combines;
|
|
17265
|
+
if (first !== null && SET_OPERATIONS$1.has(first)) return SELECT_READ_ONLY_REASONS.combines;
|
|
17261
17266
|
return SELECT_READ_ONLY_REASONS.notSelect;
|
|
17262
17267
|
}
|
|
17263
17268
|
for (let at = from; at < tokens.length; at += 1) {
|
|
@@ -17265,7 +17270,7 @@ function tailRefusal(reader, from, depth) {
|
|
|
17265
17270
|
const word = reader.word(tokens[at]);
|
|
17266
17271
|
if (word === null) continue;
|
|
17267
17272
|
if (GROUPING.has(word)) return SELECT_READ_ONLY_REASONS.aggregates;
|
|
17268
|
-
if (SET_OPERATIONS.has(word)) return SELECT_READ_ONLY_REASONS.combines;
|
|
17273
|
+
if (SET_OPERATIONS$1.has(word)) return SELECT_READ_ONLY_REASONS.combines;
|
|
17269
17274
|
if (JOINS.has(word) || word === ON$2 && at > from) return SELECT_READ_ONLY_REASONS.joins;
|
|
17270
17275
|
if (OTHER_TAIL.has(word) && word !== NOT) return SELECT_READ_ONLY_REASONS.notSelect;
|
|
17271
17276
|
}
|
|
@@ -17279,9 +17284,9 @@ function parseSimpleSelect(sql, dialect) {
|
|
|
17279
17284
|
const tokens = significantTokens(sql, dialect).filter((token) => token.kind !== "delimiter");
|
|
17280
17285
|
const reader = new Reader(sql, tokens);
|
|
17281
17286
|
const head = reader.word(tokens[0]);
|
|
17282
|
-
if (head === WITH$
|
|
17287
|
+
if (head === WITH$5) return { readOnly: SELECT_READ_ONLY_REASONS.with };
|
|
17283
17288
|
if (reader.symbol(tokens[0]) === OPEN$5) return { readOnly: SELECT_READ_ONLY_REASONS.combines };
|
|
17284
|
-
if (head !== SELECT$
|
|
17289
|
+
if (head !== SELECT$2) return { readOnly: SELECT_READ_ONLY_REASONS.notSelect };
|
|
17285
17290
|
const { depth, inSubquery } = reader.depths();
|
|
17286
17291
|
let at = 1;
|
|
17287
17292
|
const modifier = reader.word(tokens[at]);
|
|
@@ -17326,7 +17331,7 @@ function parseSimpleSelect(sql, dialect) {
|
|
|
17326
17331
|
};
|
|
17327
17332
|
}
|
|
17328
17333
|
function isClauseWord(word) {
|
|
17329
|
-
return TAIL_CLAUSES.has(word) || JOINS.has(word) || GROUPING.has(word) || SET_OPERATIONS.has(word) || OTHER_TAIL.has(word) || word === ON$2 || word === ONLY;
|
|
17334
|
+
return TAIL_CLAUSES.has(word) || JOINS.has(word) || GROUPING.has(word) || SET_OPERATIONS$1.has(word) || OTHER_TAIL.has(word) || word === ON$2 || word === ONLY;
|
|
17330
17335
|
}
|
|
17331
17336
|
// ../plugin-api/src/sql/namespace.ts
|
|
17332
17337
|
var USE = "USE";
|
|
@@ -18534,10 +18539,10 @@ function sqlCompleter(options) {
|
|
|
18534
18539
|
};
|
|
18535
18540
|
}
|
|
18536
18541
|
// ../plugin-api/src/sql/words.ts
|
|
18537
|
-
var OPEN_PAREN = "(";
|
|
18538
|
-
var CLOSE_PAREN = ")";
|
|
18539
|
-
var WITH$
|
|
18540
|
-
var MAIN_VERBS = /* @__PURE__ */ new Set([
|
|
18542
|
+
var OPEN_PAREN$1 = "(";
|
|
18543
|
+
var CLOSE_PAREN$1 = ")";
|
|
18544
|
+
var WITH$4 = "WITH";
|
|
18545
|
+
var MAIN_VERBS$1 = /* @__PURE__ */ new Set([
|
|
18541
18546
|
"SELECT",
|
|
18542
18547
|
"INSERT",
|
|
18543
18548
|
"UPDATE",
|
|
@@ -18550,8 +18555,8 @@ function words(sql, tokens) {
|
|
|
18550
18555
|
let depth = 0;
|
|
18551
18556
|
for (const token of tokens) if (token.kind === "symbol") {
|
|
18552
18557
|
const char = sql.charAt(token.from);
|
|
18553
|
-
if (char === OPEN_PAREN) depth += 1;
|
|
18554
|
-
else if (char === CLOSE_PAREN) depth = Math.max(0, depth - 1);
|
|
18558
|
+
if (char === OPEN_PAREN$1) depth += 1;
|
|
18559
|
+
else if (char === CLOSE_PAREN$1) depth = Math.max(0, depth - 1);
|
|
18555
18560
|
} else if (token.kind === "word") found.push({
|
|
18556
18561
|
word: wordOf(sql, token),
|
|
18557
18562
|
depth
|
|
@@ -18560,8 +18565,8 @@ function words(sql, tokens) {
|
|
|
18560
18565
|
}
|
|
18561
18566
|
/** The verb that decides what a `WITH …` statement does: the first one outside the CTEs' parentheses. */
|
|
18562
18567
|
function mainVerb(list) {
|
|
18563
|
-
if (list[0]?.word !== WITH$
|
|
18564
|
-
const index = list.findIndex((entry, at) => at > 0 && entry.depth === 0 && MAIN_VERBS.has(entry.word));
|
|
18568
|
+
if (list[0]?.word !== WITH$4) return 0;
|
|
18569
|
+
const index = list.findIndex((entry, at) => at > 0 && entry.depth === 0 && MAIN_VERBS$1.has(entry.word));
|
|
18565
18570
|
return index < 0 ? 0 : index;
|
|
18566
18571
|
}
|
|
18567
18572
|
/** MySQL reads `DESCRIBE` and `DESC` before a statement as `EXPLAIN`, `ANALYZE` included. */
|
|
@@ -18624,7 +18629,7 @@ var BY_OWNERS$1 = /* @__PURE__ */ new Set([
|
|
|
18624
18629
|
var ON$1 = "ON";
|
|
18625
18630
|
/** `ON DUPLICATE KEY UPDATE` and `ON CONFLICT`: an `ON` that starts an action, not a join condition. */
|
|
18626
18631
|
var ON_ACTIONS = /* @__PURE__ */ new Set(["DUPLICATE", "CONFLICT"]);
|
|
18627
|
-
var WITH$
|
|
18632
|
+
var WITH$3 = "WITH";
|
|
18628
18633
|
var CREATE$1 = "CREATE";
|
|
18629
18634
|
var AS$3 = "AS";
|
|
18630
18635
|
/** Statements whose clauses the inspections understand; anything else gets only the lexical checks. */
|
|
@@ -18636,7 +18641,7 @@ var INSPECTED_VERBS = /* @__PURE__ */ new Set([
|
|
|
18636
18641
|
"REPLACE"
|
|
18637
18642
|
]);
|
|
18638
18643
|
var CREATED_FROM_QUERY = /* @__PURE__ */ new Set(["TABLE", "VIEW"]);
|
|
18639
|
-
var QUERY_STARTS = /* @__PURE__ */ new Set(["SELECT", WITH$
|
|
18644
|
+
var QUERY_STARTS = /* @__PURE__ */ new Set(["SELECT", WITH$3]);
|
|
18640
18645
|
/** Words an expression may hold that no built-in keyword list names, so they are never taken for columns. */
|
|
18641
18646
|
var EXPRESSION_WORDS = [
|
|
18642
18647
|
"INTERVAL",
|
|
@@ -19276,7 +19281,7 @@ var ASC = "ASC";
|
|
|
19276
19281
|
var ELSE$1 = "ELSE";
|
|
19277
19282
|
var END$3 = "END";
|
|
19278
19283
|
var AS$1 = "AS";
|
|
19279
|
-
var WITH$
|
|
19284
|
+
var WITH$2 = "WITH";
|
|
19280
19285
|
var ROW = "ROW";
|
|
19281
19286
|
var VALUES_WORDS = /* @__PURE__ */ new Set(["VALUES", "VALUE"]);
|
|
19282
19287
|
var RECURSIVE = "RECURSIVE";
|
|
@@ -19571,7 +19576,7 @@ function cteRemoval(view, nameIndex, close) {
|
|
|
19571
19576
|
}
|
|
19572
19577
|
const withIndex = view.word(nameIndex - 1) === RECURSIVE ? nameIndex - 2 : nameIndex - 1;
|
|
19573
19578
|
const withToken = view.token(withIndex);
|
|
19574
|
-
if (view.word(withIndex) !== WITH$
|
|
19579
|
+
if (view.word(withIndex) !== WITH$2 || withToken === void 0 || following === void 0) return null;
|
|
19575
19580
|
return removal("Remove CTE", {
|
|
19576
19581
|
from: withToken.from,
|
|
19577
19582
|
to: following.from
|
|
@@ -19656,7 +19661,7 @@ var OPEN$1 = "(";
|
|
|
19656
19661
|
var CLOSE$1 = ")";
|
|
19657
19662
|
var COMMA$3 = ",";
|
|
19658
19663
|
var BY = "BY";
|
|
19659
|
-
var SELECT = "SELECT";
|
|
19664
|
+
var SELECT$1 = "SELECT";
|
|
19660
19665
|
var EXPRESSION_EXPECTED = "Expression expected";
|
|
19661
19666
|
/** Keywords that start the next clause, so a clause keyword right before one has no body. */
|
|
19662
19667
|
var CLAUSE_STARTS = /* @__PURE__ */ new Set([
|
|
@@ -19693,7 +19698,7 @@ var NEEDS_BODY = /* @__PURE__ */ new Set([
|
|
|
19693
19698
|
"HAVING",
|
|
19694
19699
|
"ON",
|
|
19695
19700
|
"SET",
|
|
19696
|
-
SELECT
|
|
19701
|
+
SELECT$1
|
|
19697
19702
|
]);
|
|
19698
19703
|
var BY_OWNERS = /* @__PURE__ */ new Set([
|
|
19699
19704
|
"ORDER",
|
|
@@ -19737,14 +19742,14 @@ function emptyClause(view, index) {
|
|
|
19737
19742
|
if (owner === null || !BY_OWNERS.has(owner)) return null;
|
|
19738
19743
|
first = index - 1;
|
|
19739
19744
|
} else if (!NEEDS_BODY.has(word)) return null;
|
|
19740
|
-
if (word === SELECT) while (SELECT_MODIFIERS$1.has(view.word(last + 1) ?? "")) last += 1;
|
|
19745
|
+
if (word === SELECT$1) while (SELECT_MODIFIERS$1.has(view.word(last + 1) ?? "")) last += 1;
|
|
19741
19746
|
if (!nothingFollows(view, last)) return null;
|
|
19742
19747
|
const start = view.token(first);
|
|
19743
19748
|
const end = view.token(last);
|
|
19744
19749
|
if (start === void 0 || end === void 0) return null;
|
|
19745
19750
|
const label = view.text.slice(start.from, end.to).toUpperCase().replace(/\s+/g, " ");
|
|
19746
19751
|
const fixes = [];
|
|
19747
|
-
if (word !== SELECT) {
|
|
19752
|
+
if (word !== SELECT$1) {
|
|
19748
19753
|
const following = view.token(last + 1);
|
|
19749
19754
|
const span = following === void 0 || view.isSymbol(last + 1, CLOSE$1) ? view.withLeadingSpace(first, last) : {
|
|
19750
19755
|
from: start.from,
|
|
@@ -19988,7 +19993,7 @@ var START$1 = "START";
|
|
|
19988
19993
|
var TRANSACTION = "TRANSACTION";
|
|
19989
19994
|
var WHERE = "WHERE";
|
|
19990
19995
|
var LIMIT$1 = "LIMIT";
|
|
19991
|
-
var WITH = "WITH";
|
|
19996
|
+
var WITH$1 = "WITH";
|
|
19992
19997
|
/** Prefixes the explained statement's destructive reason, so the confirmation says why it matters. */
|
|
19993
19998
|
var EXPLAIN_ANALYZE_REASON_PREFIX = "EXPLAIN ANALYZE runs it: ";
|
|
19994
19999
|
function hasTopLevel(list, from, word) {
|
|
@@ -20047,7 +20052,7 @@ function classifyWords(list) {
|
|
|
20047
20052
|
const verbAt = mainVerb(list);
|
|
20048
20053
|
const verb = list[verbAt]?.word ?? first;
|
|
20049
20054
|
return {
|
|
20050
|
-
kind: first === WITH && verbAt === 0 ? "read" : KINDS.get(verb) ?? "other",
|
|
20055
|
+
kind: first === WITH$1 && verbAt === 0 ? "read" : KINDS.get(verb) ?? "other",
|
|
20051
20056
|
destructive: destructiveReason(list, verbAt)
|
|
20052
20057
|
};
|
|
20053
20058
|
}
|
|
@@ -28354,7 +28359,7 @@ var SET_OPERATORS = /* @__PURE__ */ new Set([
|
|
|
28354
28359
|
"EXCEPT",
|
|
28355
28360
|
"MINUS"
|
|
28356
28361
|
]);
|
|
28357
|
-
var SET_QUANTIFIERS = /* @__PURE__ */ new Set(["ALL", "DISTINCT"]);
|
|
28362
|
+
var SET_QUANTIFIERS$1 = /* @__PURE__ */ new Set(["ALL", "DISTINCT"]);
|
|
28358
28363
|
var SELECT_MODIFIERS = /* @__PURE__ */ new Set([
|
|
28359
28364
|
"ALL",
|
|
28360
28365
|
"DISTINCT",
|
|
@@ -28641,7 +28646,7 @@ var AlignedPrinter = class {
|
|
|
28641
28646
|
if (node.type === "tok" && node.keyword && SET_OPERATORS.has(node.upper)) {
|
|
28642
28647
|
const operator = [node];
|
|
28643
28648
|
const quantifier = nodes[index + 1];
|
|
28644
|
-
if (quantifier?.type === "tok" && quantifier.keyword && SET_QUANTIFIERS.has(quantifier.upper)) {
|
|
28649
|
+
if (quantifier?.type === "tok" && quantifier.keyword && SET_QUANTIFIERS$1.has(quantifier.upper)) {
|
|
28645
28650
|
operator.push(quantifier);
|
|
28646
28651
|
index += 1;
|
|
28647
28652
|
}
|
|
@@ -29587,6 +29592,121 @@ function sqlExplainable(options) {
|
|
|
29587
29592
|
};
|
|
29588
29593
|
return { explainable };
|
|
29589
29594
|
}
|
|
29595
|
+
// ../plugin-api/src/sql/limit.ts
|
|
29596
|
+
var SELECT = "SELECT";
|
|
29597
|
+
var WITH = "WITH";
|
|
29598
|
+
var TOP = "TOP";
|
|
29599
|
+
var OPEN_PAREN = "(";
|
|
29600
|
+
var CLOSE_PAREN = ")";
|
|
29601
|
+
/** What may stand between `SELECT` and `TOP`. */
|
|
29602
|
+
var SET_QUANTIFIERS = /* @__PURE__ */ new Set(["ALL", "DISTINCT"]);
|
|
29603
|
+
var MAIN_VERBS = /* @__PURE__ */ new Set([
|
|
29604
|
+
"SELECT",
|
|
29605
|
+
"INSERT",
|
|
29606
|
+
"UPDATE",
|
|
29607
|
+
"DELETE",
|
|
29608
|
+
"MERGE"
|
|
29609
|
+
]);
|
|
29610
|
+
/** A top-level row limit the statement already has. */
|
|
29611
|
+
var OWN_LIMITS = /* @__PURE__ */ new Set([
|
|
29612
|
+
"LIMIT",
|
|
29613
|
+
"OFFSET",
|
|
29614
|
+
"FETCH"
|
|
29615
|
+
]);
|
|
29616
|
+
/**
|
|
29617
|
+
* Top-level words that make a SELECT more than a read of rows a limit may trim: `INTO` writes,
|
|
29618
|
+
* `FOR UPDATE` and `LOCK IN SHARE MODE` lock what they read, `PROCEDURE` hands the rows to MySQL.
|
|
29619
|
+
*/
|
|
29620
|
+
var NOT_A_PLAIN_READ = /* @__PURE__ */ new Set([
|
|
29621
|
+
"INTO",
|
|
29622
|
+
"FOR",
|
|
29623
|
+
"LOCK",
|
|
29624
|
+
"PROCEDURE"
|
|
29625
|
+
]);
|
|
29626
|
+
/** A data-modifying CTE or subquery runs whatever the limit trims. */
|
|
29627
|
+
var WRITES = /* @__PURE__ */ new Set([
|
|
29628
|
+
"INSERT",
|
|
29629
|
+
"UPDATE",
|
|
29630
|
+
"DELETE",
|
|
29631
|
+
"MERGE"
|
|
29632
|
+
]);
|
|
29633
|
+
/** `TOP` limits only the SELECT it opens, not the whole combined query. */
|
|
29634
|
+
var SET_OPERATIONS = /* @__PURE__ */ new Set([
|
|
29635
|
+
"UNION",
|
|
29636
|
+
"INTERSECT",
|
|
29637
|
+
"EXCEPT",
|
|
29638
|
+
"MINUS"
|
|
29639
|
+
]);
|
|
29640
|
+
function placedWords(sql, tokens) {
|
|
29641
|
+
const found = [];
|
|
29642
|
+
let depth = 0;
|
|
29643
|
+
for (const token of tokens) if (token.kind === "symbol") {
|
|
29644
|
+
const char = sql.charAt(token.from);
|
|
29645
|
+
if (char === OPEN_PAREN) depth += 1;
|
|
29646
|
+
else if (char === CLOSE_PAREN) depth = Math.max(0, depth - 1);
|
|
29647
|
+
} else if (token.kind === "word") found.push({
|
|
29648
|
+
word: wordOf(sql, token),
|
|
29649
|
+
depth,
|
|
29650
|
+
token
|
|
29651
|
+
});
|
|
29652
|
+
return found;
|
|
29653
|
+
}
|
|
29654
|
+
function mainSelect(list) {
|
|
29655
|
+
const first = list[0];
|
|
29656
|
+
if (first === void 0 || first.depth !== 0) return null;
|
|
29657
|
+
if (first.word === SELECT) return 0;
|
|
29658
|
+
if (first.word !== WITH) return null;
|
|
29659
|
+
const verb = list.findIndex((entry, at) => at > 0 && entry.depth === 0 && MAIN_VERBS.has(entry.word));
|
|
29660
|
+
return verb > 0 && list[verb]?.word === SELECT ? verb : null;
|
|
29661
|
+
}
|
|
29662
|
+
/** The statement's tokens up to its delimiter; null when another statement follows it. */
|
|
29663
|
+
function ownTokens(tokens) {
|
|
29664
|
+
const end = tokens.findIndex((token) => token.kind === "delimiter");
|
|
29665
|
+
if (end < 0) return tokens;
|
|
29666
|
+
return tokens.slice(end).every((token) => token.kind === "delimiter") ? tokens.slice(0, end) : null;
|
|
29667
|
+
}
|
|
29668
|
+
function insert(sql, offset, text) {
|
|
29669
|
+
return {
|
|
29670
|
+
sql: sql.slice(0, offset) + text + sql.slice(offset),
|
|
29671
|
+
inserted: {
|
|
29672
|
+
offset,
|
|
29673
|
+
length: text.length
|
|
29674
|
+
}
|
|
29675
|
+
};
|
|
29676
|
+
}
|
|
29677
|
+
function topOffset(list, verb) {
|
|
29678
|
+
let at = verb + 1;
|
|
29679
|
+
if (SET_QUANTIFIERS.has(list[at]?.word ?? "")) at += 1;
|
|
29680
|
+
if (list[at]?.word === TOP) return null;
|
|
29681
|
+
return list[at - 1]?.token.to ?? null;
|
|
29682
|
+
}
|
|
29683
|
+
/**
|
|
29684
|
+
* The `rowLimit` language service for a dialect (decision 162). It limits a plain SELECT, `WITH`
|
|
29685
|
+
* included, by one insertion, and answers null for anything it cannot limit without changing what
|
|
29686
|
+
* the statement does or reading it wrongly: another verb, a limit of its own, `INTO`, a locking
|
|
29687
|
+
* read, a data-modifying CTE, more than one statement, and under `top` a combined query.
|
|
29688
|
+
*/
|
|
29689
|
+
function sqlRowLimiter(options, style) {
|
|
29690
|
+
return { limit(sql, rows) {
|
|
29691
|
+
if (!Number.isSafeInteger(rows) || rows < 1) throw new RangeError(`A row limit is a positive integer, not ${rows}`);
|
|
29692
|
+
const tokens = ownTokens(significantTokens(sql, options));
|
|
29693
|
+
const last = tokens?.at(-1);
|
|
29694
|
+
if (tokens === null || last === void 0) return null;
|
|
29695
|
+
const list = placedWords(sql, tokens);
|
|
29696
|
+
const verb = mainSelect(list);
|
|
29697
|
+
if (verb === null) return null;
|
|
29698
|
+
if (list.some((entry) => WRITES.has(entry.word))) return null;
|
|
29699
|
+
const top = list.slice(verb + 1).filter((entry) => entry.depth === 0);
|
|
29700
|
+
if (top.some((entry) => OWN_LIMITS.has(entry.word) || NOT_A_PLAIN_READ.has(entry.word))) return null;
|
|
29701
|
+
if (style === "top") {
|
|
29702
|
+
if (top.some((entry) => SET_OPERATIONS.has(entry.word))) return null;
|
|
29703
|
+
const offset = topOffset(list, verb);
|
|
29704
|
+
return offset === null ? null : insert(sql, offset, ` ${TOP} (${rows})`);
|
|
29705
|
+
}
|
|
29706
|
+
const clause = style === "limit" ? ` LIMIT ${rows}` : ` FETCH FIRST ${rows} ROWS ONLY`;
|
|
29707
|
+
return insert(sql, last.to, clause);
|
|
29708
|
+
} };
|
|
29709
|
+
}
|
|
29590
29710
|
// ../../plugins/duckdb/src/explain.ts
|
|
29591
29711
|
/** What DuckDB's `EXPLAIN` plans; anything else answers an empty tree. */
|
|
29592
29712
|
var EXPLAIN_VERBS = [
|
|
@@ -40329,7 +40449,8 @@ var CAPABILITIES = [
|
|
|
40329
40449
|
"ddl",
|
|
40330
40450
|
"explain",
|
|
40331
40451
|
"explainAnalyze",
|
|
40332
|
-
"bulkInsert"
|
|
40452
|
+
"bulkInsert",
|
|
40453
|
+
"rowLimit"
|
|
40333
40454
|
];
|
|
40334
40455
|
/** DuckDB reads PostgreSQL's lexis: dollar quotes and nested block comments. */
|
|
40335
40456
|
var DIALECT = {
|
|
@@ -40434,7 +40555,8 @@ var language = {
|
|
|
40434
40555
|
keywords: KEYWORDS,
|
|
40435
40556
|
types: IMPORT_TYPES,
|
|
40436
40557
|
decimal: duckdbDecimal
|
|
40437
|
-
})
|
|
40558
|
+
}),
|
|
40559
|
+
rowLimit: sqlRowLimiter(DIALECT, "limit")
|
|
40438
40560
|
}
|
|
40439
40561
|
};
|
|
40440
40562
|
// ../../plugins/duckdb/src/errorPosition.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tablecraft-app/plugin-duckdb-darwin-arm64",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.0",
|
|
4
4
|
"description": "The DuckDB datasource plugin for TableCraft, downloaded by the app when a data source needs it. This package is for darwin-arm64.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"tableCraft": {
|
|
29
29
|
"id": "duckdb",
|
|
30
|
-
"apiVersion": "2.
|
|
30
|
+
"apiVersion": "2.2.0",
|
|
31
31
|
"platform": "darwin-arm64"
|
|
32
32
|
},
|
|
33
33
|
"os": [
|
package/table-craft-plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "duckdb",
|
|
3
3
|
"name": "DuckDB",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"apiVersion": "2.
|
|
4
|
+
"version": "1.35.0",
|
|
5
|
+
"apiVersion": "2.2.0",
|
|
6
6
|
"entry": "index.js",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"sql",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"ddl",
|
|
13
13
|
"explain",
|
|
14
14
|
"explainAnalyze",
|
|
15
|
-
"bulkInsert"
|
|
15
|
+
"bulkInsert",
|
|
16
|
+
"rowLimit"
|
|
16
17
|
],
|
|
17
18
|
"highlight": "postgresql",
|
|
18
19
|
"brands": [
|