@tablecraft-app/plugin-postgres 1.10.3 → 1.10.4

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 CHANGED
@@ -11215,7 +11215,13 @@ var SHOWN_ARROW = "→";
11215
11215
  var OPTIONAL_MARK = "?";
11216
11216
  var VARIADIC_MARK = "...";
11217
11217
  var COMPARATOR = /^(>=|<=|>|<|=)?(\d+(?:\.\d+)*)$/;
11218
- function parameter$1(written) {
11218
+ var BARE_MARK = "=";
11219
+ var LEAD_WORD = /^[A-Z][A-Z_]*$/;
11220
+ var LEAD_CHOICE = "|";
11221
+ var PARAMETER_SEPARATOR = ",";
11222
+ var COMMA_SHOWN = ", ";
11223
+ var MEMBER_SEPARATOR$2 = ".";
11224
+ function parameter$1(written, lead) {
11219
11225
  let name = written.trim();
11220
11226
  const variadic = name.endsWith(VARIADIC_MARK);
11221
11227
  if (variadic) name = name.slice(0, -3).trim();
@@ -11224,28 +11230,78 @@ function parameter$1(written) {
11224
11230
  return {
11225
11231
  name,
11226
11232
  ...optional ? { optional } : {},
11227
- ...variadic ? { variadic } : {}
11233
+ ...variadic ? { variadic } : {},
11234
+ ...lead === null ? {} : { lead }
11228
11235
  };
11229
11236
  }
11230
- /** Reads `"str, len? -> string"`: `?` marks an optional parameter, `...` one that repeats. */
11237
+ function isLeadWord(word) {
11238
+ return word.split(LEAD_CHOICE).every((choice) => LEAD_WORD.test(choice));
11239
+ }
11240
+ /** Whether `lead` is `word` or offers it among its `|` alternatives. */
11241
+ function leadMatches(lead, word) {
11242
+ return lead.split(LEAD_CHOICE).includes(word);
11243
+ }
11244
+ /**
11245
+ * One comma-separated part: an upper-case word between names leads the next, as one before the
11246
+ * first parameter does; one standing alone is a keyword choice. After a comma the keyword is the
11247
+ * argument's own (`date, INTERVAL expr unit`), since the comma already separates it.
11248
+ */
11249
+ function leadParameters(part, index) {
11250
+ const words = part.trim().split(/\s+/);
11251
+ const parameters = [];
11252
+ let lead = null;
11253
+ let name = [];
11254
+ const flush = () => {
11255
+ if (name.length > 0) parameters.push(parameter$1(name.join(" "), lead));
11256
+ name = [];
11257
+ lead = null;
11258
+ };
11259
+ words.forEach((word, at) => {
11260
+ const next = words[at + 1];
11261
+ if (!(at === 0 && index > 0) && isLeadWord(word) && next !== void 0 && !isLeadWord(next)) {
11262
+ flush();
11263
+ lead = word;
11264
+ } else name.push(word);
11265
+ });
11266
+ flush();
11267
+ return parameters;
11268
+ }
11269
+ function isBareSignature(written) {
11270
+ return written.trim().startsWith(BARE_MARK);
11271
+ }
11272
+ /**
11273
+ * Reads `"str, len? -> string"`: `?` marks an optional parameter, `...` one that repeats, an
11274
+ * upper-case word between names the keyword before the next (`"unit FROM date -> integer"`).
11275
+ * `"= date"` is a bare function's and `"str ->"` a procedure's, which returns nothing.
11276
+ */
11231
11277
  function parseSignature(written) {
11278
+ if (isBareSignature(written)) return {
11279
+ parameters: [],
11280
+ returns: written.trim().slice(1).trim()
11281
+ };
11232
11282
  const arrow = written.lastIndexOf(RETURNS_ARROW);
11233
11283
  if (arrow < 0) throw new Error(`Signature "${written}" has no "${RETURNS_ARROW} type"; add what it returns.`);
11234
11284
  const list = written.slice(0, arrow).trim();
11235
11285
  return {
11236
- parameters: list === "" ? [] : list.split(",").map(parameter$1),
11286
+ parameters: list === "" ? [] : list.split(PARAMETER_SEPARATOR).flatMap(leadParameters),
11237
11287
  returns: written.slice(arrow + 2).trim()
11238
11288
  };
11239
11289
  }
11240
11290
  /** Specs for one category, from compact entries a plugin's data file lists. */
11241
11291
  function functionSpecs(category, entries) {
11242
- return entries.map(([name, signatures, summary, available]) => ({
11243
- name,
11244
- signatures: (typeof signatures === "string" ? [signatures] : signatures).map(parseSignature),
11245
- summary,
11246
- category,
11247
- ...available === void 0 ? {} : { available }
11248
- }));
11292
+ return entries.map(([name, signatures, summary, available]) => {
11293
+ const written = typeof signatures === "string" ? [signatures] : signatures;
11294
+ const bare = written.filter(isBareSignature).length;
11295
+ if (bare > 0 && bare < written.length) throw new Error(`${name} mixes "${BARE_MARK} type" with called signatures; write the bare form as "-> type".`);
11296
+ return {
11297
+ name,
11298
+ signatures: written.map(parseSignature),
11299
+ summary,
11300
+ category,
11301
+ ...available === void 0 ? {} : { available },
11302
+ ...bare > 0 ? { bare: true } : {}
11303
+ };
11304
+ });
11249
11305
  }
11250
11306
  function compareVersions(left, right) {
11251
11307
  for (let at = 0; at < Math.max(left.length, right.length); at += 1) {
@@ -11274,20 +11330,48 @@ function isAvailable(spec, server) {
11274
11330
  if (range === false) return false;
11275
11331
  return range.split(/\s+/).filter((comparator) => comparator !== "").every((comparator) => satisfies(server.version, comparator));
11276
11332
  }
11277
- function shownParameter(parameter) {
11333
+ function shownParameter(parameter, index) {
11278
11334
  const name = parameter.variadic === true ? `${parameter.name}${VARIADIC_MARK}` : parameter.name;
11279
- return parameter.optional === true ? `[${name}]` : name;
11335
+ const led = parameter.lead === void 0 ? name : `${parameter.lead} ${name}`;
11336
+ return (index === 0 ? "" : parameter.lead === void 0 ? COMMA_SHOWN : " ") + (parameter.optional === true ? `[${led}]` : led);
11280
11337
  }
11281
- /** `(date, format) → string`, the popup's detail for one signature. */
11338
+ function returnsLabel(returns) {
11339
+ return returns === "" ? "" : `${SHOWN_ARROW} ${returns}`;
11340
+ }
11341
+ /** `(date, format) → string`, the popup's detail for one signature; a lead replaces the comma, a procedure has no `→`. */
11282
11342
  function signatureLabel(signature) {
11283
- return `(${signature.parameters.map(shownParameter).join(", ")}) ${SHOWN_ARROW} ${signature.returns}`;
11343
+ const list = `(${signature.parameters.map(shownParameter).join("")})`;
11344
+ const returns = returnsLabel(signature.returns);
11345
+ return returns === "" ? list : `${list} ${returns}`;
11346
+ }
11347
+ function shownSignature(spec, signature) {
11348
+ return spec.bare === true ? returnsLabel(signature.returns) : signatureLabel(signature);
11284
11349
  }
11285
11350
  /** Every signature on its own line, then the summary. */
11286
11351
  function functionInfo(spec) {
11287
11352
  const label = spec.name.toLowerCase();
11288
- return `${spec.signatures.map((signature) => `${label}${signatureLabel(signature)}`).join("\n")}\n\n${spec.summary}`;
11353
+ const gap = spec.bare === true ? " " : "";
11354
+ return `${spec.signatures.map((signature) => `${label}${gap}${shownSignature(spec, signature)}`).join("\n")}\n\n${spec.summary}`;
11289
11355
  }
11290
- /** A spec as an item: `name()` with the caret between the parentheses when it takes arguments. */
11356
+ /**
11357
+ * A spec as an item: `name()` with the caret between the parentheses when it takes arguments, or
11358
+ * the name alone for a bare one. `label` is what the popup offers, the member alone after `pkg.`.
11359
+ */
11360
+ function specItem(spec, label, boost) {
11361
+ const first = spec.signatures[0];
11362
+ const takesArguments = spec.signatures.some((signature) => signature.parameters.length > 0);
11363
+ const bare = spec.bare === true;
11364
+ return {
11365
+ label,
11366
+ kind: "function",
11367
+ detail: first === void 0 ? null : shownSignature(spec, first),
11368
+ apply: bare ? label : `${label}()`,
11369
+ boost,
11370
+ info: functionInfo(spec),
11371
+ caret: takesArguments && !bare ? label.length + 1 : null
11372
+ };
11373
+ }
11374
+ /** A spec as an item: `name()` with the caret between the parentheses when it takes arguments, the name alone when bare. */
11291
11375
  function functionItem(spec, boost) {
11292
11376
  if (typeof spec === "string") return {
11293
11377
  label: spec,
@@ -11298,18 +11382,17 @@ function functionItem(spec, boost) {
11298
11382
  info: null,
11299
11383
  caret: null
11300
11384
  };
11301
- const label = spec.name.toLowerCase();
11302
- const first = spec.signatures[0];
11303
- const takesArguments = spec.signatures.some((signature) => signature.parameters.length > 0);
11304
- return {
11305
- label,
11306
- kind: "function",
11307
- detail: first === void 0 ? null : signatureLabel(first),
11308
- apply: `${label}()`,
11309
- boost,
11310
- info: functionInfo(spec),
11311
- caret: takesArguments ? label.length + 1 : null
11312
- };
11385
+ return specItem(spec, spec.name.toLowerCase(), boost);
11386
+ }
11387
+ /** The package a spec named `PKG.MEMBER` belongs to, upper case; null for a plain function. */
11388
+ function functionPackage(spec) {
11389
+ const name = functionName(spec);
11390
+ const dot = name.lastIndexOf(MEMBER_SEPARATOR$2);
11391
+ return dot < 0 ? null : name.slice(0, dot).toUpperCase();
11392
+ }
11393
+ /** A package member as offered after `pkg.`: the member's name alone, the info naming it in full. */
11394
+ function memberItem(spec, boost) {
11395
+ return specItem(spec, spec.name.slice(spec.name.lastIndexOf(MEMBER_SEPARATOR$2) + 1).toLowerCase(), boost);
11313
11396
  }
11314
11397
  /** The name a function entry is offered under, either form. */
11315
11398
  function functionName(spec) {
@@ -11637,7 +11720,7 @@ function wordOf(text, token) {
11637
11720
  var OPEN$6 = "(";
11638
11721
  var CLOSE$5 = ")";
11639
11722
  var DOT$3 = ".";
11640
- var COMMA$7 = ",";
11723
+ var COMMA$9 = ",";
11641
11724
  var QUERY_STARTS$2 = /* @__PURE__ */ new Set(["SELECT", "WITH"]);
11642
11725
  var RELATION_INTRODUCERS$1 = /* @__PURE__ */ new Set([
11643
11726
  "FROM",
@@ -11894,7 +11977,7 @@ var QueryReader = class {
11894
11977
  flush();
11895
11978
  selecting = false;
11896
11979
  selected = true;
11897
- } else if (statement.isSymbol(index, COMMA$7)) {
11980
+ } else if (statement.isSymbol(index, COMMA$9)) {
11898
11981
  flush();
11899
11982
  continue;
11900
11983
  } else {
@@ -11926,7 +12009,7 @@ var QueryReader = class {
11926
12009
  into = false;
11927
12010
  continue;
11928
12011
  }
11929
- if (fromList && statement.isSymbol(index, COMMA$7)) expectRelation = true;
12012
+ if (fromList && statement.isSymbol(index, COMMA$9)) expectRelation = true;
11930
12013
  }
11931
12014
  if (selecting) flush();
11932
12015
  }
@@ -11954,7 +12037,7 @@ var QueryReader = class {
11954
12037
  query: statement.query(body)
11955
12038
  });
11956
12039
  this.#at += 1;
11957
- if (!statement.isSymbol(this.#index(), COMMA$7)) return;
12040
+ if (!statement.isSymbol(this.#index(), COMMA$9)) return;
11958
12041
  this.#at += 1;
11959
12042
  }
11960
12043
  }
@@ -12116,7 +12199,7 @@ function clauseOf(statement, queryOpen, group, anchor, query) {
12116
12199
  }
12117
12200
  const lastWord = statement.word(last ?? void 0);
12118
12201
  if (lastWord !== null && (RELATION_INTRODUCERS$1.has(lastWord) || RELATION_MODIFIERS.has(lastWord))) return lastWord === "JOIN" || lastWord === "STRAIGHT_JOIN" ? "join" : "relation";
12119
- if (fromList && last !== null && statement.isSymbol(last, COMMA$7)) return "relation";
12202
+ if (fromList && last !== null && statement.isSymbol(last, COMMA$9)) return "relation";
12120
12203
  if (clause !== null && EXPRESSION_CLAUSES.has(clause)) return "columns";
12121
12204
  return "keywords";
12122
12205
  }
@@ -12163,6 +12246,10 @@ function scopeAt(text, offset, dialect, mode = "complete") {
12163
12246
  };
12164
12247
  }
12165
12248
  // ../plugin-api/src/sql/signature.ts
12249
+ var COMMA$8 = ",";
12250
+ var MEMBER_SEPARATOR$1 = ".";
12251
+ /** Calls a procedure by name, so it may come before a package member as it never may before a function. */
12252
+ var CALL_WORD = "CALL";
12166
12253
  /** Words a relation or routine name follows, so `TABLE upper (` defines rather than calls. */
12167
12254
  var NAME_INTRODUCERS = /* @__PURE__ */ new Set([
12168
12255
  "CALL",
@@ -12189,7 +12276,8 @@ function upperWord(text, token) {
12189
12276
  }
12190
12277
  /**
12191
12278
  * Finds the innermost call around `offset` whose name `known` accepts, counting its top-level
12192
- * commas; strings, comments and quoted names are tokens of their own, so their commas never count.
12279
+ * commas and listing its separators; strings, comments and quoted names are tokens of their own,
12280
+ * so their commas never count. `pkg.member (` asks `known` for `PKG.MEMBER`.
12193
12281
  * Grouping parentheses are looked through; a subquery, a non-function name before `(` or a caret
12194
12282
  * in a string or comment ends the search with null. `reserved` holds the dialect's keywords: a
12195
12283
  * function spelled like one (`VALUES`, `LEFT`) is a call only where an operand fits, not after a
@@ -12198,16 +12286,35 @@ function upperWord(text, token) {
12198
12286
  function callAt(text, offset, dialect, reserved, known) {
12199
12287
  const { tokens, literal } = statementTokens(text, offset, dialect);
12200
12288
  if (literal) return null;
12289
+ /** `pkg.member` ending at `at`, when the package's spec knows the member. */
12290
+ function member(at) {
12291
+ const name = tokens[at];
12292
+ const owner = tokens[at - 2];
12293
+ const word = upperWord(text, name);
12294
+ const ownerWord = upperWord(text, owner);
12295
+ if (name === void 0 || owner === void 0 || word === null || ownerWord === null) return null;
12296
+ if (!known(`${ownerWord}${MEMBER_SEPARATOR$1}${word}`)) return null;
12297
+ const previous = upperWord(text, tokens[at - 3]);
12298
+ if (previous !== null && previous !== CALL_WORD && NAME_INTRODUCERS.has(previous)) return null;
12299
+ return {
12300
+ written: `${text.slice(owner.from, owner.to)}${MEMBER_SEPARATOR$1}${text.slice(name.from, name.to)}`,
12301
+ from: owner.from
12302
+ };
12303
+ }
12201
12304
  function callable(at) {
12202
12305
  const name = tokens[at];
12306
+ const before = tokens[at - 1];
12307
+ if (symbol(text, before, MEMBER_SEPARATOR$1)) return member(at);
12203
12308
  const word = upperWord(text, name);
12204
12309
  if (name === void 0 || word === null || !known(word)) return null;
12205
- const before = tokens[at - 1];
12206
- if (symbol(text, before, ".")) return null;
12310
+ const found = {
12311
+ written: text.slice(name.from, name.to),
12312
+ from: name.from
12313
+ };
12207
12314
  const previous = upperWord(text, before);
12208
12315
  if (previous !== null && NAME_INTRODUCERS.has(previous)) return null;
12209
- if (!reserved.has(word)) return name;
12210
- return before === void 0 || before.kind === "symbol" && !symbol(text, before, ")") || previous !== null && reserved.has(previous) ? name : null;
12316
+ if (!reserved.has(word)) return found;
12317
+ return before === void 0 || before.kind === "symbol" && !symbol(text, before, ")") || previous !== null && reserved.has(previous) ? found : null;
12211
12318
  }
12212
12319
  const frames = [];
12213
12320
  let index = 0;
@@ -12220,12 +12327,19 @@ function callAt(text, offset, dialect, reserved, known) {
12220
12327
  name,
12221
12328
  named: name === null && !grouping(text, tokens[index - 1]),
12222
12329
  open: index,
12223
- commas: 0
12330
+ commas: 0,
12331
+ separators: []
12224
12332
  });
12225
12333
  } else if (symbol(text, token, ")")) frames.pop();
12226
- else if (symbol(text, token, ",")) {
12334
+ else if (symbol(text, token, COMMA$8)) {
12227
12335
  const top = frames.at(-1);
12228
- if (top !== void 0) top.commas += 1;
12336
+ if (top !== void 0) {
12337
+ top.commas += 1;
12338
+ top.separators.push(COMMA$8);
12339
+ }
12340
+ } else {
12341
+ const word = upperWord(text, token);
12342
+ if (word !== null) frames.at(-1)?.separators.push(word);
12229
12343
  }
12230
12344
  }
12231
12345
  for (let depth = frames.length - 1; depth >= 0; depth -= 1) {
@@ -12236,8 +12350,9 @@ function callAt(text, offset, dialect, reserved, known) {
12236
12350
  continue;
12237
12351
  }
12238
12352
  return {
12239
- name: text.slice(frame.name.from, frame.name.to),
12353
+ name: frame.name.written,
12240
12354
  argument: frame.commas,
12355
+ separators: frame.separators,
12241
12356
  from: frame.name.from,
12242
12357
  to: closeOf(text, tokens, index, frames.length - depth) ?? offset
12243
12358
  };
@@ -12304,7 +12419,7 @@ var FROM = "FROM";
12304
12419
  var AS$4 = "AS";
12305
12420
  var STAR$1 = "*";
12306
12421
  var DOT$2 = ".";
12307
- var COMMA$6 = ",";
12422
+ var COMMA$7 = ",";
12308
12423
  var OPEN$5 = "(";
12309
12424
  var CLOSE$4 = ")";
12310
12425
  var OVER = "OVER";
@@ -12502,7 +12617,7 @@ function tailRefusal(reader, from, depth) {
12502
12617
  const tokens = reader.tokens;
12503
12618
  const first = reader.word(tokens[from]);
12504
12619
  if (from < tokens.length && (first === null || !TAIL_CLAUSES.has(first))) {
12505
- if (reader.symbol(tokens[from]) === COMMA$6 || first !== null && JOINS.has(first)) return SELECT_READ_ONLY_REASONS.joins;
12620
+ if (reader.symbol(tokens[from]) === COMMA$7 || first !== null && JOINS.has(first)) return SELECT_READ_ONLY_REASONS.joins;
12506
12621
  if (first !== null && GROUPING.has(first)) return SELECT_READ_ONLY_REASONS.aggregates;
12507
12622
  if (first !== null && SET_OPERATIONS.has(first)) return SELECT_READ_ONLY_REASONS.combines;
12508
12623
  return SELECT_READ_ONLY_REASONS.notSelect;
@@ -12540,7 +12655,7 @@ function parseSimpleSelect(sql, dialect) {
12540
12655
  if (refusal !== null) return { readOnly: refusal };
12541
12656
  const items = [];
12542
12657
  let itemFrom = at;
12543
- for (let index = at; index <= fromAt; index += 1) if (index === fromAt || depth[index] === 0 && reader.symbol(tokens[index]) === COMMA$6) {
12658
+ for (let index = at; index <= fromAt; index += 1) if (index === fromAt || depth[index] === 0 && reader.symbol(tokens[index]) === COMMA$7) {
12544
12659
  if (index === itemFrom) return { readOnly: SELECT_READ_ONLY_REASONS.notSelect };
12545
12660
  items.push(selectItem(reader, itemFrom, index));
12546
12661
  itemFrom = index + 1;
@@ -13315,6 +13430,47 @@ var QUOTES = /* @__PURE__ */ new Set([
13315
13430
  /** Below every other namespace: `USE mysql` is legitimate but rarely meant. */
13316
13431
  var SYSTEM_NAMESPACE_BOOST = -20;
13317
13432
  var CURRENT_DETAIL = "current";
13433
+ var COMMA$6 = ",";
13434
+ var MEMBER_SEPARATOR = ".";
13435
+ /**
13436
+ * Walks `separators` through `signature`: a comma moves to the next parameter without a lead, a
13437
+ * word to the next one it leads. A word nothing leads is an argument's own (`YEAR`, `DECIMAL`).
13438
+ * Past the last parameter a comma keeps counting, as the hint's variadic rule expects; a variadic
13439
+ * parameter keyword-led ones follow (`CHAR(code... USING charset)`) takes every comma.
13440
+ */
13441
+ function argumentAt(signature, separators) {
13442
+ const { parameters } = signature;
13443
+ let at = 0;
13444
+ let entered = false;
13445
+ let led = 0;
13446
+ for (const separator of separators) {
13447
+ if (separator === COMMA$6) {
13448
+ const next = parameters.findIndex((parameter, index) => index > at && parameter.lead === void 0);
13449
+ if (next >= 0) at = next;
13450
+ else if (!(parameters[at]?.variadic === true && at < parameters.length - 1)) at += 1;
13451
+ entered = true;
13452
+ continue;
13453
+ }
13454
+ const next = parameters.findIndex((parameter, index) => (index > at || index === at && !entered) && parameter.lead !== void 0 && leadMatches(parameter.lead, separator));
13455
+ if (next < 0) continue;
13456
+ at = next;
13457
+ entered = true;
13458
+ led += 1;
13459
+ }
13460
+ return {
13461
+ argument: at,
13462
+ led
13463
+ };
13464
+ }
13465
+ /** The argument the caret is in, by the overload whose leads the call follows most; the first on a tie. */
13466
+ function argumentOf(spec, call) {
13467
+ let best = null;
13468
+ for (const signature of spec.signatures) {
13469
+ const found = argumentAt(signature, call.separators ?? []);
13470
+ if (best === null || found.led > best.led) best = found;
13471
+ }
13472
+ return best?.argument ?? call.argument;
13473
+ }
13318
13474
  function relationKind(relation) {
13319
13475
  return relation.kind === "table" ? "table" : "view";
13320
13476
  }
@@ -13331,6 +13487,11 @@ function sqlCompleter(options) {
13331
13487
  function specNamed(name, server) {
13332
13488
  return specs.get(name.toUpperCase())?.find((spec) => isAvailable(spec, server));
13333
13489
  }
13490
+ /** The members of the package `qualifier` names, as offered after its dot. */
13491
+ function memberItems(qualifier, server) {
13492
+ const name = qualifier.map((part) => part.name.toUpperCase()).join(MEMBER_SEPARATOR);
13493
+ return availableFunctions(server, true).filter((spec) => typeof spec !== "string" && functionPackage(spec) === name).map((spec) => memberItem(spec, BOOST.function));
13494
+ }
13334
13495
  function quoted(name) {
13335
13496
  return options.plainIdentifier.test(name) && !reserved.has(name.toUpperCase()) ? name : options.quoteIdentifier(name);
13336
13497
  }
@@ -13355,10 +13516,12 @@ function sqlCompleter(options) {
13355
13516
  function keywordItems(except = /* @__PURE__ */ new Set()) {
13356
13517
  return options.keywords.filter((keyword) => !except.has(keyword.toUpperCase())).map((keyword) => item("keyword", keyword, keyword, null));
13357
13518
  }
13358
- function availableFunctions(server) {
13519
+ /** Plain functions, or with `members` the package members only: a bare name never offers `pkg.member`. */
13520
+ function availableFunctions(server, members = false) {
13359
13521
  const offered = /* @__PURE__ */ new Set();
13360
13522
  return options.functions.filter((spec) => {
13361
13523
  const name = functionName(spec).toUpperCase();
13524
+ if (functionPackage(spec) !== null !== members) return false;
13362
13525
  if (offered.has(name) || typeof spec !== "string" && !isAvailable(spec, server)) return false;
13363
13526
  offered.add(name);
13364
13527
  return true;
@@ -13369,17 +13532,18 @@ function sqlCompleter(options) {
13369
13532
  const last = qualifier.at(-1);
13370
13533
  if (last === void 0) return [];
13371
13534
  const relational = clause === "relation" || clause === "join";
13535
+ const members = relational ? [] : memberItems(qualifier, lookup.server);
13372
13536
  if (qualifier.length === 1 && !relational) {
13373
13537
  const source = sourceNamed(query, last);
13374
- if (source !== void 0) return columnItems(await lookup.columnsOf(source, query));
13538
+ if (source !== void 0) return [...columnItems(await lookup.columnsOf(source, query)), ...members];
13375
13539
  const cte = cteNamed(query, last);
13376
- if (cte !== void 0) return columnItems(await lookup.cteColumns(cte, 1));
13540
+ if (cte !== void 0) return [...columnItems(await lookup.cteColumns(cte, 1)), ...members];
13377
13541
  }
13378
13542
  const namespace = await lookup.namespace(qualifier);
13379
- if (namespace !== void 0) return relationItems(await lookup.relations(namespace.path), null);
13543
+ if (namespace !== void 0) return [...members, ...relationItems(await lookup.relations(namespace.path), null)];
13380
13544
  if (relational) return [];
13381
13545
  const found = await lookup.relation(qualifier.slice(0, -1), last);
13382
- return found === null ? [] : columnItems(found.relation.columns);
13546
+ return found === null ? members : [...columnItems(found.relation.columns), ...members];
13383
13547
  }
13384
13548
  async function relationContextItems(scope, lookup) {
13385
13549
  const current = lookup.current;
@@ -13688,14 +13852,18 @@ function sqlCompleter(options) {
13688
13852
  function signatureAt(request, catalog) {
13689
13853
  const { text, offset, shift } = wrap(request);
13690
13854
  const server = serverOf(catalog);
13691
- const call = callAt(text, offset, options.dialect, reserved, (name) => specNamed(name, server) !== void 0);
13855
+ const callable = (name) => {
13856
+ const spec = specNamed(name, server);
13857
+ return spec !== void 0 && spec.bare !== true;
13858
+ };
13859
+ const call = callAt(text, offset, options.dialect, reserved, callable);
13692
13860
  const spec = call === null ? void 0 : specNamed(call.name, server);
13693
13861
  if (call === null || spec === void 0) return Promise.resolve(null);
13694
13862
  return Promise.resolve({
13695
13863
  name: spec.name.toLowerCase(),
13696
13864
  summary: spec.summary,
13697
13865
  signatures: spec.signatures,
13698
- argument: call.argument,
13866
+ argument: argumentOf(spec, call),
13699
13867
  from: call.from - shift,
13700
13868
  to: call.to - shift
13701
13869
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablecraft-app/plugin-postgres",
3
- "version": "1.10.3",
3
+ "version": "1.10.4",
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.3.0"
27
+ "apiVersion": "1.4.0"
28
28
  }
29
29
  }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "id": "postgres",
3
3
  "name": "PostgreSQL",
4
- "version": "1.10.3",
5
- "apiVersion": "1.3.0",
4
+ "version": "1.10.4",
5
+ "apiVersion": "1.4.0",
6
6
  "entry": "index.js",
7
7
  "capabilities": [
8
8
  "sql",