@adecore/database 0.0.1 → 0.16.0-beta.0
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/LICENSE +21 -0
- package/README.md +152 -1
- package/dist/DatabaseProvider.d.ts +13 -0
- package/dist/DatabaseProvider.js +17 -0
- package/dist/actions.d.ts +40 -0
- package/dist/actions.js +1 -0
- package/dist/client/client.d.ts +5 -0
- package/dist/client/client.js +245 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +2 -0
- package/dist/client/types.d.ts +97 -0
- package/dist/client/types.js +13 -0
- package/dist/client-context.d.ts +16 -0
- package/dist/client-context.js +17 -0
- package/dist/connections/ConnectionForm.d.ts +10 -0
- package/dist/connections/ConnectionForm.js +145 -0
- package/dist/connections/ConnectionManager.d.ts +12 -0
- package/dist/connections/ConnectionManager.js +93 -0
- package/dist/connections/EngineIcon.d.ts +9 -0
- package/dist/connections/EngineIcon.js +7 -0
- package/dist/connections/connection-config.d.ts +16 -0
- package/dist/connections/connection-config.js +107 -0
- package/dist/connections/docker.d.ts +9 -0
- package/dist/connections/docker.js +38 -0
- package/dist/connections/engine-icons.d.ts +3 -0
- package/dist/connections/engine-icons.js +3 -0
- package/dist/connections/use-docker-containers.d.ts +17 -0
- package/dist/connections/use-docker-containers.js +26 -0
- package/dist/console/DestructiveDialog.d.ts +9 -0
- package/dist/console/DestructiveDialog.js +9 -0
- package/dist/console/HistoryPanel.d.ts +10 -0
- package/dist/console/HistoryPanel.js +15 -0
- package/dist/console/QueryConsole.d.ts +14 -0
- package/dist/console/QueryConsole.js +261 -0
- package/dist/console/SchemaPicker.d.ts +11 -0
- package/dist/console/SchemaPicker.js +8 -0
- package/dist/console/SqlEditor.d.ts +12 -0
- package/dist/console/SqlEditor.js +61 -0
- package/dist/console/StatementResultView.d.ts +18 -0
- package/dist/console/StatementResultView.js +32 -0
- package/dist/console/TransactionControls.d.ts +13 -0
- package/dist/console/TransactionControls.js +12 -0
- package/dist/console/destructive.d.ts +7 -0
- package/dist/console/destructive.js +43 -0
- package/dist/console/editing.d.ts +12 -0
- package/dist/console/editing.js +60 -0
- package/dist/console/history.d.ts +13 -0
- package/dist/console/history.js +43 -0
- package/dist/console/labels.d.ts +1 -0
- package/dist/console/labels.js +6 -0
- package/dist/console/outcome.d.ts +6 -0
- package/dist/console/outcome.js +11 -0
- package/dist/console/schemas.d.ts +2 -0
- package/dist/console/schemas.js +5 -0
- package/dist/console/shortcuts.d.ts +2 -0
- package/dist/console/shortcuts.js +3 -0
- package/dist/console/useConsoleHistory.d.ts +7 -0
- package/dist/console/useConsoleHistory.js +22 -0
- package/dist/ddl/alter-mysql.d.ts +4 -0
- package/dist/ddl/alter-mysql.js +79 -0
- package/dist/ddl/alter-sqlite.d.ts +4 -0
- package/dist/ddl/alter-sqlite.js +80 -0
- package/dist/ddl/alter.d.ts +4 -0
- package/dist/ddl/alter.js +24 -0
- package/dist/ddl/column.d.ts +9 -0
- package/dist/ddl/column.js +62 -0
- package/dist/ddl/create.d.ts +12 -0
- package/dist/ddl/create.js +74 -0
- package/dist/ddl/dialect.d.ts +12 -0
- package/dist/ddl/dialect.js +34 -0
- package/dist/ddl/diff.d.ts +34 -0
- package/dist/ddl/diff.js +111 -0
- package/dist/ddl/draft.d.ts +46 -0
- package/dist/ddl/draft.js +70 -0
- package/dist/ddl/index.d.ts +10 -0
- package/dist/ddl/index.js +10 -0
- package/dist/ddl/parse.d.ts +17 -0
- package/dist/ddl/parse.js +131 -0
- package/dist/ddl/statements.d.ts +6 -0
- package/dist/ddl/statements.js +12 -0
- package/dist/ddl/types.d.ts +6 -0
- package/dist/ddl/types.js +52 -0
- package/dist/ddl/validate.d.ts +7 -0
- package/dist/ddl/validate.js +38 -0
- package/dist/designer/ColumnsEditor.d.ts +2 -0
- package/dist/designer/ColumnsEditor.js +24 -0
- package/dist/designer/DesignerView.d.ts +25 -0
- package/dist/designer/DesignerView.js +33 -0
- package/dist/designer/ForeignKeysEditor.d.ts +7 -0
- package/dist/designer/ForeignKeysEditor.js +24 -0
- package/dist/designer/IndexesEditor.d.ts +2 -0
- package/dist/designer/IndexesEditor.js +13 -0
- package/dist/designer/NamePicker.d.ts +11 -0
- package/dist/designer/NamePicker.js +13 -0
- package/dist/designer/OptionsEditor.d.ts +2 -0
- package/dist/designer/OptionsEditor.js +17 -0
- package/dist/designer/SqlPreview.d.ts +12 -0
- package/dist/designer/SqlPreview.js +17 -0
- package/dist/designer/TableDesigner.d.ts +10 -0
- package/dist/designer/TableDesigner.js +103 -0
- package/dist/designer/edit.d.ts +17 -0
- package/dist/designer/edit.js +115 -0
- package/dist/designer/editor-props.d.ts +10 -0
- package/dist/designer/editor-props.js +1 -0
- package/dist/designer/plan.d.ts +9 -0
- package/dist/designer/plan.js +13 -0
- package/dist/designer/recover.d.ts +2 -0
- package/dist/designer/recover.js +18 -0
- package/dist/designer/useReferenceColumns.d.ts +3 -0
- package/dist/designer/useReferenceColumns.js +36 -0
- package/dist/explorer/DatabaseExplorer.d.ts +13 -0
- package/dist/explorer/DatabaseExplorer.js +264 -0
- package/dist/explorer/RowMenu.d.ts +11 -0
- package/dist/explorer/RowMenu.js +89 -0
- package/dist/explorer/TableDialog.d.ts +15 -0
- package/dist/explorer/TableDialog.js +50 -0
- package/dist/explorer/expansion.d.ts +7 -0
- package/dist/explorer/expansion.js +31 -0
- package/dist/explorer/table-statements.d.ts +5 -0
- package/dist/explorer/table-statements.js +12 -0
- package/dist/explorer/tree.d.ts +125 -0
- package/dist/explorer/tree.js +295 -0
- package/dist/explorer/use-explorer-loads.d.ts +12 -0
- package/dist/explorer/use-explorer-loads.js +109 -0
- package/dist/explorer/use-stored-expansion.d.ts +9 -0
- package/dist/explorer/use-stored-expansion.js +47 -0
- package/dist/grid/CellEditor.d.ts +9 -0
- package/dist/grid/CellEditor.js +29 -0
- package/dist/grid/CopyAsMenu.d.ts +7 -0
- package/dist/grid/CopyAsMenu.js +10 -0
- package/dist/grid/DataGrid.d.ts +36 -0
- package/dist/grid/DataGrid.js +512 -0
- package/dist/grid/EnumPicker.d.ts +17 -0
- package/dist/grid/EnumPicker.js +53 -0
- package/dist/grid/GridHeaderCell.d.ts +36 -0
- package/dist/grid/GridHeaderCell.js +69 -0
- package/dist/grid/RecordView.d.ts +20 -0
- package/dist/grid/RecordView.js +126 -0
- package/dist/grid/ValueDock.d.ts +11 -0
- package/dist/grid/ValueDock.js +28 -0
- package/dist/grid/aggregates.d.ts +22 -0
- package/dist/grid/aggregates.js +62 -0
- package/dist/grid/cell-range.d.ts +14 -0
- package/dist/grid/cell-range.js +11 -0
- package/dist/grid/column-layout.d.ts +18 -0
- package/dist/grid/column-layout.js +49 -0
- package/dist/grid/column-selection.d.ts +11 -0
- package/dist/grid/column-selection.js +28 -0
- package/dist/grid/column-view.d.ts +10 -0
- package/dist/grid/column-view.js +23 -0
- package/dist/grid/copy-formats.d.ts +15 -0
- package/dist/grid/copy-formats.js +80 -0
- package/dist/grid/display.d.ts +20 -0
- package/dist/grid/display.js +81 -0
- package/dist/grid/edit-value.d.ts +5 -0
- package/dist/grid/edit-value.js +55 -0
- package/dist/grid/enum-type.d.ts +7 -0
- package/dist/grid/enum-type.js +52 -0
- package/dist/grid/focused-value.d.ts +4 -0
- package/dist/grid/focused-value.js +19 -0
- package/dist/grid/layout.d.ts +22 -0
- package/dist/grid/layout.js +74 -0
- package/dist/grid/navigation.d.ts +15 -0
- package/dist/grid/navigation.js +52 -0
- package/dist/grid/row-selection.d.ts +9 -0
- package/dist/grid/row-selection.js +24 -0
- package/dist/grid/sort.d.ts +7 -0
- package/dist/grid/sort.js +7 -0
- package/dist/grid/types.d.ts +30 -0
- package/dist/grid/types.js +9 -0
- package/dist/host/helper-path.d.ts +7 -0
- package/dist/host/helper-path.js +15 -0
- package/dist/host/host.d.ts +2 -0
- package/dist/host/host.js +343 -0
- package/dist/host/index.d.ts +5 -0
- package/dist/host/index.js +4 -0
- package/dist/host/spawn.d.ts +7 -0
- package/dist/host/spawn.js +98 -0
- package/dist/host/types.d.ts +19 -0
- package/dist/host/types.js +1 -0
- package/dist/host/validate.d.ts +10 -0
- package/dist/host/validate.js +339 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +13 -0
- package/dist/locales/en.json +577 -0
- package/dist/locales/nl.json +577 -0
- package/dist/locales.d.ts +4 -0
- package/dist/locales.js +14 -0
- package/dist/protocol/connection.d.ts +56 -0
- package/dist/protocol/connection.js +1 -0
- package/dist/protocol/errors.d.ts +7 -0
- package/dist/protocol/errors.js +1 -0
- package/dist/protocol/index.d.ts +5 -0
- package/dist/protocol/index.js +3 -0
- package/dist/protocol/messages.d.ts +250 -0
- package/dist/protocol/messages.js +2 -0
- package/dist/protocol/schema.d.ts +53 -0
- package/dist/protocol/schema.js +1 -0
- package/dist/protocol/values.d.ts +21 -0
- package/dist/protocol/values.js +15 -0
- package/dist/sql-split.d.ts +15 -0
- package/dist/sql-split.js +201 -0
- package/dist/sql.d.ts +29 -0
- package/dist/sql.js +104 -0
- package/dist/structure/StructureView.d.ts +14 -0
- package/dist/structure/StructureView.js +99 -0
- package/dist/structure/structure-text.d.ts +2 -0
- package/dist/structure/structure-text.js +2 -0
- package/dist/table/CommandField.d.ts +14 -0
- package/dist/table/CommandField.js +157 -0
- package/dist/table/ImportDialog.d.ts +27 -0
- package/dist/table/ImportDialog.js +28 -0
- package/dist/table/TableStatusBar.d.ts +19 -0
- package/dist/table/TableStatusBar.js +22 -0
- package/dist/table/TableToolbar.d.ts +43 -0
- package/dist/table/TableToolbar.js +16 -0
- package/dist/table/TableView.d.ts +13 -0
- package/dist/table/TableView.js +508 -0
- package/dist/table/command-field.d.ts +57 -0
- package/dist/table/command-field.js +203 -0
- package/dist/table/grid-rows.d.ts +23 -0
- package/dist/table/grid-rows.js +55 -0
- package/dist/table/import-mapping.d.ts +7 -0
- package/dist/table/import-mapping.js +28 -0
- package/dist/table/layout-store.d.ts +13 -0
- package/dist/table/layout-store.js +43 -0
- package/dist/table/paging.d.ts +12 -0
- package/dist/table/paging.js +20 -0
- package/dist/table/pending.d.ts +32 -0
- package/dist/table/pending.js +94 -0
- package/dist/table/references.d.ts +12 -0
- package/dist/table/references.js +21 -0
- package/dist/table/useLoaded.d.ts +7 -0
- package/dist/table/useLoaded.js +36 -0
- package/dist/table/useStoredLayout.d.ts +8 -0
- package/dist/table/useStoredLayout.js +39 -0
- package/dist/table/useTableTransfer.d.ts +51 -0
- package/dist/table/useTableTransfer.js +125 -0
- package/dist/testing/fake.d.ts +21 -0
- package/dist/testing/fake.js +372 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1 -0
- package/dist/use-popup-press.d.ts +1 -0
- package/dist/use-popup-press.js +24 -0
- package/dist/use-schema-change.d.ts +1 -0
- package/dist/use-schema-change.js +13 -0
- package/dist/use-stable-callback.d.ts +1 -0
- package/dist/use-stable-callback.js +9 -0
- package/dist/value/ValuePanel.d.ts +14 -0
- package/dist/value/ValuePanel.js +103 -0
- package/dist/value/draft.d.ts +33 -0
- package/dist/value/draft.js +44 -0
- package/dist/value/hex.d.ts +14 -0
- package/dist/value/hex.js +46 -0
- package/dist/value/json.d.ts +9 -0
- package/dist/value/json.js +71 -0
- package/dist/value/views.d.ts +22 -0
- package/dist/value/views.js +54 -0
- package/dist/workbench/DatabaseWorkbench.d.ts +9 -0
- package/dist/workbench/DatabaseWorkbench.js +179 -0
- package/dist/workbench/DesignerTab.d.ts +10 -0
- package/dist/workbench/DesignerTab.js +22 -0
- package/dist/workbench/TableTab.d.ts +10 -0
- package/dist/workbench/TableTab.js +8 -0
- package/dist/workbench/tabs.d.ts +42 -0
- package/dist/workbench/tabs.js +139 -0
- package/package.json +79 -3
- package/src/DatabaseProvider.tsx +37 -0
- package/src/actions.ts +34 -0
- package/src/client/client.ts +324 -0
- package/src/client/index.ts +18 -0
- package/src/client/types.ts +161 -0
- package/src/client-context.ts +35 -0
- package/src/connections/ConnectionForm.tsx +474 -0
- package/src/connections/ConnectionManager.tsx +224 -0
- package/src/connections/EngineIcon.tsx +18 -0
- package/src/connections/connection-config.ts +143 -0
- package/src/connections/docker.ts +50 -0
- package/src/connections/engine-icons.ts +5 -0
- package/src/connections/use-docker-containers.ts +41 -0
- package/src/console/DestructiveDialog.tsx +40 -0
- package/src/console/HistoryPanel.tsx +67 -0
- package/src/console/QueryConsole.tsx +439 -0
- package/src/console/SchemaPicker.tsx +32 -0
- package/src/console/SqlEditor.tsx +95 -0
- package/src/console/StatementResultView.tsx +176 -0
- package/src/console/TransactionControls.tsx +53 -0
- package/src/console/destructive.ts +60 -0
- package/src/console/editing.ts +77 -0
- package/src/console/history.ts +62 -0
- package/src/console/labels.ts +7 -0
- package/src/console/outcome.ts +14 -0
- package/src/console/schemas.ts +7 -0
- package/src/console/shortcuts.ts +4 -0
- package/src/console/useConsoleHistory.ts +39 -0
- package/src/ddl/alter-mysql.ts +90 -0
- package/src/ddl/alter-sqlite.ts +93 -0
- package/src/ddl/alter.ts +29 -0
- package/src/ddl/column.ts +74 -0
- package/src/ddl/create.ts +92 -0
- package/src/ddl/dialect.ts +53 -0
- package/src/ddl/diff.ts +164 -0
- package/src/ddl/draft.ts +136 -0
- package/src/ddl/index.ts +10 -0
- package/src/ddl/parse.ts +161 -0
- package/src/ddl/statements.ts +20 -0
- package/src/ddl/types.ts +60 -0
- package/src/ddl/validate.ts +47 -0
- package/src/designer/ColumnsEditor.tsx +204 -0
- package/src/designer/DesignerView.tsx +184 -0
- package/src/designer/ForeignKeysEditor.tsx +132 -0
- package/src/designer/IndexesEditor.tsx +63 -0
- package/src/designer/NamePicker.tsx +44 -0
- package/src/designer/OptionsEditor.tsx +101 -0
- package/src/designer/SqlPreview.tsx +56 -0
- package/src/designer/TableDesigner.tsx +186 -0
- package/src/designer/edit.ts +137 -0
- package/src/designer/editor-props.ts +13 -0
- package/src/designer/plan.ts +25 -0
- package/src/designer/recover.ts +20 -0
- package/src/designer/useReferenceColumns.ts +54 -0
- package/src/explorer/DatabaseExplorer.tsx +450 -0
- package/src/explorer/RowMenu.tsx +134 -0
- package/src/explorer/TableDialog.tsx +80 -0
- package/src/explorer/expansion.ts +47 -0
- package/src/explorer/table-statements.ts +18 -0
- package/src/explorer/tree.ts +453 -0
- package/src/explorer/use-explorer-loads.ts +157 -0
- package/src/explorer/use-stored-expansion.ts +66 -0
- package/src/grid/CellEditor.tsx +53 -0
- package/src/grid/CopyAsMenu.tsx +33 -0
- package/src/grid/DataGrid.tsx +871 -0
- package/src/grid/EnumPicker.tsx +108 -0
- package/src/grid/GridHeaderCell.tsx +243 -0
- package/src/grid/RecordView.tsx +293 -0
- package/src/grid/ValueDock.tsx +52 -0
- package/src/grid/aggregates.ts +94 -0
- package/src/grid/cell-range.ts +26 -0
- package/src/grid/column-layout.ts +71 -0
- package/src/grid/column-selection.ts +42 -0
- package/src/grid/column-view.ts +35 -0
- package/src/grid/copy-formats.ts +108 -0
- package/src/grid/display.ts +109 -0
- package/src/grid/edit-value.ts +60 -0
- package/src/grid/enum-type.ts +62 -0
- package/src/grid/focused-value.ts +23 -0
- package/src/grid/layout.ts +91 -0
- package/src/grid/navigation.ts +74 -0
- package/src/grid/row-selection.ts +35 -0
- package/src/grid/sort.ts +12 -0
- package/src/grid/types.ts +59 -0
- package/src/host/helper-path.ts +41 -0
- package/src/host/host.ts +456 -0
- package/src/host/index.ts +5 -0
- package/src/host/spawn.ts +124 -0
- package/src/host/types.ts +46 -0
- package/src/host/validate.ts +402 -0
- package/src/index.ts +37 -0
- package/src/locales/en.json +577 -0
- package/src/locales/nl.json +577 -0
- package/src/locales.ts +18 -0
- package/src/protocol/connection.ts +86 -0
- package/src/protocol/errors.ts +38 -0
- package/src/protocol/index.ts +33 -0
- package/src/protocol/messages.ts +168 -0
- package/src/protocol/schema.ts +76 -0
- package/src/protocol/values.ts +52 -0
- package/src/sql-split.ts +220 -0
- package/src/sql.ts +152 -0
- package/src/structure/StructureView.tsx +269 -0
- package/src/structure/structure-text.ts +4 -0
- package/src/table/CommandField.tsx +318 -0
- package/src/table/ImportDialog.tsx +168 -0
- package/src/table/TableStatusBar.tsx +91 -0
- package/src/table/TableToolbar.tsx +217 -0
- package/src/table/TableView.tsx +880 -0
- package/src/table/command-field.ts +285 -0
- package/src/table/grid-rows.ts +80 -0
- package/src/table/import-mapping.ts +37 -0
- package/src/table/layout-store.ts +62 -0
- package/src/table/paging.ts +33 -0
- package/src/table/pending.ts +143 -0
- package/src/table/references.ts +38 -0
- package/src/table/useLoaded.ts +58 -0
- package/src/table/useStoredLayout.ts +53 -0
- package/src/table/useTableTransfer.ts +187 -0
- package/src/testing/fake.ts +533 -0
- package/src/testing/index.ts +1 -0
- package/src/use-popup-press.ts +27 -0
- package/src/use-schema-change.ts +19 -0
- package/src/use-stable-callback.ts +12 -0
- package/src/value/ValuePanel.tsx +254 -0
- package/src/value/draft.ts +72 -0
- package/src/value/hex.ts +62 -0
- package/src/value/json.ts +74 -0
- package/src/value/views.ts +68 -0
- package/src/workbench/DatabaseWorkbench.tsx +348 -0
- package/src/workbench/DesignerTab.tsx +37 -0
- package/src/workbench/TableTab.tsx +27 -0
- package/src/workbench/tabs.ts +184 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Field, Input, Switch, TextArea } from '@adecore/ui';
|
|
6
|
+
import { MYSQL_CHARSETS, MYSQL_ENGINES, collationSuggestionsOf } from '../ddl/index.js';
|
|
7
|
+
import { patchOptions } from './edit.js';
|
|
8
|
+
/* The options of a table, which differ per engine: a storage engine and character set on MySQL, rowid and strict typing on SQLite. */
|
|
9
|
+
export function OptionsEditor({ draft, dialect, disabled, onChange, className, ref }) {
|
|
10
|
+
const { t } = useTranslation('database');
|
|
11
|
+
const id = useId();
|
|
12
|
+
const { options } = draft;
|
|
13
|
+
if (dialect.engine === 'sqlite') {
|
|
14
|
+
return (_jsxs("div", { ref: ref, className: clsx('flex flex-col gap-4 p-3', className), children: [_jsxs("label", { className: "flex items-start gap-3", children: [_jsx(Switch, { label: t('designer.options.withoutRowid'), checked: options.withoutRowid, disabled: disabled, onCheckedChange: (checked) => onChange(patchOptions(draft, { withoutRowid: checked })) }), _jsxs("span", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm text-text", children: t('designer.options.withoutRowid') }), _jsx("span", { className: "text-xs text-text-muted", children: t('designer.options.withoutRowidHint') })] })] }), _jsxs("label", { className: "flex items-start gap-3", children: [_jsx(Switch, { label: t('designer.options.strict'), checked: options.strict, disabled: disabled, onCheckedChange: (checked) => onChange(patchOptions(draft, { strict: checked })) }), _jsxs("span", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm text-text", children: t('designer.options.strict') }), _jsx("span", { className: "text-xs text-text-muted", children: t('designer.options.strictHint') })] })] })] }));
|
|
15
|
+
}
|
|
16
|
+
return (_jsxs("div", { ref: ref, className: clsx('flex max-w-xl flex-col gap-4 p-3', className), children: [_jsx("datalist", { id: `${id}-engines`, children: MYSQL_ENGINES.map((engine) => (_jsx("option", { value: engine }, engine))) }), _jsx("datalist", { id: `${id}-charsets`, children: MYSQL_CHARSETS.map((charset) => (_jsx("option", { value: charset }, charset))) }), _jsx("datalist", { id: `${id}-collations`, children: collationSuggestionsOf(options.charset).map((collation) => (_jsx("option", { value: collation }, collation))) }), _jsx(Field, { label: t('designer.options.engine'), hint: t('designer.options.serverDefault'), children: _jsx(Input, { mono: true, list: `${id}-engines`, spellCheck: false, value: options.engine, disabled: disabled, onChange: (event) => onChange(patchOptions(draft, { engine: event.target.value })) }) }), _jsx(Field, { label: t('designer.options.charset'), hint: t('designer.options.serverDefault'), children: _jsx(Input, { mono: true, list: `${id}-charsets`, spellCheck: false, value: options.charset, disabled: disabled, onChange: (event) => onChange(patchOptions(draft, { charset: event.target.value })) }) }), _jsx(Field, { label: t('designer.options.collation'), hint: t('designer.options.serverDefault'), children: _jsx(Input, { mono: true, list: `${id}-collations`, spellCheck: false, value: options.collation, disabled: disabled, onChange: (event) => onChange(patchOptions(draft, { collation: event.target.value })) }) }), _jsx(Field, { label: t('designer.options.comment'), children: _jsx(TextArea, { rows: 3, value: options.comment, disabled: disabled, onChange: (event) => onChange(patchOptions(draft, { comment: event.target.value })) }) })] }));
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Ref } from 'react';
|
|
2
|
+
import type { DraftProblem } from '../ddl/index.ts';
|
|
3
|
+
import type { Plan } from './plan.ts';
|
|
4
|
+
export interface SqlPreviewProps {
|
|
5
|
+
plan: Plan;
|
|
6
|
+
className?: string;
|
|
7
|
+
ref?: Ref<HTMLDivElement>;
|
|
8
|
+
}
|
|
9
|
+
export declare function ProblemText({ problem }: {
|
|
10
|
+
problem: DraftProblem;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export declare function SqlPreview({ plan, className, ref }: SqlPreviewProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { Copy } from 'lucide-react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Button, Icon, copyText } from '@adecore/ui';
|
|
6
|
+
import { scriptOf } from './plan.js';
|
|
7
|
+
/* The sentence a problem of the draft is read as. */
|
|
8
|
+
export function ProblemText({ problem }) {
|
|
9
|
+
const { t } = useTranslation('database');
|
|
10
|
+
return _jsx(_Fragment, { children: t(`ddl.problem.${problem.code}`, { subject: problem.subject }) });
|
|
11
|
+
}
|
|
12
|
+
/* What Apply would run, as a person reads it: monospace, read only, and copyable. */
|
|
13
|
+
export function SqlPreview({ plan, className, ref }) {
|
|
14
|
+
const { t } = useTranslation('database');
|
|
15
|
+
const script = scriptOf(plan.statements);
|
|
16
|
+
return (_jsxs("section", { ref: ref, "aria-label": t('designer.sql'), className: clsx('relative flex min-h-0 flex-col border-t border-border-soft bg-surface-sunken', className), children: [_jsxs("div", { className: "flex h-8 shrink-0 items-center justify-between pr-2 pl-3", children: [_jsx("span", { className: "text-xs font-medium text-text-faint", children: t('designer.sql') }), _jsxs(Button, { variant: "ghost", size: "xs", disabled: script === '', onClick: () => copyText(script), children: [_jsx(Icon, { icon: Copy, size: 12 }), t('designer.copy')] })] }), _jsx("div", { className: "max-h-48 min-h-12 overflow-auto px-3 pb-3 select-text", children: plan.problems.length > 0 ? (_jsx("ul", { className: "flex flex-col gap-1 text-xs text-status-error", children: plan.problems.map((problem, i) => (_jsx("li", { children: _jsx(ProblemText, { problem: problem }) }, `${problem.code}:${problem.subject}:${i}`))) })) : script === '' ? (_jsx("p", { className: "text-xs text-text-faint", children: t('designer.noChanges') })) : (_jsx("pre", { className: "font-mono text-code whitespace-pre text-text", children: script })) })] }));
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import type { Connection } from '../client/types.ts';
|
|
3
|
+
export interface TableDesignerProps {
|
|
4
|
+
connection: Connection;
|
|
5
|
+
schema: string;
|
|
6
|
+
table?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
ref?: Ref<HTMLDivElement>;
|
|
9
|
+
}
|
|
10
|
+
export declare function TableDesigner({ connection, schema, table, className, ref }: TableDesignerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useRef, useState } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { CircleAlert, RefreshCw } from 'lucide-react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Banner, Button, Spinner, messageOf } from '@adecore/ui';
|
|
7
|
+
import { useDatabaseAction, useDatabaseClient } from '../client-context.js';
|
|
8
|
+
import { dialectOf, draftOf, emptyDraft } from '../ddl/index.js';
|
|
9
|
+
import { useLoaded } from '../table/useLoaded.js';
|
|
10
|
+
import { useSchemaChange } from '../use-schema-change.js';
|
|
11
|
+
import { DesignerView } from './DesignerView.js';
|
|
12
|
+
import { planOf } from './plan.js';
|
|
13
|
+
import { recoverFrom } from './recover.js';
|
|
14
|
+
import { useReferenceColumns } from './useReferenceColumns.js';
|
|
15
|
+
/* Creates a table or modifies one: its columns, indexes, foreign keys and options, with the SQL it will run shown before it runs. */
|
|
16
|
+
export function TableDesigner({ connection, schema, table, className, ref }) {
|
|
17
|
+
const { t } = useTranslation('database');
|
|
18
|
+
const client = useDatabaseClient();
|
|
19
|
+
const onAction = useDatabaseAction();
|
|
20
|
+
const [subject, setSubject] = useState({ requested: table, current: table ?? null });
|
|
21
|
+
const [editing, setEditing] = useState({ snapshot: null, baseline: emptyDraft(), draft: emptyDraft() });
|
|
22
|
+
const [confirming, setConfirming] = useState(false);
|
|
23
|
+
const [failure, setFailure] = useState(null);
|
|
24
|
+
const [shapeChanged, setShapeChanged] = useState(false);
|
|
25
|
+
const applying = useRef(false);
|
|
26
|
+
if (subject.requested !== table) {
|
|
27
|
+
setSubject({ requested: table, current: table ?? null });
|
|
28
|
+
}
|
|
29
|
+
const loaded = useLoaded(async (signal) => {
|
|
30
|
+
const session = client.session(connection);
|
|
31
|
+
const [server, structure, tables] = await Promise.all([
|
|
32
|
+
session.server({ signal }),
|
|
33
|
+
subject.current === null ? Promise.resolve(null) : session.structure(schema, subject.current, { signal }),
|
|
34
|
+
session.tables(schema, { signal })
|
|
35
|
+
]);
|
|
36
|
+
return { dialect: dialectOf(server), structure, tables: tables.filter((info) => info.kind === 'table').map((info) => info.name) };
|
|
37
|
+
}, JSON.stringify([connection.id, schema, subject.current]));
|
|
38
|
+
const snapshot = loaded.value;
|
|
39
|
+
// The apply of this designer reloads by itself; a change from elsewhere replaces an untouched draft and warns about an edited one.
|
|
40
|
+
useSchemaChange(connection.id, schema, () => {
|
|
41
|
+
if (applying.current) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (editing.draft === editing.baseline) {
|
|
45
|
+
loaded.reload();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
setShapeChanged(true);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
// A new snapshot, after a load or an apply, starts a fresh draft.
|
|
52
|
+
if (snapshot !== null && editing.snapshot !== snapshot) {
|
|
53
|
+
const baseline = snapshot.structure === null ? emptyDraft() : draftOf(snapshot.structure);
|
|
54
|
+
setEditing({ snapshot, baseline, draft: baseline });
|
|
55
|
+
setShapeChanged(false);
|
|
56
|
+
}
|
|
57
|
+
const draft = editing.draft;
|
|
58
|
+
const plan = useMemo(() => (snapshot === null ? null : planOf(snapshot.dialect, schema, snapshot.structure, draft)), [snapshot, schema, draft]);
|
|
59
|
+
const referenceColumns = useReferenceColumns(client, connection, schema, draft);
|
|
60
|
+
const readOnlyReason = connection.config.readOnly === true ? t('designer.readOnly.connection') : snapshot?.structure?.kind === 'view' ? t('designer.readOnly.view') : null;
|
|
61
|
+
async function apply() {
|
|
62
|
+
if (snapshot === null || plan === null) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const session = client.session(connection);
|
|
66
|
+
const statements = plan.statements;
|
|
67
|
+
const wasNew = snapshot.structure === null;
|
|
68
|
+
let outcome;
|
|
69
|
+
applying.current = true;
|
|
70
|
+
try {
|
|
71
|
+
outcome = await session.execute(statements.join(';\n'), { schema });
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
setFailure(messageOf(e, t('designer.failed')));
|
|
75
|
+
setConfirming(false);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
applying.current = false;
|
|
80
|
+
}
|
|
81
|
+
const failed = outcome.results.find((result) => result.kind === 'error');
|
|
82
|
+
if (failed?.kind === 'error') {
|
|
83
|
+
await recoverFrom(session, statements, failed.sql, outcome.inTransaction);
|
|
84
|
+
setFailure(failed.error.message);
|
|
85
|
+
setConfirming(false);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
setFailure(null);
|
|
89
|
+
setConfirming(false);
|
|
90
|
+
// The client has told its listeners already: `execute` does for a statement that creates, alters or drops.
|
|
91
|
+
if (wasNew || draft.name !== draft.originalName) {
|
|
92
|
+
setSubject({ requested: table, current: draft.name });
|
|
93
|
+
onAction?.({ kind: 'edit-table', ref: { connectionId: connection.id, schema, table: draft.name } });
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
loaded.reload();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return (_jsxs("div", { ref: ref, className: clsx('flex min-h-0 min-w-0 flex-col', className), children: [(loaded.loading || snapshot === null) && loaded.error === null && (_jsx("div", { className: "grid grow place-items-center py-8 text-text-muted", children: _jsx(Spinner, { size: 20, label: t('designer.loading') }) })), loaded.error !== null && snapshot === null && (_jsx("div", { className: "p-3", children: _jsx(Banner, { icon: CircleAlert, tone: "error", className: "w-full", message: loaded.error, children: _jsx(Button, { variant: "secondary", size: "sm", onClick: loaded.reload, children: t('designer.retry') }) }) })), shapeChanged && (_jsx("div", { className: "shrink-0 px-3 pt-3", children: _jsx(Banner, { icon: RefreshCw, tone: "neutral", className: "w-full", message: t('designer.changed'), children: _jsx(Button, { variant: "secondary", size: "sm", onClick: loaded.reload, children: t('designer.reload') }) }) })), !loaded.loading && snapshot !== null && plan !== null && (_jsx(DesignerView, { className: "grow", dialect: snapshot.dialect, schema: schema, draft: draft, isNew: snapshot.structure === null, changed: draft !== editing.baseline, tables: snapshot.tables, plan: plan, readOnlyReason: readOnlyReason, failure: failure, confirming: confirming, referenceColumns: referenceColumns, onChange: (next) => setEditing({ ...editing, draft: next }), onRequestApply: () => setConfirming(true), onConfirm: apply, onCancelConfirm: () => setConfirming(false), onRevert: () => {
|
|
100
|
+
setEditing({ ...editing, draft: editing.baseline });
|
|
101
|
+
setFailure(null);
|
|
102
|
+
}, onDismissFailure: () => setFailure(null) }))] }));
|
|
103
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ColumnDraft, type ForeignKeyDraft, type IndexDraft, type TableDraft, type TableOptions } from '../ddl/index.ts';
|
|
2
|
+
export declare const renameTable: (draft: TableDraft, name: string) => TableDraft;
|
|
3
|
+
export declare const addColumn: (draft: TableDraft, type: string) => TableDraft;
|
|
4
|
+
export declare const patchColumn: (draft: TableDraft, key: string, patch: Partial<ColumnDraft>) => TableDraft;
|
|
5
|
+
export declare const removeColumn: (draft: TableDraft, key: string) => TableDraft;
|
|
6
|
+
export declare const moveColumn: (draft: TableDraft, key: string, offset: -1 | 1) => TableDraft;
|
|
7
|
+
export declare const togglePrimaryKey: (draft: TableDraft, key: string) => TableDraft;
|
|
8
|
+
export declare const addIndex: (draft: TableDraft) => TableDraft;
|
|
9
|
+
export declare const patchIndex: (draft: TableDraft, key: string, patch: Partial<IndexDraft>) => TableDraft;
|
|
10
|
+
export declare const toggleIndexColumn: (draft: TableDraft, key: string, column: string) => TableDraft;
|
|
11
|
+
export declare const removeIndex: (draft: TableDraft, key: string) => TableDraft;
|
|
12
|
+
export declare const addForeignKey: (draft: TableDraft, schema: string) => TableDraft;
|
|
13
|
+
export declare const patchForeignKey: (draft: TableDraft, key: string, patch: Partial<ForeignKeyDraft>) => TableDraft;
|
|
14
|
+
export declare const setReferencedTable: (draft: TableDraft, key: string, schema: string, table: string) => TableDraft;
|
|
15
|
+
export declare const toggleForeignKeyColumn: (draft: TableDraft, key: string, side: 'columns' | 'referencedColumns', column: string) => TableDraft;
|
|
16
|
+
export declare const removeForeignKey: (draft: TableDraft, key: string) => TableDraft;
|
|
17
|
+
export declare const patchOptions: (draft: TableDraft, patch: Partial<TableOptions>) => TableDraft;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { emptyColumn, nextKey } from '../ddl/index.js';
|
|
2
|
+
/* The editing steps of a draft. Each returns a new draft and leaves the one it was given alone. */
|
|
3
|
+
const replaceAt = (items, key, change) => items.map((item) => (item.key === key ? change(item) : item));
|
|
4
|
+
const toggled = (names, name) => names.includes(name) ? names.filter((candidate) => candidate !== name) : [...names, name];
|
|
5
|
+
export const renameTable = (draft, name) => ({ ...draft, name });
|
|
6
|
+
export const addColumn = (draft, type) => ({
|
|
7
|
+
...draft,
|
|
8
|
+
columns: [...draft.columns, { ...emptyColumn(), type, name: `column_${draft.columns.length + 1}` }]
|
|
9
|
+
});
|
|
10
|
+
/* A rename carries along every key, index and foreign key that names the column. */
|
|
11
|
+
export const patchColumn = (draft, key, patch) => {
|
|
12
|
+
const before = draft.columns.find((column) => column.key === key);
|
|
13
|
+
if (before === undefined) {
|
|
14
|
+
return draft;
|
|
15
|
+
}
|
|
16
|
+
const inKey = draft.primaryKey.includes(before.name);
|
|
17
|
+
const applied = inKey && patch.nullable === true ? { ...patch, nullable: false } : patch;
|
|
18
|
+
const after = { ...before, ...applied };
|
|
19
|
+
const follow = (names) => names.map((name) => (name === before.name ? after.name : name));
|
|
20
|
+
return {
|
|
21
|
+
...draft,
|
|
22
|
+
columns: replaceAt(draft.columns, key, () => after),
|
|
23
|
+
primaryKey: follow(draft.primaryKey),
|
|
24
|
+
indexes: draft.indexes.map((index) => ({ ...index, columns: follow(index.columns) })),
|
|
25
|
+
foreignKeys: draft.foreignKeys.map((foreignKey) => ({ ...foreignKey, columns: follow(foreignKey.columns) }))
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/* What names the column goes with it: an index keeps its other columns, a foreign key on it is dropped. */
|
|
29
|
+
export const removeColumn = (draft, key) => {
|
|
30
|
+
const gone = draft.columns.find((column) => column.key === key);
|
|
31
|
+
if (gone === undefined) {
|
|
32
|
+
return draft;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
...draft,
|
|
36
|
+
columns: draft.columns.filter((column) => column.key !== key),
|
|
37
|
+
primaryKey: draft.primaryKey.filter((name) => name !== gone.name),
|
|
38
|
+
indexes: draft.indexes
|
|
39
|
+
.map((index) => ({ ...index, columns: index.columns.filter((name) => name !== gone.name) }))
|
|
40
|
+
.filter((index) => index.columns.length > 0),
|
|
41
|
+
foreignKeys: draft.foreignKeys.filter((foreignKey) => !foreignKey.columns.includes(gone.name))
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export const moveColumn = (draft, key, offset) => {
|
|
45
|
+
const from = draft.columns.findIndex((column) => column.key === key);
|
|
46
|
+
const to = from + offset;
|
|
47
|
+
if (from < 0 || to < 0 || to >= draft.columns.length) {
|
|
48
|
+
return draft;
|
|
49
|
+
}
|
|
50
|
+
const columns = [...draft.columns];
|
|
51
|
+
[columns[from], columns[to]] = [columns[to], columns[from]];
|
|
52
|
+
return { ...draft, columns };
|
|
53
|
+
};
|
|
54
|
+
/* A column in the primary key cannot be null, so putting it there says so. */
|
|
55
|
+
export const togglePrimaryKey = (draft, key) => {
|
|
56
|
+
const column = draft.columns.find((candidate) => candidate.key === key);
|
|
57
|
+
if (column === undefined) {
|
|
58
|
+
return draft;
|
|
59
|
+
}
|
|
60
|
+
const joining = !draft.primaryKey.includes(column.name);
|
|
61
|
+
const toggledKey = { ...draft, primaryKey: toggled(draft.primaryKey, column.name) };
|
|
62
|
+
return joining ? patchColumn(toggledKey, key, { nullable: false }) : toggledKey;
|
|
63
|
+
};
|
|
64
|
+
export const addIndex = (draft) => ({
|
|
65
|
+
...draft,
|
|
66
|
+
indexes: [
|
|
67
|
+
...draft.indexes,
|
|
68
|
+
{ key: nextKey(), originalName: null, name: `idx_${draft.name || 'table'}_${draft.indexes.length + 1}`, columns: [], unique: false }
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
export const patchIndex = (draft, key, patch) => ({
|
|
72
|
+
...draft,
|
|
73
|
+
indexes: replaceAt(draft.indexes, key, (index) => ({ ...index, ...patch }))
|
|
74
|
+
});
|
|
75
|
+
export const toggleIndexColumn = (draft, key, column) => ({
|
|
76
|
+
...draft,
|
|
77
|
+
indexes: replaceAt(draft.indexes, key, (index) => ({ ...index, columns: toggled(index.columns, column) }))
|
|
78
|
+
});
|
|
79
|
+
export const removeIndex = (draft, key) => ({ ...draft, indexes: draft.indexes.filter((index) => index.key !== key) });
|
|
80
|
+
export const addForeignKey = (draft, schema) => ({
|
|
81
|
+
...draft,
|
|
82
|
+
foreignKeys: [
|
|
83
|
+
...draft.foreignKeys,
|
|
84
|
+
{
|
|
85
|
+
key: nextKey(),
|
|
86
|
+
originalName: null,
|
|
87
|
+
name: `fk_${draft.name || 'table'}_${draft.foreignKeys.length + 1}`,
|
|
88
|
+
columns: [],
|
|
89
|
+
referencedSchema: schema,
|
|
90
|
+
referencedTable: '',
|
|
91
|
+
referencedColumns: [],
|
|
92
|
+
onUpdate: null,
|
|
93
|
+
onDelete: null
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
export const patchForeignKey = (draft, key, patch) => ({
|
|
98
|
+
...draft,
|
|
99
|
+
foreignKeys: replaceAt(draft.foreignKeys, key, (foreignKey) => ({ ...foreignKey, ...patch }))
|
|
100
|
+
});
|
|
101
|
+
/* Another table has other columns, so the old pick is forgotten. */
|
|
102
|
+
export const setReferencedTable = (draft, key, schema, table) => patchForeignKey(draft, key, { referencedSchema: schema, referencedTable: table, referencedColumns: [] });
|
|
103
|
+
export const toggleForeignKeyColumn = (draft, key, side, column) => ({
|
|
104
|
+
...draft,
|
|
105
|
+
foreignKeys: replaceAt(draft.foreignKeys, key, (foreignKey) => ({ ...foreignKey, [side]: toggled(foreignKey[side], column) }))
|
|
106
|
+
});
|
|
107
|
+
export const removeForeignKey = (draft, key) => ({
|
|
108
|
+
...draft,
|
|
109
|
+
foreignKeys: draft.foreignKeys.filter((foreignKey) => foreignKey.key !== key)
|
|
110
|
+
});
|
|
111
|
+
/* A collation belongs to a character set, so choosing another set empties it. */
|
|
112
|
+
export const patchOptions = (draft, patch) => {
|
|
113
|
+
const charsetChanged = patch.charset !== undefined && patch.charset !== draft.options.charset;
|
|
114
|
+
return { ...draft, options: { ...draft.options, ...(charsetChanged ? { collation: '' } : {}), ...patch } };
|
|
115
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Ref } from 'react';
|
|
2
|
+
import type { Dialect, TableDraft } from '../ddl/index.ts';
|
|
3
|
+
export interface EditorProps {
|
|
4
|
+
draft: TableDraft;
|
|
5
|
+
dialect: Dialect;
|
|
6
|
+
disabled: boolean;
|
|
7
|
+
onChange(draft: TableDraft): void;
|
|
8
|
+
className?: string;
|
|
9
|
+
ref?: Ref<HTMLDivElement>;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TableStructure } from '../protocol/index.ts';
|
|
2
|
+
import { type Dialect, type DraftProblem, type TableDraft } from '../ddl/index.ts';
|
|
3
|
+
export interface Plan {
|
|
4
|
+
readonly problems: readonly DraftProblem[];
|
|
5
|
+
readonly statements: readonly string[];
|
|
6
|
+
readonly destructive: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const planOf: (dialect: Dialect, schema: string, structure: TableStructure | null, draft: TableDraft) => Plan;
|
|
9
|
+
export declare const scriptOf: (statements: readonly string[]) => string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { alterTableSql, createTableSql, dropsColumns, draftOf, validateDraft } from '../ddl/index.js';
|
|
2
|
+
export const planOf = (dialect, schema, structure, draft) => {
|
|
3
|
+
const problems = validateDraft(dialect, draft);
|
|
4
|
+
if (problems.length > 0) {
|
|
5
|
+
return { problems, statements: [], destructive: false };
|
|
6
|
+
}
|
|
7
|
+
if (structure === null) {
|
|
8
|
+
return { problems, statements: createTableSql(dialect, schema, draft), destructive: false };
|
|
9
|
+
}
|
|
10
|
+
return { problems, statements: alterTableSql(dialect, schema, structure, draft), destructive: dropsColumns(draftOf(structure), draft) };
|
|
11
|
+
};
|
|
12
|
+
/* The statements as a person reads them and as a script runs them. */
|
|
13
|
+
export const scriptOf = (statements) => statements.map((statement) => `${statement};`).join('\n');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const REBUILD_START = 'PRAGMA foreign_keys=OFF';
|
|
2
|
+
/*
|
|
3
|
+
* A failed rebuild leaves SQLite with a transaction it began and foreign keys it switched off.
|
|
4
|
+
* Only a transaction this script began is rolled back, since one the person had open is theirs.
|
|
5
|
+
*/
|
|
6
|
+
export async function recoverFrom(session, statements, failedSql, inTransaction) {
|
|
7
|
+
try {
|
|
8
|
+
if (inTransaction && statements.includes('BEGIN') && failedSql.trim().toUpperCase() !== 'BEGIN') {
|
|
9
|
+
await session.transaction('rollback');
|
|
10
|
+
}
|
|
11
|
+
if (statements[0] === REBUILD_START) {
|
|
12
|
+
await session.execute('PRAGMA foreign_keys=ON');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// The error of the statement that failed is the one worth showing.
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { Connection, DatabaseClient } from '../client/types.ts';
|
|
2
|
+
import type { TableDraft } from '../ddl/index.ts';
|
|
3
|
+
export declare function useReferenceColumns(client: DatabaseClient, connection: Connection, schema: string, draft: TableDraft): (table: string) => readonly string[] | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
/*
|
|
3
|
+
* The columns of the tables the draft's foreign keys point at, loaded as they are picked. `scope`
|
|
4
|
+
* is the connection and the schema, so a cache never answers for another. A table that fails to
|
|
5
|
+
* load has no columns to pick from, which stops the wait.
|
|
6
|
+
*/
|
|
7
|
+
export function useReferenceColumns(client, connection, schema, draft) {
|
|
8
|
+
const scope = `${connection.id}\u0000${schema}`;
|
|
9
|
+
const [cache, setCache] = useState({ scope, columns: {} });
|
|
10
|
+
const known = cache.scope === scope ? cache.columns : {};
|
|
11
|
+
const wanted = [...new Set(draft.foreignKeys.map((foreignKey) => foreignKey.referencedTable))]
|
|
12
|
+
.filter((table) => table !== '' && table !== draft.name && !(table in known))
|
|
13
|
+
.sort();
|
|
14
|
+
const wantedKey = wanted.join('\u0000');
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (wantedKey === '') {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
let current = true;
|
|
20
|
+
const session = client.session(connection);
|
|
21
|
+
for (const table of wantedKey.split('\u0000')) {
|
|
22
|
+
session
|
|
23
|
+
.structure(schema, table)
|
|
24
|
+
.then((structure) => structure.columns.map((column) => column.name), () => [])
|
|
25
|
+
.then((names) => {
|
|
26
|
+
if (current) {
|
|
27
|
+
setCache((now) => ({ scope, columns: { ...(now.scope === scope ? now.columns : {}), [table]: names } }));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return () => {
|
|
32
|
+
current = false;
|
|
33
|
+
};
|
|
34
|
+
}, [client, connection, schema, scope, wantedKey]);
|
|
35
|
+
return (table) => (table === draft.name ? draft.columns.map((column) => column.name) : (known[table] ?? null));
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Ref } from 'react';
|
|
2
|
+
import type { ExplorerSelection } from '../actions.ts';
|
|
3
|
+
import type { Connection } from '../client/types.ts';
|
|
4
|
+
export interface DatabaseExplorerProps {
|
|
5
|
+
connections: readonly Connection[];
|
|
6
|
+
value?: ExplorerSelection | null;
|
|
7
|
+
defaultValue?: ExplorerSelection | null;
|
|
8
|
+
onValueChange?(selection: ExplorerSelection | null): void;
|
|
9
|
+
showSystemSchemas?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
ref?: Ref<HTMLDivElement>;
|
|
12
|
+
}
|
|
13
|
+
export declare function DatabaseExplorer({ connections, value, defaultValue, onValueChange, showSystemSchemas, className, ref }: DatabaseExplorerProps): import("react").JSX.Element;
|