@sqlrooms/sql-editor 0.29.0-rc.6 → 0.29.0-rc.7
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/README.md +40 -0
- package/dist/SqlCodeMirrorEditor.d.ts +2 -0
- package/dist/SqlCodeMirrorEditor.d.ts.map +1 -1
- package/dist/SqlCodeMirrorEditor.js +3 -3
- package/dist/SqlCodeMirrorEditor.js.map +1 -1
- package/dist/SqlEditor.d.ts.map +1 -1
- package/dist/SqlEditor.js +1 -1
- package/dist/SqlEditor.js.map +1 -1
- package/dist/SqlEditorModal.d.ts.map +1 -1
- package/dist/SqlEditorModal.js +1 -1
- package/dist/SqlEditorModal.js.map +1 -1
- package/dist/SqlEditorSlice.d.ts +41 -0
- package/dist/SqlEditorSlice.d.ts.map +1 -1
- package/dist/SqlEditorSlice.js +142 -50
- package/dist/SqlEditorSlice.js.map +1 -1
- package/dist/SqlQuery.d.ts +34 -0
- package/dist/SqlQuery.d.ts.map +1 -0
- package/dist/SqlQuery.js +51 -0
- package/dist/SqlQuery.js.map +1 -0
- package/dist/SqlQueryBlock.d.ts +20 -0
- package/dist/SqlQueryBlock.d.ts.map +1 -0
- package/dist/SqlQueryBlock.js +148 -0
- package/dist/SqlQueryBlock.js.map +1 -0
- package/dist/codemirror/extensions/completion.d.ts +5 -2
- package/dist/codemirror/extensions/completion.d.ts.map +1 -1
- package/dist/codemirror/extensions/completion.js +82 -22
- package/dist/codemirror/extensions/completion.js.map +1 -1
- package/dist/codemirror/extensions/duck-db/duck-db.d.ts.map +1 -1
- package/dist/codemirror/extensions/duck-db/duck-db.js +3 -3
- package/dist/codemirror/extensions/duck-db/duck-db.js.map +1 -1
- package/dist/codemirror/extensions/duck-db/duckdb-sql.d.ts +2 -0
- package/dist/codemirror/extensions/duck-db/duckdb-sql.d.ts.map +1 -1
- package/dist/codemirror/extensions/duck-db/duckdb-sql.js +33 -2
- package/dist/codemirror/extensions/duck-db/duckdb-sql.js.map +1 -1
- package/dist/codemirror/extensions/sql-keymap.d.ts.map +1 -1
- package/dist/codemirror/extensions/sql-keymap.js +7 -8
- package/dist/codemirror/extensions/sql-keymap.js.map +1 -1
- package/dist/codemirror/utils/schema-converter.d.ts.map +1 -1
- package/dist/codemirror/utils/schema-converter.js +56 -1
- package/dist/codemirror/utils/schema-converter.js.map +1 -1
- package/dist/components/QueryEditorPanel.d.ts +6 -0
- package/dist/components/QueryEditorPanel.d.ts.map +1 -1
- package/dist/components/QueryEditorPanel.js +6 -0
- package/dist/components/QueryEditorPanel.js.map +1 -1
- package/dist/components/QueryEditorPanelActions.d.ts +6 -0
- package/dist/components/QueryEditorPanelActions.d.ts.map +1 -1
- package/dist/components/QueryEditorPanelActions.js +17 -5
- package/dist/components/QueryEditorPanelActions.js.map +1 -1
- package/dist/components/QueryEditorPanelEditor.d.ts +8 -0
- package/dist/components/QueryEditorPanelEditor.d.ts.map +1 -1
- package/dist/components/QueryEditorPanelEditor.js +29 -9
- package/dist/components/QueryEditorPanelEditor.js.map +1 -1
- package/dist/components/QueryResultLimitSelect.d.ts.map +1 -1
- package/dist/components/QueryResultLimitSelect.js +3 -2
- package/dist/components/QueryResultLimitSelect.js.map +1 -1
- package/dist/components/QueryResultPanel.d.ts +8 -0
- package/dist/components/QueryResultPanel.d.ts.map +1 -1
- package/dist/components/QueryResultPanel.js +28 -13
- package/dist/components/QueryResultPanel.js.map +1 -1
- package/dist/components/SqlEditorHeader.d.ts +2 -0
- package/dist/components/SqlEditorHeader.d.ts.map +1 -1
- package/dist/components/SqlEditorHeader.js +3 -2
- package/dist/components/SqlEditorHeader.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +13 -12
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ This package provides:
|
|
|
4
4
|
|
|
5
5
|
- `createSqlEditorSlice()` for query tabs, execution, and results state
|
|
6
6
|
- `SqlEditor` and `SqlEditorModal` UI
|
|
7
|
+
- `SqlQuery` compound components and `SqlQueryBlock` for reusable single-query
|
|
8
|
+
surfaces
|
|
7
9
|
- `SqlMonacoEditor` standalone SQL editor
|
|
8
10
|
- helpers/components for query results, table structure, and SQL data sources
|
|
9
11
|
|
|
@@ -95,6 +97,44 @@ function RunQueryButton() {
|
|
|
95
97
|
}
|
|
96
98
|
```
|
|
97
99
|
|
|
100
|
+
For reusable single-query surfaces, use id-addressable query actions:
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
const ensureQuery = useRoomStore((state) => state.sqlEditor.ensureQuery);
|
|
104
|
+
const runQueryById = useRoomStore((state) => state.sqlEditor.runQueryById);
|
|
105
|
+
|
|
106
|
+
ensureQuery('query-1', {name: 'Top Airports', query: 'SELECT * FROM airports'});
|
|
107
|
+
await runQueryById('query-1');
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Single Query UI
|
|
111
|
+
|
|
112
|
+
`SqlQuery` is a compound component for rearranging and styling a single query
|
|
113
|
+
experience without the full tabbed workbench:
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
import {SqlQuery} from '@sqlrooms/sql-editor';
|
|
117
|
+
|
|
118
|
+
export function QueryBlock() {
|
|
119
|
+
return (
|
|
120
|
+
<SqlQuery.Root queryId="query-1" name="Top Airports">
|
|
121
|
+
<SqlQuery.Header title="Top Airports">
|
|
122
|
+
<SqlQuery.Actions />
|
|
123
|
+
</SqlQuery.Header>
|
|
124
|
+
<SqlQuery.Editor />
|
|
125
|
+
<SqlQuery.Results />
|
|
126
|
+
</SqlQuery.Root>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`SqlQuery.Results` accepts the same props as `QueryResultPanel`, including
|
|
132
|
+
`footerDetails` for small metadata rendered at the end of the result footer and
|
|
133
|
+
`dataTableClassName` for styling the inner paginated table.
|
|
134
|
+
|
|
135
|
+
Use `createSqlQueryBlockDefinition()` when a SQL query should be both embeddable
|
|
136
|
+
as a stateful block and openable as an artifact shell.
|
|
137
|
+
|
|
98
138
|
## Standalone editor (without SQLRooms store)
|
|
99
139
|
|
|
100
140
|
`SqlMonacoEditor` can be used independently:
|
|
@@ -12,6 +12,8 @@ export interface SqlCodeMirrorEditorProps extends Omit<CodeMirrorEditorProps, 'e
|
|
|
12
12
|
connector?: DuckDbConnector;
|
|
13
13
|
/** Table schemas for autocompletion and hover tooltips */
|
|
14
14
|
tableSchemas?: DataTable[];
|
|
15
|
+
/** Hide all editor gutters. Useful for compact embedded editors. */
|
|
16
|
+
hideGutter?: boolean;
|
|
15
17
|
/** Callback to get the latest table schemas */
|
|
16
18
|
getLatestSchemas?: () => {
|
|
17
19
|
tableSchemas: DataTable[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlCodeMirrorEditor.d.ts","sourceRoot":"","sources":["../src/SqlCodeMirrorEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAG1D,OAAO,KAAK,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAmB,qBAAqB,EAAC,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,8CAA8C,CAAC;AAItD,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,qBAAqB,EACrB,YAAY,CACb;IACC,0DAA0D;IAC1D,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3B,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM;QAAC,YAAY,EAAE,SAAS,EAAE,CAAA;KAAC,CAAC;IACrD,0EAA0E;IAC1E,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AASD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,
|
|
1
|
+
{"version":3,"file":"SqlCodeMirrorEditor.d.ts","sourceRoot":"","sources":["../src/SqlCodeMirrorEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAG1D,OAAO,KAAK,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAmB,qBAAqB,EAAC,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,8CAA8C,CAAC;AAItD,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,qBAAqB,EACrB,YAAY,CACb;IACC,0DAA0D;IAC1D,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM;QAAC,YAAY,EAAE,SAAS,EAAE,CAAA;KAAC,CAAC;IACrD,0EAA0E;IAC1E,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AASD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA+DlE,CAAC"}
|
|
@@ -16,7 +16,7 @@ const EDITOR_OPTIONS = {
|
|
|
16
16
|
* Lightweight alternative to SqlMonacoEditor with syntax highlighting,
|
|
17
17
|
* linting, schema-aware completions, and hover tooltips. Cmd+Enter to run query.
|
|
18
18
|
*/
|
|
19
|
-
export const SqlCodeMirrorEditor = ({ dialect = SqlDialects.DuckDb, connector, tableSchemas = [], getLatestSchemas, onRunQuery, onMount, options, ...restProps }) => {
|
|
19
|
+
export const SqlCodeMirrorEditor = ({ dialect = SqlDialects.DuckDb, connector, tableSchemas = [], hideGutter, getLatestSchemas, onRunQuery, onMount, options, ...restProps }) => {
|
|
20
20
|
const viewRef = useRef(null);
|
|
21
21
|
// Get current schemas (use callback if provided)
|
|
22
22
|
const currentSchemas = useMemo(() => {
|
|
@@ -34,9 +34,9 @@ export const SqlCodeMirrorEditor = ({ dialect = SqlDialects.DuckDb, connector, t
|
|
|
34
34
|
connector,
|
|
35
35
|
}),
|
|
36
36
|
createSqlKeymap(onRunQuery),
|
|
37
|
-
createSqlTheme(),
|
|
37
|
+
createSqlTheme({ hideGutter }),
|
|
38
38
|
];
|
|
39
|
-
}, [dialect, currentSchemas, onRunQuery, connector]);
|
|
39
|
+
}, [dialect, currentSchemas, onRunQuery, connector, hideGutter]);
|
|
40
40
|
// Handle editor mount
|
|
41
41
|
const handleEditorMount = useCallback((view) => {
|
|
42
42
|
viewRef.current = view;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlCodeMirrorEditor.js","sourceRoot":"","sources":["../src/SqlCodeMirrorEditor.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAC,WAAW,EAAE,OAAO,EAAE,MAAM,EAAC,MAAM,OAAO,CAAC;AAI1D,OAAO,EAAC,gBAAgB,EAAwB,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EACL,kBAAkB,EAClB,WAAW,GAEZ,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAC,eAAe,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAC,cAAc,EAAC,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"SqlCodeMirrorEditor.js","sourceRoot":"","sources":["../src/SqlCodeMirrorEditor.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAC,WAAW,EAAE,OAAO,EAAE,MAAM,EAAC,MAAM,OAAO,CAAC;AAI1D,OAAO,EAAC,gBAAgB,EAAwB,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EACL,kBAAkB,EAClB,WAAW,GAEZ,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAC,eAAe,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAC,cAAc,EAAC,MAAM,+BAA+B,CAAC;AAuB7D,MAAM,cAAc,GAAqC;IACvD,WAAW,EAAE,IAAI;IACjB,YAAY,EAAE,IAAI;IAClB,mBAAmB,EAAE,IAAI;IACzB,cAAc,EAAE,IAAI;CACrB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAuC,CAAC,EACtE,OAAO,GAAG,WAAW,CAAC,MAAM,EAC5B,SAAS,EACT,YAAY,GAAG,EAAE,EACjB,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,OAAO,EACP,GAAG,SAAS,EACb,EAAE,EAAE;IACH,MAAM,OAAO,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAEhD,iDAAiD;IACjD,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,EAAE;QAClC,IAAI,gBAAgB,EAAE,CAAC;YACrB,OAAO,gBAAgB,EAAE,CAAC,YAAY,CAAC;QACzC,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC,EAAE,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC,CAAC;IAErC,mBAAmB;IACnB,MAAM,UAAU,GAAG,OAAO,CAAc,GAAG,EAAE;QAC3C,OAAO;YACL,GAAG,kBAAkB,CAAC;gBACpB,OAAO;gBACP,cAAc;gBACd,SAAS;aACV,CAAC;YACF,eAAe,CAAC,UAAU,CAAC;YAC3B,cAAc,CAAC,EAAC,UAAU,EAAC,CAAC;SAC7B,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IAEjE,sBAAsB;IACtB,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,IAAgB,EAAE,EAAE;QACnB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QAEvB,gCAAgC;QAChC,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;IACH,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAqC,EAAE,CAAC,CAAC;QACvC,GAAG,cAAc;QACjB,GAAG,OAAO;KACX,CAAC,EACF,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,CACL,KAAC,gBAAgB,IACf,OAAO,EAAE,iBAAiB,EAC1B,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,eAAe,KACpB,SAAS,GACb,CACH,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import React, {useCallback, useMemo, useRef} from 'react';\nimport type {EditorView} from '@codemirror/view';\nimport type {Extension} from '@codemirror/state';\nimport type {DataTable, DuckDbConnector} from '@sqlrooms/duckdb';\nimport {CodeMirrorEditor, CodeMirrorEditorProps} from '@sqlrooms/codemirror';\nimport {\n createSqlExtension,\n SqlDialects,\n type SqlDialect,\n} from './codemirror/extensions/create-sql-extension';\nimport {createSqlKeymap} from './codemirror/extensions/sql-keymap';\nimport {createSqlTheme} from './codemirror/themes/sql-theme';\n\nexport interface SqlCodeMirrorEditorProps extends Omit<\n CodeMirrorEditorProps,\n 'extensions'\n> {\n /** SQL dialect for syntax highlighting and completions */\n dialect?: SqlDialect;\n /**\n * Connector for dynamic function suggestions\n * TODO: change to generic connector interface to support multiple dialects\n */\n connector?: DuckDbConnector;\n /** Table schemas for autocompletion and hover tooltips */\n tableSchemas?: DataTable[];\n /** Hide all editor gutters. Useful for compact embedded editors. */\n hideGutter?: boolean;\n /** Callback to get the latest table schemas */\n getLatestSchemas?: () => {tableSchemas: DataTable[]};\n /** Callback when Cmd+Enter is pressed (selected text or full document) */\n onRunQuery?: (query: string) => void;\n}\n\nconst EDITOR_OPTIONS: CodeMirrorEditorProps['options'] = {\n lineNumbers: true,\n lineWrapping: true,\n highlightActiveLine: true,\n autocompletion: true,\n};\n\n/**\n * CodeMirror editor for SQL with dialect-specific support\n *\n * Lightweight alternative to SqlMonacoEditor with syntax highlighting,\n * linting, schema-aware completions, and hover tooltips. Cmd+Enter to run query.\n */\nexport const SqlCodeMirrorEditor: React.FC<SqlCodeMirrorEditorProps> = ({\n dialect = SqlDialects.DuckDb,\n connector,\n tableSchemas = [],\n hideGutter,\n getLatestSchemas,\n onRunQuery,\n onMount,\n options,\n ...restProps\n}) => {\n const viewRef = useRef<EditorView | null>(null);\n\n // Get current schemas (use callback if provided)\n const currentSchemas = useMemo(() => {\n if (getLatestSchemas) {\n return getLatestSchemas().tableSchemas;\n }\n return tableSchemas;\n }, [getLatestSchemas, tableSchemas]);\n\n // Build extensions\n const extensions = useMemo<Extension[]>(() => {\n return [\n ...createSqlExtension({\n dialect,\n currentSchemas,\n connector,\n }),\n createSqlKeymap(onRunQuery),\n createSqlTheme({hideGutter}),\n ];\n }, [dialect, currentSchemas, onRunQuery, connector, hideGutter]);\n\n // Handle editor mount\n const handleEditorMount = useCallback(\n (view: EditorView) => {\n viewRef.current = view;\n\n // Call user onMount if provided\n if (onMount) {\n onMount(view);\n }\n },\n [onMount],\n );\n\n const combinedOptions = useMemo(\n (): CodeMirrorEditorProps['options'] => ({\n ...EDITOR_OPTIONS,\n ...options,\n }),\n [options],\n );\n\n return (\n <CodeMirrorEditor\n onMount={handleEditorMount}\n extensions={extensions}\n options={combinedOptions}\n {...restProps}\n />\n );\n};\n"]}
|
package/dist/SqlEditor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlEditor.d.ts","sourceRoot":"","sources":["../src/SqlEditor.tsx"],"names":[],"mappings":"AAOA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAE/D,OAAO,EAEL,wBAAwB,EACzB,MAAM,kCAAkC,CAAC;AAG1C,MAAM,MAAM,cAAc,GAAG;IAC3B;;0EAEsE;IACtE,MAAM,CAAC,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAC5C,kDAAkD;IAClD,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACrC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,IAAI,CACrB,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,EAC7C,YAAY,GAAG,kBAAkB,CAClC,CAAC;IACF,0DAA0D;IAC1D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,QAAA,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"SqlEditor.d.ts","sourceRoot":"","sources":["../src/SqlEditor.tsx"],"names":[],"mappings":"AAOA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAE/D,OAAO,EAEL,wBAAwB,EACzB,MAAM,kCAAkC,CAAC;AAG1C,MAAM,MAAM,cAAc,GAAG;IAC3B;;0EAEsE;IACtE,MAAM,CAAC,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAC5C,kDAAkD;IAClD,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACrC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,IAAI,CACrB,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,EAC7C,YAAY,GAAG,kBAAkB,CAClC,CAAC;IACF,0DAA0D;IAC1D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,QAAA,MAAM,SAAS,4CAkFb,CAAC;AAGH,eAAe,SAAS,CAAC"}
|
package/dist/SqlEditor.js
CHANGED
|
@@ -27,7 +27,7 @@ const SqlEditor = React.memo((props) => {
|
|
|
27
27
|
const handleCreateTable = useCallback(() => {
|
|
28
28
|
setCreateTableModalOpen(true);
|
|
29
29
|
}, []);
|
|
30
|
-
return (_jsxs("div", { className: "relative flex h-full w-full flex-col overflow-hidden", children: [_jsx(SqlEditorHeader, { title: "SQL Editor", showDocs: showDocs, documentationPanel: documentationPanel, onToggleDocs: handleToggleDocs }), _jsx("div", { className: "bg-muted h-full grow", children: _jsxs(ResizablePanelGroup, { orientation: "horizontal", className: "h-full", children: [_jsx(ResizablePanel, { defaultSize: showDocs ? '70' : '100', children: _jsxs(ResizablePanelGroup, { orientation: "vertical", className: "h-full", children: [_jsx(ResizablePanel, { defaultSize: "50", className: "flex flex-row", children: _jsxs(ResizablePanelGroup, { orientation: "horizontal", children: [_jsx(ResizablePanel, { defaultSize: "20", children: _jsx(TableStructurePanel, { schema: schema }) }), _jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: "80", children: _jsx(QueryEditorPanel, {}) })] }) }), _jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: "50", children: _jsx(QueryResultPanel, { onRowClick: queryResultProps?.onRowClick, onRowDoubleClick: queryResultProps?.onRowDoubleClick, renderActions: () => (_jsx("div", { className: "flex gap-2", children: _jsxs(Button, { size: "xs", onClick: handleCreateTable, children: [_jsx(PlusIcon, { className: "h-4 w-4" }), "New table"] }) })) }) })] }) }), showDocs && (_jsxs(_Fragment, { children: [_jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: "30", children: documentationPanel })] }))] }) }), _jsx(CreateTableModal, { query: lastQuery, isOpen: createTableModalOpen, onClose: () => setCreateTableModalOpen(false), allowMultipleStatements: true, showSchemaSelection: true })] }));
|
|
30
|
+
return (_jsxs("div", { className: "relative flex h-full w-full flex-col overflow-hidden", children: [_jsx(SqlEditorHeader, { title: "SQL Editor", showDocs: showDocs, documentationPanel: documentationPanel, onToggleDocs: handleToggleDocs, onClose: props.onClose }), _jsx("div", { className: "bg-muted h-full grow", children: _jsxs(ResizablePanelGroup, { orientation: "horizontal", className: "h-full", children: [_jsx(ResizablePanel, { defaultSize: showDocs ? '70' : '100', children: _jsxs(ResizablePanelGroup, { orientation: "vertical", className: "h-full", children: [_jsx(ResizablePanel, { defaultSize: "50", className: "flex flex-row", children: _jsxs(ResizablePanelGroup, { orientation: "horizontal", children: [_jsx(ResizablePanel, { defaultSize: "20", children: _jsx(TableStructurePanel, { schema: schema }) }), _jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: "80", children: _jsx(QueryEditorPanel, {}) })] }) }), _jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: "50", children: _jsx(QueryResultPanel, { onRowClick: queryResultProps?.onRowClick, onRowDoubleClick: queryResultProps?.onRowDoubleClick, renderActions: () => (_jsx("div", { className: "flex gap-2", children: _jsxs(Button, { size: "xs", onClick: handleCreateTable, children: [_jsx(PlusIcon, { className: "h-4 w-4" }), "New table"] }) })) }) })] }) }), showDocs && (_jsxs(_Fragment, { children: [_jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: "30", children: documentationPanel })] }))] }) }), _jsx(CreateTableModal, { query: lastQuery, isOpen: createTableModalOpen, onClose: () => setCreateTableModalOpen(false), allowMultipleStatements: true, showSchemaSelection: true })] }));
|
|
31
31
|
});
|
|
32
32
|
SqlEditor.displayName = 'SqlEditor';
|
|
33
33
|
export default SqlEditor;
|
package/dist/SqlEditor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlEditor.js","sourceRoot":"","sources":["../src/SqlEditor.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,MAAM,EACN,eAAe,EACf,cAAc,EACd,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,EAAE,EAAC,WAAW,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAC;AACnD,OAAO,gBAAgB,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EACL,mBAAmB,GAEpB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AAuBvD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAiB,CAAC,KAAK,EAAE,EAAE;IACrD,MAAM,EAAC,MAAM,GAAG,GAAG,EAAE,kBAAkB,EAAE,gBAAgB,EAAC,GAAG,KAAK,CAAC;IAEnE,MAAM,SAAS,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5C,MAAM,UAAU,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC;QACtD,MAAM,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,EAAE,EAAE,MAAM,KAAK,SAAS,IAAI,EAAE,EAAE,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC,KAAK,CAAC;QACvE,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IACH,WAAW;IACX,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExE,WAAW;IACX,MAAM,gBAAgB,GAAG,WAAW,CAAC,CAAC,IAAa,EAAE,EAAE;QACrD,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;QACzC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,eAAK,SAAS,EAAC,sDAAsD,aACnE,KAAC,eAAe,IACd,KAAK,EAAC,YAAY,EAClB,QAAQ,EAAE,QAAQ,EAClB,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"SqlEditor.js","sourceRoot":"","sources":["../src/SqlEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Button,\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from '@sqlrooms/ui';\nimport {PlusIcon} from 'lucide-react';\nimport React, {useCallback, useState} from 'react';\nimport CreateTableModal from './components/CreateTableModal';\nimport {QueryEditorPanel} from './components/QueryEditorPanel';\nimport {QueryResultPanel} from './components/QueryResultPanel';\nimport {SqlEditorHeader} from './components/SqlEditorHeader';\nimport {\n TableStructurePanel,\n TableStructurePanelProps,\n} from './components/TableStructurePanel';\nimport {useStoreWithSqlEditor} from './SqlEditorSlice';\n\nexport type SqlEditorProps = {\n /** The database schema to use. Defaults to '*'.\n * If '*' is provided, all tables will be shown.\n * If a function is provided, it will be used to filter the tables. */\n schema?: TableStructurePanelProps['schema'];\n /** Whether the SQL editor is currently visible */\n isOpen: boolean;\n /** Optional component to render SQL documentation in the side panel */\n documentationPanel?: React.ReactNode;\n /**\n * Props forwarded to `QueryResultPanel` to configure result behavior.\n * This provides a single entry point for table interactions.\n */\n queryResultProps?: Pick<\n React.ComponentProps<typeof QueryResultPanel>,\n 'onRowClick' | 'onRowDoubleClick'\n >;\n /** Callback fired when the SQL editor should be closed */\n onClose: () => void;\n};\n\nconst SqlEditor = React.memo<SqlEditorProps>((props) => {\n const {schema = '*', documentationPanel, queryResultProps} = props;\n\n const lastQuery = useStoreWithSqlEditor((s) => {\n const selectedId = s.sqlEditor.config.selectedQueryId;\n const qr = s.sqlEditor.queryResultsById[selectedId];\n if (qr?.status === 'success' && qr?.type === 'select') return qr.query;\n return s.sqlEditor.getCurrentQuery();\n });\n // UI state\n const [showDocs, setShowDocs] = useState(false);\n const [createTableModalOpen, setCreateTableModalOpen] = useState(false);\n\n // Handlers\n const handleToggleDocs = useCallback((show: boolean) => {\n setShowDocs(show);\n }, []);\n\n const handleCreateTable = useCallback(() => {\n setCreateTableModalOpen(true);\n }, []);\n\n return (\n <div className=\"relative flex h-full w-full flex-col overflow-hidden\">\n <SqlEditorHeader\n title=\"SQL Editor\"\n showDocs={showDocs}\n documentationPanel={documentationPanel}\n onToggleDocs={handleToggleDocs}\n onClose={props.onClose}\n />\n <div className=\"bg-muted h-full grow\">\n <ResizablePanelGroup orientation=\"horizontal\" className=\"h-full\">\n <ResizablePanel defaultSize={showDocs ? '70' : '100'}>\n <ResizablePanelGroup orientation=\"vertical\" className=\"h-full\">\n <ResizablePanel defaultSize=\"50\" className=\"flex flex-row\">\n <ResizablePanelGroup orientation=\"horizontal\">\n <ResizablePanel defaultSize=\"20\">\n <TableStructurePanel schema={schema} />\n </ResizablePanel>\n <ResizableHandle withHandle />\n <ResizablePanel defaultSize=\"80\">\n <QueryEditorPanel />\n </ResizablePanel>\n </ResizablePanelGroup>\n </ResizablePanel>\n <ResizableHandle withHandle />\n <ResizablePanel defaultSize=\"50\">\n <QueryResultPanel\n onRowClick={queryResultProps?.onRowClick}\n onRowDoubleClick={queryResultProps?.onRowDoubleClick}\n renderActions={() => (\n <div className=\"flex gap-2\">\n <Button size=\"xs\" onClick={handleCreateTable}>\n <PlusIcon className=\"h-4 w-4\" />\n New table\n </Button>\n </div>\n )}\n />\n </ResizablePanel>\n </ResizablePanelGroup>\n </ResizablePanel>\n {showDocs && (\n <>\n <ResizableHandle withHandle />\n <ResizablePanel defaultSize=\"30\">\n {documentationPanel}\n </ResizablePanel>\n </>\n )}\n </ResizablePanelGroup>\n </div>\n <CreateTableModal\n query={lastQuery}\n isOpen={createTableModalOpen}\n onClose={() => setCreateTableModalOpen(false)}\n allowMultipleStatements={true}\n showSchemaSelection={true}\n />\n </div>\n );\n});\nSqlEditor.displayName = 'SqlEditor';\n\nexport default SqlEditor;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlEditorModal.d.ts","sourceRoot":"","sources":["../src/SqlEditorModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAkB,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,
|
|
1
|
+
{"version":3,"file":"SqlEditorModal.d.ts","sourceRoot":"","sources":["../src/SqlEditorModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAkB,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA8B5C,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
package/dist/SqlEditorModal.js
CHANGED
|
@@ -39,7 +39,7 @@ const SqlEditorModal = (props) => {
|
|
|
39
39
|
if (!open)
|
|
40
40
|
onClose();
|
|
41
41
|
}, [onClose]);
|
|
42
|
-
return (_jsxs(Dialog, { open: isOpen, onOpenChange: handleOpenChange, children: [_jsx(DialogOverlay, { className: "bg-background/80" }), _jsxs(DialogContent, { className: "h-screen max-h-screen w-screen max-w-[100vw] p-3", children: [_jsxs(DialogHeader, { className: "sr-only", children: [_jsx(DialogTitle, { children: "SQL Editor" }), _jsx(DialogDescription, { children: "SQL editor for querying and managing database tables" })] }), _jsx(Suspense, { fallback: _jsx(SpinnerPane, { h: "100%" }), children: _jsx(SqlEditor, { ...props }) })] })] }));
|
|
42
|
+
return (_jsxs(Dialog, { open: isOpen, onOpenChange: handleOpenChange, children: [_jsx(DialogOverlay, { className: "bg-background/80" }), _jsxs(DialogContent, { className: "h-screen max-h-screen w-screen max-w-[100vw] p-3", showCloseButton: false, children: [_jsxs(DialogHeader, { className: "sr-only", children: [_jsx(DialogTitle, { children: "SQL Editor" }), _jsx(DialogDescription, { children: "SQL editor for querying and managing database tables" })] }), _jsx(Suspense, { fallback: _jsx(SpinnerPane, { h: "100%" }), children: _jsx(SqlEditor, { ...props }) })] })] }));
|
|
43
43
|
};
|
|
44
44
|
export default SqlEditorModal;
|
|
45
45
|
//# sourceMappingURL=SqlEditorModal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlEditorModal.js","sourceRoot":"","sources":["../src/SqlEditorModal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACL,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAc,EAAC,QAAQ,EAAE,WAAW,EAAC,MAAM,OAAO,CAAC;AACnD,OAAO,SAA2B,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,cAAc,GAA6B,CAAC,KAAK,EAAE,EAAE;IACzD,MAAM,EAAC,MAAM,EAAE,OAAO,EAAC,GAAG,KAAK,CAAC;IAEhC,4CAA4C;IAC5C,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,IAAa,EAAE,EAAE;QAChB,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;IACvB,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,CACL,MAAC,MAAM,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,gBAAgB,aAClD,KAAC,aAAa,IAAC,SAAS,EAAC,kBAAkB,GAAG,EAC9C,MAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"SqlEditorModal.js","sourceRoot":"","sources":["../src/SqlEditorModal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACL,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAc,EAAC,QAAQ,EAAE,WAAW,EAAC,MAAM,OAAO,CAAC;AACnD,OAAO,SAA2B,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,cAAc,GAA6B,CAAC,KAAK,EAAE,EAAE;IACzD,MAAM,EAAC,MAAM,EAAE,OAAO,EAAC,GAAG,KAAK,CAAC;IAEhC,4CAA4C;IAC5C,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,IAAa,EAAE,EAAE;QAChB,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;IACvB,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,CACL,MAAC,MAAM,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,gBAAgB,aAClD,KAAC,aAAa,IAAC,SAAS,EAAC,kBAAkB,GAAG,EAC9C,MAAC,aAAa,IACZ,SAAS,EAAC,kDAAkD,EAC5D,eAAe,EAAE,KAAK,aAEtB,MAAC,YAAY,IAAC,SAAS,EAAC,SAAS,aAC/B,KAAC,WAAW,6BAAyB,EACrC,KAAC,iBAAiB,uEAEE,IACP,EACf,KAAC,QAAQ,IAAC,QAAQ,EAAE,KAAC,WAAW,IAAC,CAAC,EAAC,MAAM,GAAG,YAC1C,KAAC,SAAS,OAAK,KAAK,GAAI,GACf,IACG,IACT,CACV,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["'use client';\n\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogOverlay,\n DialogTitle,\n SpinnerPane,\n} from '@sqlrooms/ui';\nimport React, {Suspense, useCallback} from 'react';\nimport SqlEditor, {SqlEditorProps} from './SqlEditor';\n\n/**\n * A modal wrapper for the SQL Editor component that provides a full-screen dialog interface.\n *\n * This component wraps the main SqlEditor component in a modal dialog, making it suitable for\n * overlay/popup usage scenarios. It inherits all props from SqlEditorProps and handles the\n * modal-specific behavior.\n *\n * @example\n * ```tsx\n * <SqlEditorModal\n * isOpen={true}\n * onClose={() => setIsOpen(false)}\n * sqlEditorConfig={config}\n * onChange={handleConfigChange}\n * />\n * ```\n *\n * @see {@link SqlEditor} for detailed documentation of all available props\n *\n * @see {@link SqlEditorProps}\n * The component accepts all props from SqlEditorProps:\n * - `isOpen` - Whether the SQL editor modal is currently visible\n * - `onClose` - Callback fired when the modal should be closed\n * - `sqlEditorConfig` - Configuration object containing queries and selected query state\n * - `onChange` - Callback fired when the SQL editor configuration changes\n * - `schema` - Optional database schema to use for queries (defaults to 'main')\n * - `documentationPanel` - Optional component to render SQL documentation in the side panel\n * - `onAddOrUpdateSqlQuery` - Callback fired when a new table should be created from query results\n */\nconst SqlEditorModal: React.FC<SqlEditorProps> = (props) => {\n const {isOpen, onClose} = props;\n\n // Memoize the handler to prevent re-renders\n const handleOpenChange = useCallback(\n (open: boolean) => {\n if (!open) onClose();\n },\n [onClose],\n );\n\n return (\n <Dialog open={isOpen} onOpenChange={handleOpenChange}>\n <DialogOverlay className=\"bg-background/80\" />\n <DialogContent\n className=\"h-screen max-h-screen w-screen max-w-[100vw] p-3\"\n showCloseButton={false}\n >\n <DialogHeader className=\"sr-only\">\n <DialogTitle>SQL Editor</DialogTitle>\n <DialogDescription>\n SQL editor for querying and managing database tables\n </DialogDescription>\n </DialogHeader>\n <Suspense fallback={<SpinnerPane h=\"100%\" />}>\n <SqlEditor {...props} />\n </Suspense>\n </DialogContent>\n </Dialog>\n );\n};\n\nexport default SqlEditorModal;\n"]}
|
package/dist/SqlEditorSlice.d.ts
CHANGED
|
@@ -1,26 +1,42 @@
|
|
|
1
1
|
import { RoomShellSliceState, StateCreator } from '@sqlrooms/room-shell';
|
|
2
2
|
import { SqlEditorSliceConfig } from '@sqlrooms/sql-editor-config';
|
|
3
3
|
import * as arrow from 'apache-arrow';
|
|
4
|
+
export type SqlEditorQuery = SqlEditorSliceConfig['queries'][number];
|
|
5
|
+
export type EnsureSqlQueryOptions = {
|
|
6
|
+
name?: string;
|
|
7
|
+
query?: string;
|
|
8
|
+
open?: boolean;
|
|
9
|
+
select?: boolean;
|
|
10
|
+
};
|
|
4
11
|
export type QueryResult = {
|
|
5
12
|
status: 'loading';
|
|
6
13
|
isBeingAborted?: boolean;
|
|
7
14
|
controller: AbortController;
|
|
15
|
+
startedAt?: number;
|
|
8
16
|
} | {
|
|
9
17
|
status: 'aborted';
|
|
18
|
+
durationMs?: number;
|
|
19
|
+
completedAt?: number;
|
|
10
20
|
} | {
|
|
11
21
|
status: 'error';
|
|
12
22
|
error: string;
|
|
23
|
+
durationMs?: number;
|
|
24
|
+
completedAt?: number;
|
|
13
25
|
} | {
|
|
14
26
|
status: 'success';
|
|
15
27
|
type: 'pragma' | 'explain' | 'select';
|
|
16
28
|
result: arrow.Table | undefined;
|
|
17
29
|
query: string;
|
|
18
30
|
lastQueryStatement: string;
|
|
31
|
+
durationMs?: number;
|
|
32
|
+
completedAt?: number;
|
|
19
33
|
} | {
|
|
20
34
|
status: 'success';
|
|
21
35
|
type: 'exec';
|
|
22
36
|
query: string;
|
|
23
37
|
lastQueryStatement: string;
|
|
38
|
+
durationMs?: number;
|
|
39
|
+
completedAt?: number;
|
|
24
40
|
};
|
|
25
41
|
export declare function isQueryWithResult(queryResult: QueryResult | undefined): queryResult is QueryResult & {
|
|
26
42
|
status: 'success';
|
|
@@ -48,6 +64,31 @@ export type SqlEditorSliceState = {
|
|
|
48
64
|
* Set the config for the sql editor slice.
|
|
49
65
|
*/
|
|
50
66
|
setConfig(config: SqlEditorSliceConfig): void;
|
|
67
|
+
/**
|
|
68
|
+
* Ensure an id-addressable query exists without requiring it to be an open
|
|
69
|
+
* workbench tab.
|
|
70
|
+
*/
|
|
71
|
+
ensureQuery(queryId: string, options?: EnsureSqlQueryOptions): SqlEditorQuery;
|
|
72
|
+
/**
|
|
73
|
+
* Remove an id-addressable query and its runtime result.
|
|
74
|
+
*/
|
|
75
|
+
removeQuery(queryId: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Rename an id-addressable query.
|
|
78
|
+
*/
|
|
79
|
+
renameQuery(queryId: string, name: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* Run a query by id, optionally overriding its stored SQL text first.
|
|
82
|
+
*/
|
|
83
|
+
runQueryById(queryId: string, query?: string): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Abort a running query by id.
|
|
86
|
+
*/
|
|
87
|
+
abortQueryById(queryId: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Clear the runtime result for a query id.
|
|
90
|
+
*/
|
|
91
|
+
clearQueryResult(queryId: string): void;
|
|
51
92
|
/**
|
|
52
93
|
* Run the currently selected query.
|
|
53
94
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlEditorSlice.d.ts","sourceRoot":"","sources":["../src/SqlEditorSlice.tsx"],"names":[],"mappings":"AAQA,OAAO,EAKL,mBAAmB,EACnB,YAAY,EAGb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,oBAAoB,EACrB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAQtC,MAAM,MAAM,WAAW,GACnB;
|
|
1
|
+
{"version":3,"file":"SqlEditorSlice.d.ts","sourceRoot":"","sources":["../src/SqlEditorSlice.tsx"],"names":[],"mappings":"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"}
|
package/dist/SqlEditorSlice.js
CHANGED
|
@@ -35,6 +35,74 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
35
35
|
draft.sqlEditor.config = config;
|
|
36
36
|
}));
|
|
37
37
|
},
|
|
38
|
+
ensureQuery: (queryId, options = {}) => {
|
|
39
|
+
const now = Date.now();
|
|
40
|
+
const existingQuery = get().sqlEditor.config.queries.find((query) => query.id === queryId);
|
|
41
|
+
const shouldOpen = Boolean(options.open || options.select);
|
|
42
|
+
const nextQuery = existingQuery
|
|
43
|
+
? {
|
|
44
|
+
...existingQuery,
|
|
45
|
+
...(options.name !== undefined ? { name: options.name } : {}),
|
|
46
|
+
...(options.query !== undefined ? { query: options.query } : {}),
|
|
47
|
+
...(options.select ? { lastOpenedAt: now } : {}),
|
|
48
|
+
}
|
|
49
|
+
: {
|
|
50
|
+
id: queryId,
|
|
51
|
+
name: options.name ?? 'SQL Query',
|
|
52
|
+
query: options.query ?? '',
|
|
53
|
+
...(options.select ? { lastOpenedAt: now } : {}),
|
|
54
|
+
};
|
|
55
|
+
set((state) => produce(state, (draft) => {
|
|
56
|
+
const config = draft.sqlEditor.config;
|
|
57
|
+
const index = config.queries.findIndex((query) => query.id === queryId);
|
|
58
|
+
if (index >= 0) {
|
|
59
|
+
config.queries[index] = nextQuery;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
config.queries.push(nextQuery);
|
|
63
|
+
}
|
|
64
|
+
if (shouldOpen && !config.openTabs.includes(queryId)) {
|
|
65
|
+
config.openTabs.push(queryId);
|
|
66
|
+
}
|
|
67
|
+
if (options.select) {
|
|
68
|
+
config.selectedQueryId = queryId;
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
71
|
+
return nextQuery;
|
|
72
|
+
},
|
|
73
|
+
removeQuery: (queryId) => {
|
|
74
|
+
const currentResult = get().sqlEditor.queryResultsById[queryId];
|
|
75
|
+
if (currentResult?.status === 'loading') {
|
|
76
|
+
currentResult.controller.abort();
|
|
77
|
+
}
|
|
78
|
+
set((state) => produce(state, (draft) => {
|
|
79
|
+
const config = draft.sqlEditor.config;
|
|
80
|
+
const wasSelected = config.selectedQueryId === queryId;
|
|
81
|
+
config.queries = config.queries.filter((query) => query.id !== queryId);
|
|
82
|
+
config.openTabs = config.openTabs.filter((id) => id !== queryId);
|
|
83
|
+
delete draft.sqlEditor.queryResultsById[queryId];
|
|
84
|
+
if (wasSelected) {
|
|
85
|
+
const nextSelectedId = config.openTabs[0] ?? config.queries[0]?.id;
|
|
86
|
+
if (nextSelectedId) {
|
|
87
|
+
config.selectedQueryId = nextSelectedId;
|
|
88
|
+
if (!config.openTabs.includes(nextSelectedId)) {
|
|
89
|
+
config.openTabs.push(nextSelectedId);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
config.selectedQueryId = '';
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}));
|
|
97
|
+
},
|
|
98
|
+
renameQuery: (queryId, name) => {
|
|
99
|
+
set((state) => produce(state, (draft) => {
|
|
100
|
+
const query = draft.sqlEditor.config.queries.find((candidate) => candidate.id === queryId);
|
|
101
|
+
if (query) {
|
|
102
|
+
query.name = name || query.name;
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
105
|
+
},
|
|
38
106
|
exportResultsToCsv: (results, filename) => {
|
|
39
107
|
if (!results)
|
|
40
108
|
return;
|
|
@@ -60,34 +128,29 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
60
128
|
return newQuery;
|
|
61
129
|
},
|
|
62
130
|
deleteQueryTab: (queryId) => {
|
|
63
|
-
const sqlEditorConfig = get().sqlEditor.config;
|
|
64
|
-
const queries = sqlEditorConfig.queries;
|
|
65
|
-
const openTabs = sqlEditorConfig.openTabs;
|
|
66
|
-
if (queries.length <= 1) {
|
|
67
|
-
// Don't delete the last query
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const wasSelected = sqlEditorConfig.selectedQueryId === queryId;
|
|
71
|
-
const deletingOpenIndex = openTabs.indexOf(queryId);
|
|
72
|
-
const filteredQueries = queries.filter((q) => q.id !== queryId);
|
|
73
131
|
set((state) => produce(state, (draft) => {
|
|
74
|
-
draft.sqlEditor.config
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
132
|
+
const config = draft.sqlEditor.config;
|
|
133
|
+
if (config.queries.length <= 1) {
|
|
134
|
+
// Don't delete the last query
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const wasSelected = config.selectedQueryId === queryId;
|
|
138
|
+
const deletingOpenIndex = config.openTabs.indexOf(queryId);
|
|
139
|
+
config.queries = config.queries.filter((q) => q.id !== queryId);
|
|
140
|
+
config.openTabs = config.openTabs.filter((id) => id !== queryId);
|
|
141
|
+
delete draft.sqlEditor.queryResultsById[queryId];
|
|
78
142
|
// If we deleted the selected query, select another one
|
|
79
143
|
if (wasSelected) {
|
|
80
|
-
const newOpenTabs =
|
|
81
|
-
const remainingQueries =
|
|
144
|
+
const newOpenTabs = config.openTabs;
|
|
145
|
+
const remainingQueries = config.queries;
|
|
82
146
|
if (newOpenTabs.length > 0) {
|
|
83
147
|
// Select from remaining open tabs
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const newSelectedId = newOpenTabs[newIndex];
|
|
148
|
+
const baseIndex = deletingOpenIndex <= 0 ? 0 : deletingOpenIndex - 1;
|
|
149
|
+
const newIndex = Math.min(baseIndex, newOpenTabs.length - 1);
|
|
150
|
+
const newSelectedId = newOpenTabs[newIndex] ?? remainingQueries[0]?.id;
|
|
88
151
|
if (newSelectedId) {
|
|
89
|
-
|
|
90
|
-
const newSelectedQuery =
|
|
152
|
+
config.selectedQueryId = newSelectedId;
|
|
153
|
+
const newSelectedQuery = config.queries.find((q) => q.id === newSelectedId);
|
|
91
154
|
if (newSelectedQuery) {
|
|
92
155
|
newSelectedQuery.lastOpenedAt = Date.now();
|
|
93
156
|
}
|
|
@@ -97,8 +160,8 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
97
160
|
// No open tabs left, open a closed query
|
|
98
161
|
const queryToOpen = remainingQueries[0];
|
|
99
162
|
if (queryToOpen) {
|
|
100
|
-
|
|
101
|
-
|
|
163
|
+
config.openTabs.push(queryToOpen.id);
|
|
164
|
+
config.selectedQueryId = queryToOpen.id;
|
|
102
165
|
queryToOpen.lastOpenedAt = Date.now();
|
|
103
166
|
}
|
|
104
167
|
}
|
|
@@ -106,12 +169,7 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
106
169
|
}));
|
|
107
170
|
},
|
|
108
171
|
renameQueryTab: (queryId, newName) => {
|
|
109
|
-
|
|
110
|
-
const query = draft.sqlEditor.config.queries.find((q) => q.id === queryId);
|
|
111
|
-
if (query) {
|
|
112
|
-
query.name = newName || query.name;
|
|
113
|
-
}
|
|
114
|
-
}));
|
|
172
|
+
get().sqlEditor.renameQuery(queryId, newName);
|
|
115
173
|
},
|
|
116
174
|
closeQueryTab: (queryId) => {
|
|
117
175
|
set((state) => produce(state, (draft) => {
|
|
@@ -170,43 +228,59 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
170
228
|
draft.sqlEditor.queryResultsById = {};
|
|
171
229
|
}));
|
|
172
230
|
},
|
|
173
|
-
parseAndRunCurrentQuery: async () => get().sqlEditor.
|
|
231
|
+
parseAndRunCurrentQuery: async () => get().sqlEditor.runQueryById(get().sqlEditor.config.selectedQueryId),
|
|
174
232
|
abortCurrentQuery: () => {
|
|
175
|
-
|
|
176
|
-
|
|
233
|
+
get().sqlEditor.abortQueryById(get().sqlEditor.config.selectedQueryId);
|
|
234
|
+
},
|
|
235
|
+
setQueryResultLimit: (limit) => {
|
|
236
|
+
set((state) => produce(state, (draft) => {
|
|
237
|
+
draft.sqlEditor.queryResultLimit = limit;
|
|
238
|
+
}));
|
|
239
|
+
},
|
|
240
|
+
abortQueryById: (queryId) => {
|
|
241
|
+
const currentResult = get().sqlEditor.queryResultsById[queryId];
|
|
177
242
|
if (currentResult?.status === 'loading' && currentResult.controller) {
|
|
178
243
|
currentResult.controller.abort();
|
|
179
244
|
}
|
|
180
245
|
set((state) => produce(state, (draft) => {
|
|
181
|
-
const result = draft.sqlEditor.queryResultsById[
|
|
246
|
+
const result = draft.sqlEditor.queryResultsById[queryId];
|
|
182
247
|
if (result?.status === 'loading') {
|
|
183
248
|
result.isBeingAborted = true;
|
|
184
249
|
}
|
|
185
250
|
}));
|
|
186
251
|
},
|
|
187
|
-
|
|
252
|
+
clearQueryResult: (queryId) => {
|
|
253
|
+
const currentResult = get().sqlEditor.queryResultsById[queryId];
|
|
254
|
+
if (currentResult?.status === 'loading') {
|
|
255
|
+
currentResult.controller.abort();
|
|
256
|
+
}
|
|
188
257
|
set((state) => produce(state, (draft) => {
|
|
189
|
-
draft.sqlEditor.
|
|
258
|
+
delete draft.sqlEditor.queryResultsById[queryId];
|
|
190
259
|
}));
|
|
191
260
|
},
|
|
192
|
-
parseAndRunQuery: async (query) =>
|
|
193
|
-
|
|
194
|
-
const
|
|
261
|
+
parseAndRunQuery: async (query) => get().sqlEditor.runQueryById(get().sqlEditor.config.selectedQueryId, query),
|
|
262
|
+
runQueryById: async (queryId, queryOverride) => {
|
|
263
|
+
const storedQuery = get().sqlEditor.config.queries.find((query) => query.id === queryId);
|
|
264
|
+
const query = queryOverride ?? storedQuery?.query ?? '';
|
|
265
|
+
const existingResult = get().sqlEditor.queryResultsById[queryId];
|
|
195
266
|
if (existingResult?.status === 'loading') {
|
|
196
267
|
throw new Error('Query already running');
|
|
197
268
|
}
|
|
198
269
|
if (!query.trim()) {
|
|
199
270
|
return;
|
|
200
271
|
}
|
|
272
|
+
get().sqlEditor.ensureQuery(queryId, { query });
|
|
201
273
|
// Create abort controller for this query execution
|
|
202
274
|
const queryController = new AbortController();
|
|
275
|
+
const startedAt = Date.now();
|
|
203
276
|
// First update loading state and clear results
|
|
204
277
|
set((state) => produce(state, (draft) => {
|
|
205
278
|
draft.sqlEditor.selectedTable = undefined;
|
|
206
|
-
draft.sqlEditor.queryResultsById[
|
|
279
|
+
draft.sqlEditor.queryResultsById[queryId] = {
|
|
207
280
|
status: 'loading',
|
|
208
281
|
isBeingAborted: false,
|
|
209
282
|
controller: queryController,
|
|
283
|
+
startedAt,
|
|
210
284
|
};
|
|
211
285
|
}));
|
|
212
286
|
let queryResult;
|
|
@@ -244,6 +318,7 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
244
318
|
query,
|
|
245
319
|
lastQueryStatement,
|
|
246
320
|
result,
|
|
321
|
+
durationMs: Date.now() - startedAt,
|
|
247
322
|
};
|
|
248
323
|
}
|
|
249
324
|
else {
|
|
@@ -272,6 +347,7 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
272
347
|
query,
|
|
273
348
|
lastQueryStatement,
|
|
274
349
|
result,
|
|
350
|
+
durationMs: Date.now() - startedAt,
|
|
275
351
|
};
|
|
276
352
|
}
|
|
277
353
|
else if (/^(PRAGMA)/i.test(lastQueryStatement)) {
|
|
@@ -281,6 +357,7 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
281
357
|
query,
|
|
282
358
|
lastQueryStatement,
|
|
283
359
|
result,
|
|
360
|
+
durationMs: Date.now() - startedAt,
|
|
284
361
|
};
|
|
285
362
|
}
|
|
286
363
|
else {
|
|
@@ -289,6 +366,7 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
289
366
|
type: 'exec',
|
|
290
367
|
query,
|
|
291
368
|
lastQueryStatement,
|
|
369
|
+
durationMs: Date.now() - startedAt,
|
|
292
370
|
};
|
|
293
371
|
}
|
|
294
372
|
}
|
|
@@ -309,26 +387,40 @@ export function createSqlEditorSlice({ config = createDefaultSqlEditorConfig(),
|
|
|
309
387
|
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
310
388
|
if (errorMessage === 'Query aborted' ||
|
|
311
389
|
queryController.signal.aborted) {
|
|
312
|
-
queryResult = {
|
|
390
|
+
queryResult = {
|
|
391
|
+
status: 'aborted',
|
|
392
|
+
durationMs: Date.now() - startedAt,
|
|
393
|
+
};
|
|
313
394
|
}
|
|
314
395
|
else {
|
|
315
396
|
queryResult = {
|
|
316
397
|
status: 'error',
|
|
317
398
|
error: errorMessage,
|
|
399
|
+
durationMs: Date.now() - startedAt,
|
|
318
400
|
};
|
|
319
401
|
}
|
|
320
402
|
}
|
|
403
|
+
queryResult = { ...queryResult, completedAt: Date.now() };
|
|
321
404
|
// Update state without Immer since Arrow Tables don't play well with drafts.
|
|
322
|
-
set((state) =>
|
|
323
|
-
|
|
324
|
-
sqlEditor
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
405
|
+
set((state) => {
|
|
406
|
+
const currentResult = state.sqlEditor.queryResultsById[queryId];
|
|
407
|
+
const queryStillExists = state.sqlEditor.config.queries.some((candidate) => candidate.id === queryId);
|
|
408
|
+
if (!queryStillExists ||
|
|
409
|
+
currentResult?.status !== 'loading' ||
|
|
410
|
+
currentResult.controller !== queryController) {
|
|
411
|
+
return state;
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
...state,
|
|
415
|
+
sqlEditor: {
|
|
416
|
+
...state.sqlEditor,
|
|
417
|
+
queryResultsById: {
|
|
418
|
+
...state.sqlEditor.queryResultsById,
|
|
419
|
+
[queryId]: queryResult,
|
|
420
|
+
},
|
|
329
421
|
},
|
|
330
|
-
}
|
|
331
|
-
})
|
|
422
|
+
};
|
|
423
|
+
});
|
|
332
424
|
},
|
|
333
425
|
},
|
|
334
426
|
};
|