sqllens 1.5.0 → 1.5.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.
|
@@ -131,7 +131,8 @@ function collect(doc, offset, schema) {
|
|
|
131
131
|
// failure the bare-slot fallback covers. Its member twin: read `FROM/JOIN name [alias]`
|
|
132
132
|
// pairs off the token stream and answer the matching relation's schema columns.
|
|
133
133
|
if (scoped.length === 0 && schema) {
|
|
134
|
-
|
|
134
|
+
const fallback = qualifiedFallbackColumns(walkTokens, cfg, path.parts, schema, dialect, doc.templated?.tags, doc.text);
|
|
135
|
+
for (const c of fallback)
|
|
135
136
|
add(c);
|
|
136
137
|
}
|
|
137
138
|
}
|
|
@@ -322,16 +323,45 @@ function qualifiedSourceColumns(scopes, ast, offset, qualParts, dialect, schema)
|
|
|
322
323
|
/** The member-position twin of `fromRelationColumns` (#38): when the scope is empty (the dangling
|
|
323
324
|
* dot broke the FROM parse), read `FROM/JOIN name(.name)* [AS] [alias]` off the token stream and
|
|
324
325
|
* answer the columns of the ONE relation the qualifier matches — the alias when present, else the
|
|
325
|
-
* name's own trailing parts.
|
|
326
|
-
|
|
326
|
+
* name's own trailing parts. A templated source ({{ ref() }} c) is resolved through the provider
|
|
327
|
+
* (relationOf), matching the qualifier to its alias — the same seam `fromRelationColumns` uses. No
|
|
328
|
+
* match (or several) answers [] — never a fabricated union. */
|
|
329
|
+
function qualifiedFallbackColumns(walkTokens, cfg, qualParts, schema, dialect, tags, text) {
|
|
327
330
|
if (cfg.relationKeywordTokens.size === 0)
|
|
328
331
|
return [];
|
|
329
332
|
const b = resolveBehavior(dialect);
|
|
330
333
|
const toks = walkTokens.filter((t) => t.channel === Token.DEFAULT_CHANNEL);
|
|
331
334
|
const hits = [];
|
|
335
|
+
const colHits = (cols) => {
|
|
336
|
+
if (cols)
|
|
337
|
+
hits.push(cols.map((c) => ({ label: c.name, kind: "column", detail: c.type })));
|
|
338
|
+
};
|
|
332
339
|
for (let i = 0; i + 1 < toks.length; i++) {
|
|
333
340
|
if (!cfg.relationKeywordTokens.has(toks[i].type))
|
|
334
341
|
continue;
|
|
342
|
+
// A templated source ({{ ref('customers') }} c) blanks to a channel-2 tag the filter drops, so
|
|
343
|
+
// the next SQL token is the ALIAS, not a relation name. Resolve the relation through the provider
|
|
344
|
+
// (relationOf) — the same seam fromRelationColumns uses — and match the qualifier to that alias;
|
|
345
|
+
// without this, the alias got read AS the relation name and columnsFor answered nothing.
|
|
346
|
+
const kw = toks[i];
|
|
347
|
+
const next = toks[i + 1];
|
|
348
|
+
const tag = tags?.find((t) => t.kind === "call" && t.tagSpan.start >= kw.start && t.tagSpan.start < next.start);
|
|
349
|
+
if (tag) {
|
|
350
|
+
if (schema instanceof DefaultTemplateProvider) {
|
|
351
|
+
let a = i + 1;
|
|
352
|
+
if (toks[a] && b.fold(toks[a].text) === "as")
|
|
353
|
+
a++;
|
|
354
|
+
const alias = toks[a];
|
|
355
|
+
if (alias &&
|
|
356
|
+
cfg.nameTokens.has(alias.type) &&
|
|
357
|
+
qualParts.length === 1 &&
|
|
358
|
+
b.fold(qualParts[0]) === b.fold(alias.text)) {
|
|
359
|
+
const rel = schema.relationOf(callOf(tag, text));
|
|
360
|
+
colHits(rel ? (rel.columns ?? schema.columnsFor(rel.nameParts, dialect)) : undefined);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
continue; // templated source handled (or unresolvable) — never treat the alias as a relation name
|
|
364
|
+
}
|
|
335
365
|
let j = i + 1;
|
|
336
366
|
if (!toks[j] || !cfg.nameTokens.has(toks[j].type))
|
|
337
367
|
continue;
|
|
@@ -352,9 +382,7 @@ function qualifiedFallbackColumns(walkTokens, cfg, qualParts, schema, dialect) {
|
|
|
352
382
|
qualParts.every((p, k) => b.fold(p, "table") === b.fold(parts[parts.length - qualParts.length + k], "table"));
|
|
353
383
|
if (!matches)
|
|
354
384
|
continue;
|
|
355
|
-
|
|
356
|
-
if (cols)
|
|
357
|
-
hits.push(cols.map((c) => ({ label: c.name, kind: "column", detail: c.type })));
|
|
385
|
+
colHits(schema.columnsFor(parts, dialect));
|
|
358
386
|
}
|
|
359
387
|
return hits.length === 1 ? hits[0] : [];
|
|
360
388
|
}
|
package/dist/symbols/symbols.js
CHANGED
|
@@ -422,7 +422,10 @@ function relationSymbol(src, frame, dialect) {
|
|
|
422
422
|
return {
|
|
423
423
|
kind: "table",
|
|
424
424
|
modifiers: ref,
|
|
425
|
-
|
|
425
|
+
// DISPLAY spelling, from relation.parts — NOT src.name, which is the folded identity key
|
|
426
|
+
// (#38). displaying the key uppercases the name on a case-folding dialect; matches the CTE
|
|
427
|
+
// branch's display convention and scope.d.ts's "never show name" contract.
|
|
428
|
+
name: src.source.relation.parts.map(show).join("."),
|
|
426
429
|
span: spanOf(src.source.cst),
|
|
427
430
|
frame,
|
|
428
431
|
node: src.source,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sqllens",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "A TypeScript SQL parser and static analyzer: parse, resolve names, infer types, and trace column lineage across many SQL dialects (Databricks, T-SQL, Snowflake, BigQuery, Redshift, PostgreSQL, DuckDB, Trino, SQLite, MySQL).",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|