@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.
Files changed (121) hide show
  1. package/dist/assets/{ConnectedDataExplorerComponent-ByyTMxAe.js → ConnectedDataExplorerComponent-oOiI8-Is.js} +1 -1
  2. package/dist/assets/{ImageComparisonComponent-BEvMtMGK.js → ImageComparisonComponent-CrBtZ5gk.js} +1 -1
  3. package/dist/assets/{VegaLite-B6ZXw089.js → VegaLite-BruLY7Yo.js} +1 -1
  4. package/dist/assets/{_baseEach-BM02cWfw.js → _baseEach-Dtl0u6a9.js} +1 -1
  5. package/dist/assets/_baseMap-BbSMx7sO.js +1 -0
  6. package/dist/assets/{_baseUniq-B3VNhTaG.js → _baseUniq-oH3tH_Lx.js} +1 -1
  7. package/dist/assets/{_createAggregator-CBRdQRkQ.js → _createAggregator-DVbCk7I8.js} +1 -1
  8. package/dist/assets/{any-language-editor-EOMlEVeL.js → any-language-editor-DNTe-hGh.js} +1 -1
  9. package/dist/assets/{architectureDiagram-SUXI7LT5-Bz_etWhT.js → architectureDiagram-SUXI7LT5-BNE5Ocu0.js} +1 -1
  10. package/dist/assets/{blockDiagram-6J76NXCF-C3NjjGV1.js → blockDiagram-6J76NXCF-BkAnLDAP.js} +1 -1
  11. package/dist/assets/{c4Diagram-6F6E4RAY-Cfcu16fD.js → c4Diagram-6F6E4RAY-CMvcINsX.js} +1 -1
  12. package/dist/assets/channel-AZKaNSLi.js +1 -0
  13. package/dist/assets/{chunk-353BL4L5-D_x_But5.js → chunk-353BL4L5-DZ6k9BBV.js} +1 -1
  14. package/dist/assets/{chunk-67H74DCK-B78ctzkW.js → chunk-67H74DCK-Btl2ATCi.js} +1 -1
  15. package/dist/assets/{chunk-AACKK3MU-C_X3yBIA.js → chunk-AACKK3MU-Di82a8tq.js} +1 -1
  16. package/dist/assets/{chunk-BFAMUDN2-CmT_5Wnf.js → chunk-BFAMUDN2-C6ACh81N.js} +1 -1
  17. package/dist/assets/{chunk-E2GYISFI-TLOBmOmy.js → chunk-E2GYISFI-BGhna3Tu.js} +1 -1
  18. package/dist/assets/{chunk-OW32GOEJ-C1x0Lb_3.js → chunk-OW32GOEJ-BvQbpZtP.js} +6 -6
  19. package/dist/assets/{chunk-SKB7J2MH-t9L60ESv.js → chunk-SKB7J2MH-B5xc8b3Z.js} +1 -1
  20. package/dist/assets/{chunk-SZ463SBG-OsFZC8Fm.js → chunk-SZ463SBG-DqkT0n2R.js} +1 -1
  21. package/dist/assets/{circle-play-Coa1pbLo.js → circle-play-DPIHEaaR.js} +1 -1
  22. package/dist/assets/classDiagram-M3E45YP4-B7yw2nKS.js +1 -0
  23. package/dist/assets/classDiagram-v2-YAWTLIQI-B7yw2nKS.js +1 -0
  24. package/dist/assets/clone-4KJc73U3.js +1 -0
  25. package/dist/assets/common-keywords-Dg3Y2cJS.js +1 -0
  26. package/dist/assets/{compile-kBFbLKtC.js → compile-DiFbtiAE.js} +1 -1
  27. package/dist/assets/{dagre-JOIXM2OF-KIVae2Ja.js → dagre-JOIXM2OF-1P_Dgkjl.js} +1 -1
  28. package/dist/assets/{data-grid-overlay-editor-ClaYc6AL.js → data-grid-overlay-editor-Dghfz964.js} +1 -1
  29. package/dist/assets/{diagram-5UYTHUR4-CAegkM8o.js → diagram-5UYTHUR4-56oBr9Mj.js} +1 -1
  30. package/dist/assets/{diagram-VMROVX33-COZimksW.js → diagram-VMROVX33-Bg7PYU8p.js} +1 -1
  31. package/dist/assets/{diagram-ZTM2IBQH-RPzV6IQt.js → diagram-ZTM2IBQH-CPzEgjbH.js} +1 -1
  32. package/dist/assets/duckdb-keywords-CFYiiNsB.js +1 -0
  33. package/dist/assets/{edit-page-Bj7J0vUV.js → edit-page-DCrlym3M.js} +4 -4
  34. package/dist/assets/{erDiagram-3M52JZNH-DyyQZo2F.js → erDiagram-3M52JZNH-T300kYM8.js} +1 -1
  35. package/dist/assets/{flowDiagram-KYDEHFYC-BY45MXHx.js → flowDiagram-KYDEHFYC-BYZfYSI2.js} +1 -1
  36. package/dist/assets/{ganttDiagram-EK5VF46D-D0SJ9Vb8.js → ganttDiagram-EK5VF46D-BEDi_5bs.js} +1 -1
  37. package/dist/assets/{gitGraphDiagram-GW3U2K7C-DQIrG7Ne.js → gitGraphDiagram-GW3U2K7C-Cu1vg-Ae.js} +1 -1
  38. package/dist/assets/{glide-data-editor-CvbrMET8.js → glide-data-editor-lK9K3ps-.js} +4 -4
  39. package/dist/assets/{graph-BvDRm3kJ.js → graph-CDj368Ef.js} +1 -1
  40. package/dist/assets/{home-page-StH-FqwP.js → home-page-Bke3YQtW.js} +2 -2
  41. package/dist/assets/{index-FjwIsM4E.js → index-BIamDpT3.js} +1 -1
  42. package/dist/assets/{index-BxpEkFHY.js → index-BdPIybcd.js} +1 -1
  43. package/dist/assets/{index-BMlE8K6G.js → index-BfMKs8fK.js} +188 -179
  44. package/dist/assets/{index-DeBpKt6z.js → index-BgN5JveD.js} +1 -1
  45. package/dist/assets/{index-D6ttr-M5.js → index-BlIpJJ1s.js} +1 -1
  46. package/dist/assets/{index-B2AnidM8.js → index-C1sif23O.js} +1 -1
  47. package/dist/assets/{index-Dl0aViKc.js → index-C5zHu97c.js} +1 -1
  48. package/dist/assets/{index-C1Ev5kmm.js → index-CHUAhpF9.js} +1 -1
  49. package/dist/assets/{index-nhAJG0Zq.js → index-CHvSTvku.js} +1 -1
  50. package/dist/assets/{index-BklcjKLc.js → index-CV-cT8XZ.js} +1 -1
  51. package/dist/assets/{index-DqW_iv-8.js → index-CVJgiMKT.js} +1 -1
  52. package/dist/assets/index-Cd8lKjXa.js +68 -0
  53. package/dist/assets/{index-DcCjqlwv.js → index-D2wUEqSr.js} +1 -1
  54. package/dist/assets/{index-BSAd1_jA.js → index-DQeLlRNN.js} +1 -1
  55. package/dist/assets/{index-D9fGE-pM.js → index-DdE5sj7B.js} +1 -1
  56. package/dist/assets/{index-DWx68F4W.js → index-DpaljNVK.js} +1 -1
  57. package/dist/assets/{index-BqgXsw2X.js → index-DskNGo48.js} +1 -1
  58. package/dist/assets/{index-v9Rqt1AL.js → index-PXSGnTt_.js} +1 -1
  59. package/dist/assets/{index-QQV-w55W.js → index-UakLQEhR.js} +1 -1
  60. package/dist/assets/{index-DXQK0dbr.js → index-uLE7UQoA.js} +1 -1
  61. package/dist/assets/infoDiagram-LHK5PUON-DvKYogid.js +2 -0
  62. package/dist/assets/{journeyDiagram-EWQZEKCU-Cv34gpl9.js → journeyDiagram-EWQZEKCU-qFhtMoPK.js} +1 -1
  63. package/dist/assets/{kanban-definition-ZSS6B67P-FTq3yb2c.js → kanban-definition-ZSS6B67P-d4c_bpNj.js} +1 -1
  64. package/dist/assets/{layout-DGo16j-R.js → layout-B1YrGZ5o.js} +1 -1
  65. package/dist/assets/{linear-0J3_DIzy.js → linear-Ce9Ln0y7.js} +1 -1
  66. package/dist/assets/{links-h2K0p6lB.js → links--FJRrKkU.js} +12 -12
  67. package/dist/assets/{mermaid-BfTGIKjH.js → mermaid-TIsLiY_c.js} +26 -26
  68. package/dist/assets/min-pEaRzhJa.js +1 -0
  69. package/dist/assets/{mindmap-definition-6CBA2TL7-BFWeE5l4.js → mindmap-definition-6CBA2TL7-NzRV0KhB.js} +1 -1
  70. package/dist/assets/{number-overlay-editor-nJ_uE4OC.js → number-overlay-editor-wIfVoa2g.js} +2 -2
  71. package/dist/assets/{pieDiagram-NIOCPIFQ-CIPNZnyq.js → pieDiagram-NIOCPIFQ-DLjq0P3e.js} +3 -3
  72. package/dist/assets/{quadrantDiagram-2OG54O6I-DFTpGGxg.js → quadrantDiagram-2OG54O6I-9Oz1n3p6.js} +1 -1
  73. package/dist/assets/{react-plotly-BHmRdjjS.js → react-plotly-CpyIgXbT.js} +1 -1
  74. package/dist/assets/{requirementDiagram-QOLK2EJ7-bhqWzDfk.js → requirementDiagram-QOLK2EJ7-efmOhh-Y.js} +1 -1
  75. package/dist/assets/{run-page-C08qMCRH.js → run-page-CigF14nw.js} +1 -1
  76. package/dist/assets/{sankeyDiagram-4UZDY2LN-CaS2yE0B.js → sankeyDiagram-4UZDY2LN-C8d1HP5D.js} +1 -1
  77. package/dist/assets/{sequenceDiagram-SKLFT4DO-B7DEVd4j.js → sequenceDiagram-SKLFT4DO-YYvQS_Ez.js} +1 -1
  78. package/dist/assets/{slides-component-CT3uDvEm.js → slides-component-DaIiszro.js} +1 -1
  79. package/dist/assets/sortBy-DPhCeare.js +1 -0
  80. package/dist/assets/{stateDiagram-MI5ZYTHO-DcIY6HTB.js → stateDiagram-MI5ZYTHO-BUsXwOkv.js} +1 -1
  81. package/dist/assets/stateDiagram-v2-5AN5P6BG-C0_3uVRU.js +1 -0
  82. package/dist/assets/{storage-Ciru-sFj.js → storage-DVfCYCuA.js} +5 -5
  83. package/dist/assets/{terminal-Pn5QVsJZ.js → terminal-WkSrTXmZ.js} +1 -1
  84. package/dist/assets/time-CMDJBHm4.js +1 -0
  85. package/dist/assets/{timeline-definition-MYPXXCX6-Cd626Lgg.js → timeline-definition-MYPXXCX6-D6F16eAY.js} +1 -1
  86. package/dist/assets/{tracing-B1pgg2Ra.js → tracing-Bs9fWQQg.js} +2 -2
  87. package/dist/assets/{trash-CKCjDfOY.js → trash-BotaB4h_.js} +1 -1
  88. package/dist/assets/{treemap-75Q7IDZK-D6IH2czJ.js → treemap-75Q7IDZK-ReN7RgbK.js} +1 -1
  89. package/dist/assets/{vega-component-BbGjjrAW.js → vega-component-LxHHxxVY.js} +1 -1
  90. package/dist/assets/{xychartDiagram-H2YORKM3-Dk39Tmbz.js → xychartDiagram-H2YORKM3-BBA6XWcv.js} +1 -1
  91. package/dist/index.html +1 -1
  92. package/package.json +3 -2
  93. package/src/components/app-config/user-config-form.tsx +25 -0
  94. package/src/components/chat/markdown-renderer.tsx +1 -1
  95. package/src/components/editor/ai/add-cell-with-ai.tsx +1 -1
  96. package/src/components/editor/cell/CreateCellButton.tsx +1 -1
  97. package/src/components/editor/cell/code/language-toggle.tsx +1 -1
  98. package/src/components/editor/renderers/CellArray.tsx +1 -1
  99. package/src/core/codemirror/language/LanguageAdapters.ts +1 -1
  100. package/src/core/codemirror/language/__tests__/sql.test.ts +5 -5
  101. package/src/core/codemirror/language/extension.ts +1 -1
  102. package/src/core/codemirror/language/languages/sql/completion-sources.tsx +99 -0
  103. package/src/core/codemirror/language/languages/sql/completion-store.ts +191 -0
  104. package/src/core/codemirror/language/languages/{sql.ts → sql/sql.ts} +124 -248
  105. package/src/core/codemirror/language/languages/sql/utils.ts +42 -0
  106. package/src/core/codemirror/language/panel/panel.tsx +1 -1
  107. package/src/core/config/feature-flag.tsx +2 -0
  108. package/src/theme/useTheme.ts +1 -1
  109. package/dist/assets/_baseMap-CrbS00BX.js +0 -1
  110. package/dist/assets/channel-U5X5dN6K.js +0 -1
  111. package/dist/assets/classDiagram-M3E45YP4-7u91LcR8.js +0 -1
  112. package/dist/assets/classDiagram-v2-YAWTLIQI-7u91LcR8.js +0 -1
  113. package/dist/assets/clone-DltB19IA.js +0 -1
  114. package/dist/assets/infoDiagram-LHK5PUON-BI8vgvHA.js +0 -2
  115. package/dist/assets/min-BN2Aip45.js +0 -1
  116. package/dist/assets/sortBy-_N03fOwk.js +0 -1
  117. package/dist/assets/stateDiagram-v2-5AN5P6BG-BbbtK1gk.js +0 -1
  118. package/dist/assets/time-CzUrup3A.js +0 -1
  119. package/src/core/codemirror/language/languages/sql-dialects/README.md +0 -5
  120. package/src/core/codemirror/language/languages/sql-dialects/duckdb.ts +0 -22
  121. 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 SQLCompletionStore();
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 SQLCompletionStore();
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 };