@marimo-team/frontend 0.14.18-dev29 → 0.14.18-dev30
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/assets/{ConnectedDataExplorerComponent-ByyTMxAe.js → ConnectedDataExplorerComponent-oOiI8-Is.js} +1 -1
- package/dist/assets/{ImageComparisonComponent-BEvMtMGK.js → ImageComparisonComponent-CrBtZ5gk.js} +1 -1
- package/dist/assets/{VegaLite-B6ZXw089.js → VegaLite-BruLY7Yo.js} +1 -1
- package/dist/assets/{_baseEach-BM02cWfw.js → _baseEach-Dtl0u6a9.js} +1 -1
- package/dist/assets/_baseMap-BbSMx7sO.js +1 -0
- package/dist/assets/{_baseUniq-B3VNhTaG.js → _baseUniq-oH3tH_Lx.js} +1 -1
- package/dist/assets/{_createAggregator-CBRdQRkQ.js → _createAggregator-DVbCk7I8.js} +1 -1
- package/dist/assets/{any-language-editor-EOMlEVeL.js → any-language-editor-DNTe-hGh.js} +1 -1
- package/dist/assets/{architectureDiagram-SUXI7LT5-Bz_etWhT.js → architectureDiagram-SUXI7LT5-BNE5Ocu0.js} +1 -1
- package/dist/assets/{blockDiagram-6J76NXCF-C3NjjGV1.js → blockDiagram-6J76NXCF-BkAnLDAP.js} +1 -1
- package/dist/assets/{c4Diagram-6F6E4RAY-Cfcu16fD.js → c4Diagram-6F6E4RAY-CMvcINsX.js} +1 -1
- package/dist/assets/channel-AZKaNSLi.js +1 -0
- package/dist/assets/{chunk-353BL4L5-D_x_But5.js → chunk-353BL4L5-DZ6k9BBV.js} +1 -1
- package/dist/assets/{chunk-67H74DCK-B78ctzkW.js → chunk-67H74DCK-Btl2ATCi.js} +1 -1
- package/dist/assets/{chunk-AACKK3MU-C_X3yBIA.js → chunk-AACKK3MU-Di82a8tq.js} +1 -1
- package/dist/assets/{chunk-BFAMUDN2-CmT_5Wnf.js → chunk-BFAMUDN2-C6ACh81N.js} +1 -1
- package/dist/assets/{chunk-E2GYISFI-TLOBmOmy.js → chunk-E2GYISFI-BGhna3Tu.js} +1 -1
- package/dist/assets/{chunk-OW32GOEJ-C1x0Lb_3.js → chunk-OW32GOEJ-BvQbpZtP.js} +6 -6
- package/dist/assets/{chunk-SKB7J2MH-t9L60ESv.js → chunk-SKB7J2MH-B5xc8b3Z.js} +1 -1
- package/dist/assets/{chunk-SZ463SBG-OsFZC8Fm.js → chunk-SZ463SBG-DqkT0n2R.js} +1 -1
- package/dist/assets/{circle-play-Coa1pbLo.js → circle-play-DPIHEaaR.js} +1 -1
- package/dist/assets/classDiagram-M3E45YP4-B7yw2nKS.js +1 -0
- package/dist/assets/classDiagram-v2-YAWTLIQI-B7yw2nKS.js +1 -0
- package/dist/assets/clone-4KJc73U3.js +1 -0
- package/dist/assets/common-keywords-Dg3Y2cJS.js +1 -0
- package/dist/assets/{compile-kBFbLKtC.js → compile-DiFbtiAE.js} +1 -1
- package/dist/assets/{dagre-JOIXM2OF-KIVae2Ja.js → dagre-JOIXM2OF-1P_Dgkjl.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-ClaYc6AL.js → data-grid-overlay-editor-Dghfz964.js} +1 -1
- package/dist/assets/{diagram-5UYTHUR4-CAegkM8o.js → diagram-5UYTHUR4-56oBr9Mj.js} +1 -1
- package/dist/assets/{diagram-VMROVX33-COZimksW.js → diagram-VMROVX33-Bg7PYU8p.js} +1 -1
- package/dist/assets/{diagram-ZTM2IBQH-RPzV6IQt.js → diagram-ZTM2IBQH-CPzEgjbH.js} +1 -1
- package/dist/assets/duckdb-keywords-CFYiiNsB.js +1 -0
- package/dist/assets/{edit-page-Bj7J0vUV.js → edit-page-DCrlym3M.js} +4 -4
- package/dist/assets/{erDiagram-3M52JZNH-DyyQZo2F.js → erDiagram-3M52JZNH-T300kYM8.js} +1 -1
- package/dist/assets/{flowDiagram-KYDEHFYC-BY45MXHx.js → flowDiagram-KYDEHFYC-BYZfYSI2.js} +1 -1
- package/dist/assets/{ganttDiagram-EK5VF46D-D0SJ9Vb8.js → ganttDiagram-EK5VF46D-BEDi_5bs.js} +1 -1
- package/dist/assets/{gitGraphDiagram-GW3U2K7C-DQIrG7Ne.js → gitGraphDiagram-GW3U2K7C-Cu1vg-Ae.js} +1 -1
- package/dist/assets/{glide-data-editor-CvbrMET8.js → glide-data-editor-lK9K3ps-.js} +4 -4
- package/dist/assets/{graph-BvDRm3kJ.js → graph-CDj368Ef.js} +1 -1
- package/dist/assets/{home-page-StH-FqwP.js → home-page-Bke3YQtW.js} +2 -2
- package/dist/assets/{index-FjwIsM4E.js → index-BIamDpT3.js} +1 -1
- package/dist/assets/{index-BxpEkFHY.js → index-BdPIybcd.js} +1 -1
- package/dist/assets/{index-BMlE8K6G.js → index-BfMKs8fK.js} +188 -179
- package/dist/assets/{index-DeBpKt6z.js → index-BgN5JveD.js} +1 -1
- package/dist/assets/{index-D6ttr-M5.js → index-BlIpJJ1s.js} +1 -1
- package/dist/assets/{index-B2AnidM8.js → index-C1sif23O.js} +1 -1
- package/dist/assets/{index-Dl0aViKc.js → index-C5zHu97c.js} +1 -1
- package/dist/assets/{index-C1Ev5kmm.js → index-CHUAhpF9.js} +1 -1
- package/dist/assets/{index-nhAJG0Zq.js → index-CHvSTvku.js} +1 -1
- package/dist/assets/{index-BklcjKLc.js → index-CV-cT8XZ.js} +1 -1
- package/dist/assets/{index-DqW_iv-8.js → index-CVJgiMKT.js} +1 -1
- package/dist/assets/index-Cd8lKjXa.js +68 -0
- package/dist/assets/{index-DcCjqlwv.js → index-D2wUEqSr.js} +1 -1
- package/dist/assets/{index-BSAd1_jA.js → index-DQeLlRNN.js} +1 -1
- package/dist/assets/{index-D9fGE-pM.js → index-DdE5sj7B.js} +1 -1
- package/dist/assets/{index-DWx68F4W.js → index-DpaljNVK.js} +1 -1
- package/dist/assets/{index-BqgXsw2X.js → index-DskNGo48.js} +1 -1
- package/dist/assets/{index-v9Rqt1AL.js → index-PXSGnTt_.js} +1 -1
- package/dist/assets/{index-QQV-w55W.js → index-UakLQEhR.js} +1 -1
- package/dist/assets/{index-DXQK0dbr.js → index-uLE7UQoA.js} +1 -1
- package/dist/assets/infoDiagram-LHK5PUON-DvKYogid.js +2 -0
- package/dist/assets/{journeyDiagram-EWQZEKCU-Cv34gpl9.js → journeyDiagram-EWQZEKCU-qFhtMoPK.js} +1 -1
- package/dist/assets/{kanban-definition-ZSS6B67P-FTq3yb2c.js → kanban-definition-ZSS6B67P-d4c_bpNj.js} +1 -1
- package/dist/assets/{layout-DGo16j-R.js → layout-B1YrGZ5o.js} +1 -1
- package/dist/assets/{linear-0J3_DIzy.js → linear-Ce9Ln0y7.js} +1 -1
- package/dist/assets/{links-h2K0p6lB.js → links--FJRrKkU.js} +12 -12
- package/dist/assets/{mermaid-BfTGIKjH.js → mermaid-TIsLiY_c.js} +26 -26
- package/dist/assets/min-pEaRzhJa.js +1 -0
- package/dist/assets/{mindmap-definition-6CBA2TL7-BFWeE5l4.js → mindmap-definition-6CBA2TL7-NzRV0KhB.js} +1 -1
- package/dist/assets/{number-overlay-editor-nJ_uE4OC.js → number-overlay-editor-wIfVoa2g.js} +2 -2
- package/dist/assets/{pieDiagram-NIOCPIFQ-CIPNZnyq.js → pieDiagram-NIOCPIFQ-DLjq0P3e.js} +3 -3
- package/dist/assets/{quadrantDiagram-2OG54O6I-DFTpGGxg.js → quadrantDiagram-2OG54O6I-9Oz1n3p6.js} +1 -1
- package/dist/assets/{react-plotly-BHmRdjjS.js → react-plotly-CpyIgXbT.js} +1 -1
- package/dist/assets/{requirementDiagram-QOLK2EJ7-bhqWzDfk.js → requirementDiagram-QOLK2EJ7-efmOhh-Y.js} +1 -1
- package/dist/assets/{run-page-C08qMCRH.js → run-page-CigF14nw.js} +1 -1
- package/dist/assets/{sankeyDiagram-4UZDY2LN-CaS2yE0B.js → sankeyDiagram-4UZDY2LN-C8d1HP5D.js} +1 -1
- package/dist/assets/{sequenceDiagram-SKLFT4DO-B7DEVd4j.js → sequenceDiagram-SKLFT4DO-YYvQS_Ez.js} +1 -1
- package/dist/assets/{slides-component-CT3uDvEm.js → slides-component-DaIiszro.js} +1 -1
- package/dist/assets/sortBy-DPhCeare.js +1 -0
- package/dist/assets/{stateDiagram-MI5ZYTHO-DcIY6HTB.js → stateDiagram-MI5ZYTHO-BUsXwOkv.js} +1 -1
- package/dist/assets/stateDiagram-v2-5AN5P6BG-C0_3uVRU.js +1 -0
- package/dist/assets/{storage-Ciru-sFj.js → storage-DVfCYCuA.js} +5 -5
- package/dist/assets/{terminal-Pn5QVsJZ.js → terminal-WkSrTXmZ.js} +1 -1
- package/dist/assets/time-CMDJBHm4.js +1 -0
- package/dist/assets/{timeline-definition-MYPXXCX6-Cd626Lgg.js → timeline-definition-MYPXXCX6-D6F16eAY.js} +1 -1
- package/dist/assets/{tracing-B1pgg2Ra.js → tracing-Bs9fWQQg.js} +2 -2
- package/dist/assets/{trash-CKCjDfOY.js → trash-BotaB4h_.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-D6IH2czJ.js → treemap-75Q7IDZK-ReN7RgbK.js} +1 -1
- package/dist/assets/{vega-component-BbGjjrAW.js → vega-component-LxHHxxVY.js} +1 -1
- package/dist/assets/{xychartDiagram-H2YORKM3-Dk39Tmbz.js → xychartDiagram-H2YORKM3-BBA6XWcv.js} +1 -1
- package/dist/index.html +1 -1
- package/package.json +3 -2
- package/src/components/app-config/user-config-form.tsx +25 -0
- package/src/components/chat/markdown-renderer.tsx +1 -1
- package/src/components/editor/ai/add-cell-with-ai.tsx +1 -1
- package/src/components/editor/cell/CreateCellButton.tsx +1 -1
- package/src/components/editor/cell/code/language-toggle.tsx +1 -1
- package/src/components/editor/renderers/CellArray.tsx +1 -1
- package/src/core/codemirror/language/LanguageAdapters.ts +1 -1
- package/src/core/codemirror/language/__tests__/sql.test.ts +5 -5
- package/src/core/codemirror/language/extension.ts +1 -1
- package/src/core/codemirror/language/languages/sql/completion-sources.tsx +99 -0
- package/src/core/codemirror/language/languages/sql/completion-store.ts +191 -0
- package/src/core/codemirror/language/languages/{sql.ts → sql/sql.ts} +124 -248
- package/src/core/codemirror/language/languages/sql/utils.ts +42 -0
- package/src/core/codemirror/language/panel/panel.tsx +1 -1
- package/src/core/config/feature-flag.tsx +2 -0
- package/src/theme/useTheme.ts +1 -1
- package/dist/assets/_baseMap-CrbS00BX.js +0 -1
- package/dist/assets/channel-U5X5dN6K.js +0 -1
- package/dist/assets/classDiagram-M3E45YP4-7u91LcR8.js +0 -1
- package/dist/assets/classDiagram-v2-YAWTLIQI-7u91LcR8.js +0 -1
- package/dist/assets/clone-DltB19IA.js +0 -1
- package/dist/assets/infoDiagram-LHK5PUON-BI8vgvHA.js +0 -2
- package/dist/assets/min-BN2Aip45.js +0 -1
- package/dist/assets/sortBy-_N03fOwk.js +0 -1
- package/dist/assets/stateDiagram-v2-5AN5P6BG-BbbtK1gk.js +0 -1
- package/dist/assets/time-CzUrup3A.js +0 -1
- package/src/core/codemirror/language/languages/sql-dialects/README.md +0 -5
- package/src/core/codemirror/language/languages/sql-dialects/duckdb.ts +0 -22
- package/src/core/codemirror/language/languages/sql-dialects/spec_duckdb.py +0 -257
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
} from "@codemirror/autocomplete";
|
|
7
7
|
import { PostgreSQL } from "@codemirror/lang-sql";
|
|
8
8
|
import { EditorState, type Extension } from "@codemirror/state";
|
|
9
|
+
import { DuckDBDialect } from "@marimo-team/codemirror-sql/dialects";
|
|
9
10
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
10
11
|
import type { DataSourceConnection } from "@/core/datasets/data-source-connections";
|
|
11
12
|
import {
|
|
@@ -16,12 +17,11 @@ import { type ConnectionName, DUCKDB_ENGINE } from "@/core/datasets/engines";
|
|
|
16
17
|
import { datasetsAtom } from "@/core/datasets/state";
|
|
17
18
|
import type { DatasetsState } from "@/core/datasets/types";
|
|
18
19
|
import { store } from "@/core/state/jotai";
|
|
20
|
+
import { TestSQLCompletionStore } from "../languages/sql/completion-store";
|
|
19
21
|
import {
|
|
20
|
-
SQLCompletionStore,
|
|
21
22
|
SQLLanguageAdapter,
|
|
22
23
|
type SQLLanguageAdapterMetadata,
|
|
23
|
-
} from "../languages/sql";
|
|
24
|
-
import { DuckDBDialect } from "../languages/sql-dialects/duckdb";
|
|
24
|
+
} from "../languages/sql/sql";
|
|
25
25
|
import { languageMetadataField } from "../metadata";
|
|
26
26
|
|
|
27
27
|
const adapter = new SQLLanguageAdapter();
|
|
@@ -618,7 +618,7 @@ _df = mo.sql(
|
|
|
618
618
|
|
|
619
619
|
describe("tablesCompletionSource", () => {
|
|
620
620
|
const mockStore = store;
|
|
621
|
-
const completionStore = new
|
|
621
|
+
const completionStore = new TestSQLCompletionStore();
|
|
622
622
|
|
|
623
623
|
beforeEach(() => {
|
|
624
624
|
// Reset the adapter engine
|
|
@@ -1184,7 +1184,7 @@ describe("tablesCompletionSource", () => {
|
|
|
1184
1184
|
];
|
|
1185
1185
|
|
|
1186
1186
|
describe("SQL Completions", () => {
|
|
1187
|
-
const completionStore = new
|
|
1187
|
+
const completionStore = new TestSQLCompletionStore();
|
|
1188
1188
|
|
|
1189
1189
|
beforeEach(() => {
|
|
1190
1190
|
// Reset state
|
|
@@ -28,7 +28,7 @@ import { historyCompartment } from "../editing/extensions";
|
|
|
28
28
|
import { formattingChangeEffect } from "../format";
|
|
29
29
|
import { createPanel } from "../react-dom/createPanel";
|
|
30
30
|
import { getLanguageAdapters, LanguageAdapters } from "./LanguageAdapters";
|
|
31
|
-
import { initializeSQLDialect } from "./languages/sql";
|
|
31
|
+
import { initializeSQLDialect } from "./languages/sql/sql";
|
|
32
32
|
import type { LanguageMetadata } from "./metadata";
|
|
33
33
|
import { languageMetadataField, setLanguageMetadata } from "./metadata";
|
|
34
34
|
import { LanguagePanelComponent } from "./panel/panel";
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { Completion, CompletionSource } from "@codemirror/autocomplete";
|
|
4
|
+
import {
|
|
5
|
+
keywordCompletionSource,
|
|
6
|
+
schemaCompletionSource,
|
|
7
|
+
} from "@codemirror/lang-sql";
|
|
8
|
+
import type { EditorState } from "@codemirror/state";
|
|
9
|
+
import { DefaultSqlTooltipRenders } from "@marimo-team/codemirror-sql";
|
|
10
|
+
import { languageMetadataField } from "../../metadata";
|
|
11
|
+
import { SCHEMA_CACHE } from "./completion-store";
|
|
12
|
+
import type { SQLLanguageAdapterMetadata } from "./sql";
|
|
13
|
+
|
|
14
|
+
function getSQLMetadata(state: EditorState): SQLLanguageAdapterMetadata {
|
|
15
|
+
return state.field(languageMetadataField) as SQLLanguageAdapterMetadata;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Custom schema completion source that dynamically gets the Dialect and SQL tables.
|
|
20
|
+
*/
|
|
21
|
+
export function tablesCompletionSource(): CompletionSource {
|
|
22
|
+
return (ctx) => {
|
|
23
|
+
const metadata = getSQLMetadata(ctx.state);
|
|
24
|
+
const connectionName = metadata.engine;
|
|
25
|
+
const config = SCHEMA_CACHE.getCompletionSource(connectionName);
|
|
26
|
+
|
|
27
|
+
if (!config) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return schemaCompletionSource(config)(ctx);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Custom keyword completion source that dynamically gets the Dialect.
|
|
37
|
+
* This also ignores keyword completions on table columns.
|
|
38
|
+
*/
|
|
39
|
+
export function customKeywordCompletionSource(): CompletionSource {
|
|
40
|
+
return (ctx) => {
|
|
41
|
+
const metadata = getSQLMetadata(ctx.state);
|
|
42
|
+
const connectionName = metadata.engine;
|
|
43
|
+
const dialect = SCHEMA_CACHE.getDialect(connectionName);
|
|
44
|
+
|
|
45
|
+
// We want to ignore keyword completions on something like
|
|
46
|
+
// `WHERE my_table.col`
|
|
47
|
+
// ^cursor
|
|
48
|
+
const textBefore = ctx.matchBefore(/\.\w*/);
|
|
49
|
+
if (textBefore) {
|
|
50
|
+
// If there is a match, we are typing after a dot,
|
|
51
|
+
// so we don't want to trigger SQL keyword completion
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const keywordRenderer = (label: string, type: string): Completion => {
|
|
56
|
+
return {
|
|
57
|
+
label,
|
|
58
|
+
type,
|
|
59
|
+
info: async () => {
|
|
60
|
+
const keywordDocs = await getKeywordDocs();
|
|
61
|
+
const keywordInfo = keywordDocs[label.toLocaleLowerCase()];
|
|
62
|
+
if (!keywordInfo) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const dom = document.createElement("div");
|
|
67
|
+
dom.innerHTML = DefaultSqlTooltipRenders.keyword({
|
|
68
|
+
keyword: label,
|
|
69
|
+
info: keywordInfo,
|
|
70
|
+
});
|
|
71
|
+
return dom;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const uppercaseKeywords = true;
|
|
77
|
+
const result = keywordCompletionSource(
|
|
78
|
+
dialect,
|
|
79
|
+
uppercaseKeywords,
|
|
80
|
+
keywordRenderer,
|
|
81
|
+
)(ctx);
|
|
82
|
+
return result;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// e.g. lazily load keyword docs
|
|
87
|
+
const getKeywordDocs = async (): Promise<Record<string, unknown>> => {
|
|
88
|
+
const keywords = await import(
|
|
89
|
+
"@marimo-team/codemirror-sql/data/common-keywords.json"
|
|
90
|
+
);
|
|
91
|
+
// Include DuckDB for now, but we can remove this once we have a better way to handle dialect-specific keywords
|
|
92
|
+
const duckdbKeywords = await import(
|
|
93
|
+
"@marimo-team/codemirror-sql/data/duckdb-keywords.json"
|
|
94
|
+
);
|
|
95
|
+
return {
|
|
96
|
+
...keywords.default.keywords,
|
|
97
|
+
...duckdbKeywords.default.keywords,
|
|
98
|
+
};
|
|
99
|
+
};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type SQLConfig,
|
|
5
|
+
type SQLDialect,
|
|
6
|
+
StandardSQL,
|
|
7
|
+
} from "@codemirror/lang-sql";
|
|
8
|
+
import { isSchemaless } from "@/components/datasources/utils";
|
|
9
|
+
import { dataConnectionsMapAtom } from "@/core/datasets/data-source-connections";
|
|
10
|
+
import type { ConnectionName } from "@/core/datasets/engines";
|
|
11
|
+
import { datasetTablesAtom } from "@/core/datasets/state";
|
|
12
|
+
import type { DataSourceConnection } from "@/core/kernel/messages";
|
|
13
|
+
import { store } from "@/core/state/jotai";
|
|
14
|
+
import { LRUCache } from "@/utils/lru";
|
|
15
|
+
import { guessDialect } from "./utils";
|
|
16
|
+
|
|
17
|
+
type TableToCols = Record<string, string[]>;
|
|
18
|
+
type Schemas = Record<string, TableToCols>;
|
|
19
|
+
type CachedSchema = Pick<SQLConfig, "schema" | "defaultSchema"> & {
|
|
20
|
+
shouldAddLocalTables: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
class SQLCompletionStore {
|
|
24
|
+
private cache: LRUCache<DataSourceConnection, CachedSchema>;
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
this.cache = new LRUCache(10, {
|
|
28
|
+
create: (connection) => this.getConnectionSchema(connection),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private getConnection(
|
|
33
|
+
connectionName: ConnectionName,
|
|
34
|
+
): DataSourceConnection | undefined {
|
|
35
|
+
const dataConnectionsMap = store.get(dataConnectionsMapAtom);
|
|
36
|
+
return dataConnectionsMap.get(connectionName);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private getConnectionSchema(connection: DataSourceConnection): CachedSchema {
|
|
40
|
+
const schemaMap: Record<string, TableToCols> = {};
|
|
41
|
+
const databaseMap: Record<string, Schemas> = {};
|
|
42
|
+
|
|
43
|
+
// When there is only one database, it is the default
|
|
44
|
+
const defaultDb = connection.databases.find(
|
|
45
|
+
(db) =>
|
|
46
|
+
db.name === connection.default_database ||
|
|
47
|
+
connection.databases.length === 1,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const dbToVerify = defaultDb ?? connection.databases[0];
|
|
51
|
+
const isSchemalessDb =
|
|
52
|
+
dbToVerify?.schemas.some((schema) => isSchemaless(schema.name)) ?? false;
|
|
53
|
+
|
|
54
|
+
// For schemaless databases, treat databases as schemas
|
|
55
|
+
if (isSchemalessDb) {
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
const dbToTablesMap: Record<string, any> = {};
|
|
58
|
+
|
|
59
|
+
for (const db of connection.databases) {
|
|
60
|
+
const isDefaultDb = db.name === defaultDb?.name;
|
|
61
|
+
|
|
62
|
+
for (const schema of db.schemas) {
|
|
63
|
+
for (const table of schema.tables) {
|
|
64
|
+
const columns = table.columns.map((col) => col.name);
|
|
65
|
+
|
|
66
|
+
if (isDefaultDb) {
|
|
67
|
+
// For default database, add tables directly to top level
|
|
68
|
+
dbToTablesMap[table.name] = columns;
|
|
69
|
+
} else {
|
|
70
|
+
// Otherwise nest under database name
|
|
71
|
+
dbToTablesMap[db.name] = dbToTablesMap[db.name] || {};
|
|
72
|
+
dbToTablesMap[db.name][table.name] = columns;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
shouldAddLocalTables: false,
|
|
80
|
+
schema: dbToTablesMap,
|
|
81
|
+
defaultSchema: defaultDb?.name,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// For default db, we can use the schema name directly
|
|
86
|
+
for (const schema of defaultDb?.schemas ?? []) {
|
|
87
|
+
schemaMap[schema.name] = {};
|
|
88
|
+
for (const table of schema.tables) {
|
|
89
|
+
const columns = table.columns.map((col) => col.name);
|
|
90
|
+
schemaMap[schema.name][table.name] = columns;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Otherwise, we need to use the fully qualified name
|
|
95
|
+
for (const database of connection.databases) {
|
|
96
|
+
if (database.name === defaultDb?.name) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
databaseMap[database.name] = {};
|
|
100
|
+
|
|
101
|
+
for (const schema of database.schemas) {
|
|
102
|
+
databaseMap[database.name][schema.name] = {};
|
|
103
|
+
|
|
104
|
+
for (const table of schema.tables) {
|
|
105
|
+
const columns = table.columns.map((col) => col.name);
|
|
106
|
+
databaseMap[database.name][schema.name][table.name] = columns;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
shouldAddLocalTables: true,
|
|
113
|
+
schema: { ...databaseMap, ...schemaMap },
|
|
114
|
+
defaultSchema: connection.default_schema ?? undefined,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns the raw dialect of the connection passed from the backend,
|
|
120
|
+
* or null if the connection is not found
|
|
121
|
+
*/
|
|
122
|
+
getInternalDialect(connectionName: ConnectionName): string | null {
|
|
123
|
+
const connection = this.getConnection(connectionName);
|
|
124
|
+
if (!connection) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
return connection.dialect;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get the inferred SQL dialect for a connection
|
|
132
|
+
* If the connection is not found, return the standard SQL dialect.
|
|
133
|
+
*/
|
|
134
|
+
getDialect(connectionName: ConnectionName): SQLDialect {
|
|
135
|
+
const connection = this.getConnection(connectionName);
|
|
136
|
+
if (!connection) {
|
|
137
|
+
return StandardSQL;
|
|
138
|
+
}
|
|
139
|
+
return guessDialect(connection) ?? StandardSQL;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getCompletionSource(connectionName: ConnectionName): SQLConfig | null {
|
|
143
|
+
const connection = this.getConnection(connectionName);
|
|
144
|
+
if (!connection) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const getTablesMap = () => {
|
|
149
|
+
const localTables = store.get(datasetTablesAtom);
|
|
150
|
+
// If there is a conflict with connection tables,
|
|
151
|
+
// the engine will prioritize the connection tables without special handling
|
|
152
|
+
const tablesMap: TableToCols = {};
|
|
153
|
+
for (const table of localTables) {
|
|
154
|
+
const tableColumns = table.columns.map((col) => col.name);
|
|
155
|
+
tablesMap[table.name] = tableColumns;
|
|
156
|
+
}
|
|
157
|
+
return tablesMap;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const schema = this.cache.getOrCreate(connection);
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
dialect: guessDialect(connection),
|
|
164
|
+
schema: schema.shouldAddLocalTables
|
|
165
|
+
? { ...schema.schema, ...getTablesMap() }
|
|
166
|
+
: schema.schema,
|
|
167
|
+
defaultSchema: schema.defaultSchema,
|
|
168
|
+
defaultTable: getSingleTable(connection),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function getSingleTable(connection: DataSourceConnection): string | undefined {
|
|
174
|
+
if (connection.databases.length !== 1) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
const database = connection.databases[0];
|
|
178
|
+
if (database.schemas.length !== 1) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const schema = database.schemas[0];
|
|
182
|
+
if (schema.tables.length !== 1) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
return schema.tables[0].name;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export const SCHEMA_CACHE = new SQLCompletionStore();
|
|
189
|
+
|
|
190
|
+
// For testing
|
|
191
|
+
export { SQLCompletionStore as TestSQLCompletionStore };
|