From 9cf5973b98a97c3452b66d490c275286844ad46f Mon Sep 17 00:00:00 2001 From: dineug Date: Sat, 16 Dec 2023 16:02:13 +0900 Subject: [PATCH] feat: SQL index --- .../TablePropertiesIndexes.ts | 7 +- .../IndexesCheckboxColumn.ts | 17 ++- .../indexes-column/IndexesColumn.styles.ts | 12 ++ .../indexes-column/IndexesColumn.ts | 70 ++++++--- .../indexes-index/IndexesIndex.ts | 46 ++++-- packages/erd-editor/src/engine/actions.ts | 15 +- .../erd-editor/src/engine/history.actions.ts | 4 + .../engine/modules/index-column/actions.ts | 46 ++++++ .../modules/index-column/atom.actions.ts | 133 +++++++++++++++++- .../modules/index-column/generator.actions.ts | 121 +++++++++++++++- .../engine/modules/index-column/history.ts | 100 ++++++++++++- .../src/engine/modules/index/actions.ts | 40 ++++++ .../src/engine/modules/index/atom.actions.ts | 94 ++++++++++++- .../engine/modules/index/generator.actions.ts | 34 ++++- .../src/engine/modules/index/history.ts | 77 +++++++++- .../src/engine/modules/memo/atom.actions.ts | 4 +- .../modules/relationship/atom.actions.ts | 28 ++-- .../modules/table-column/atom.actions.ts | 3 +- .../modules/table-column/generator.actions.ts | 19 ++- .../src/engine/modules/table/atom.actions.ts | 4 +- .../engine/modules/table/generator.actions.ts | 16 ++- packages/erd-editor/src/engine/rx-store.ts | 2 +- packages/erd-editor/src/engine/store.ts | 4 + .../src/utils/collection/sequence.ts | 19 ++- .../erd-editor/src/utils/schema-sql/MSSQL.ts | 7 +- .../src/utils/schema-sql/MariaDB.ts | 7 +- .../erd-editor/src/utils/schema-sql/MySQL.ts | 7 +- .../erd-editor/src/utils/schema-sql/Oracle.ts | 7 +- .../src/utils/schema-sql/PostgreSQL.ts | 7 +- .../erd-editor/src/utils/schema-sql/SQLite.ts | 7 +- .../erd-editor/src/utils/schema-sql/index.ts | 3 +- .../erd-editor/src/utils/schema-sql/utils.ts | 13 +- .../src/render/directives/node/repeat.ts | 4 +- .../src/render/part/node/text/arrayDiff.ts | 17 ++- 34 files changed, 903 insertions(+), 91 deletions(-) create mode 100644 packages/erd-editor/src/engine/modules/index-column/actions.ts create mode 100644 packages/erd-editor/src/engine/modules/index/actions.ts diff --git a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/TablePropertiesIndexes.ts b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/TablePropertiesIndexes.ts index 8336c008..394787e5 100644 --- a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/TablePropertiesIndexes.ts +++ b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/TablePropertiesIndexes.ts @@ -5,7 +5,7 @@ import IndexesIndex from '@/components/erd/table-properties//table-properties-in import IndexesCheckboxColumn from '@/components/erd/table-properties/table-properties-indexes/indexes-checkbox-column/IndexesCheckboxColumn'; import IndexesColumn from '@/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn'; import Icon from '@/components/primitives/icon/Icon'; -import { useUnmounted } from '@/hooks/useUnmounted'; +import { addIndexAction$ } from '@/engine/modules/index/generator.actions'; import { Index } from '@/internal-types'; import { query } from '@/utils/collection/query'; @@ -20,7 +20,6 @@ const TablePropertiesIndexes: FC = ( ctx ) => { const app = useAppContext(ctx); - const { addUnsubscribe } = useUnmounted(); const state = observable({ index: null as Index | null, @@ -31,8 +30,8 @@ const TablePropertiesIndexes: FC = ( }; const handleAddIndex = () => { - // TODO: add index - console.log('handleAddIndex'); + const { store } = app.value; + store.dispatch(addIndexAction$(props.tableId)); }; return () => { diff --git a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-checkbox-column/IndexesCheckboxColumn.ts b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-checkbox-column/IndexesCheckboxColumn.ts index f3028713..e7e26a48 100644 --- a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-checkbox-column/IndexesCheckboxColumn.ts +++ b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-checkbox-column/IndexesCheckboxColumn.ts @@ -17,6 +17,10 @@ import { ColumnType, Show, } from '@/constants/schema'; +import { + addIndexColumnAction$, + removeIndexColumnAction$, +} from '@/engine/modules/index-column/generator.actions'; import { Column, Index } from '@/internal-types'; import { bHas } from '@/utils/bit'; import { calcTableWidths, ColumnWidth } from '@/utils/calcTable'; @@ -26,7 +30,7 @@ import * as styles from './IndexesCheckboxColumn.styles'; export type IndexesCheckboxColumnProps = { tableId: string; - index: Index | null; + index: Index; }; type ColumnOrderTpl = { @@ -151,8 +155,15 @@ const IndexesCheckboxColumn: FC = (props, ctx) => { }; const handleChangeIndexColumn = (event: InputEvent, column: Column) => { - // TODO: change index column - console.log('handleChangeIndexColumn', event, column); + const input = event.target as HTMLInputElement | null; + if (!input) return; + + const { store } = app.value; + const action$ = input.checked + ? addIndexColumnAction$ + : removeIndexColumnAction$; + + store.dispatch(action$(props.index.id, column.id)); }; return () => { diff --git a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn.styles.ts b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn.styles.ts index 3b463a6e..a573cbde 100644 --- a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn.styles.ts +++ b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn.styles.ts @@ -9,6 +9,10 @@ import { export const root = css` padding-top: 12px; + + .index-column-order-move { + transition: transform 0.3s; + } `; export const row = css` @@ -28,6 +32,14 @@ export const row = css` & > .column-col { padding: ${COLUMN_PADDING}px ${INPUT_MARGIN_RIGHT}px ${COLUMN_PADDING}px 0; } + + &.none-hover { + background-color: transparent; + } + + &.draggable { + opacity: 0.5; + } `; export const orderType = css` diff --git a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn.ts b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn.ts index 4e1f6cec..6ff2f91f 100644 --- a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn.ts +++ b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-column/IndexesColumn.ts @@ -1,12 +1,19 @@ -import { FC, html, repeat } from '@dineug/r-html'; +import { createRef, FC, html, onUpdated, ref, repeat } from '@dineug/r-html'; import { useAppContext } from '@/components/appContext'; import ColumnOption from '@/components/erd/canvas/table/column/column-option/ColumnOption'; import Icon from '@/components/primitives/icon/Icon'; import { OrderType } from '@/constants/schema'; +import { + changeIndexColumnOrderTypeAction$, + moveIndexColumnAction$, +} from '@/engine/modules/index-column/generator.actions'; import { Index, IndexColumn } from '@/internal-types'; import { query } from '@/utils/collection/query'; import { onPrevent } from '@/utils/domEvent'; +import { FlipAnimation } from '@/utils/flipAnimation'; +import { fromShadowDraggable } from '@/utils/rx-operators/fromShadowDraggable'; +import { toOrderName } from '@/utils/schema-sql/utils'; import * as styles from './IndexesColumn.styles'; @@ -16,17 +23,12 @@ export type IndexesColumnProps = { const IndexesColumn: FC = (props, ctx) => { const app = useAppContext(ctx); - - const toOrderName = (orderType: number) => { - switch (orderType) { - case OrderType.ASC: - return 'ASC'; - case OrderType.DESC: - return 'DESC'; - default: - return ''; - } - }; + const root = createRef(); + const flipAnimation = new FlipAnimation( + root, + `.${styles.row}`, + 'index-column-order-move' + ); const toOrderTitle = (orderType: number) => { switch (orderType) { @@ -39,16 +41,45 @@ const IndexesColumn: FC = (props, ctx) => { } }; + const handleMove = (id: string, targetId: string) => { + const { store } = app.value; + + if (id !== targetId) { + flipAnimation.snapshot(); + store.dispatch(moveIndexColumnAction$(id, targetId)); + } + }; + const handleDragstart = (event: DragEvent) => { - // TODO: change order indexColumn - console.log('handleDragstart', event); + const $root = root.value; + const $target = event.target as HTMLElement | null; + if (!$root || !$target) return; + + const id = $target.dataset.id as string; + const elements = Array.from( + $root.querySelectorAll(`.${styles.row}`) + ); + elements.forEach(el => el.classList.add('none-hover')); + $target.classList.add('draggable'); + + fromShadowDraggable(elements).subscribe({ + next: targetId => { + handleMove(id, targetId); + }, + complete: () => { + $target.classList.remove('draggable'); + elements.forEach(el => el.classList.remove('none-hover')); + }, + }); }; const handleChangeOrderType = (indexColumn: IndexColumn) => { - // TODO: change indexColumn orderType - console.log('handleChangeOrderType', indexColumn); + const { store } = app.value; + store.dispatch(changeIndexColumnOrderTypeAction$(indexColumn.id)); }; + onUpdated(() => flipAnimation.play()); + return () => { const { store } = app.value; const { collections } = store.state; @@ -64,7 +95,12 @@ const IndexesColumn: FC = (props, ctx) => { })); return html` -
+
${repeat( indexColumns, indexColumn => indexColumn.id, diff --git a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-index/IndexesIndex.ts b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-index/IndexesIndex.ts index 793ea75b..738dd003 100644 --- a/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-index/IndexesIndex.ts +++ b/packages/erd-editor/src/components/erd/table-properties/table-properties-indexes/indexes-index/IndexesIndex.ts @@ -5,6 +5,11 @@ import ColumnOption from '@/components/erd/canvas/table/column/column-option/Col import Icon from '@/components/primitives/icon/Icon'; import TextInput from '@/components/primitives/text-input/TextInput'; import { COLUMN_UNIQUE_WIDTH } from '@/constants/layout'; +import { + changeIndexNameAction, + removeIndexAction, +} from '@/engine/modules/index/atom.actions'; +import { changeIndexUniqueAction$ } from '@/engine/modules/index/generator.actions'; import { Index } from '@/internal-types'; import * as styles from './IndexesIndex.styles'; @@ -18,21 +23,35 @@ export type IndexesIndexProps = { const IndexesIndex: FC = (props, ctx) => { const app = useAppContext(ctx); - const handleRemoveIndex = (event: MouseEvent, index: Index) => { - // TODO: remove index + const handleSelect = () => { + props.onSelect(props.index); + }; + + const handleRemoveIndex = (event: MouseEvent) => { event.stopPropagation(); props.onSelect(null); - console.log('handleRemoveIndex', index); + + const { store } = app.value; + store.dispatch(removeIndexAction({ id: props.index.id })); }; - const handleChangeUniqueIndex = (index: Index) => { - // TODO: change unique index - console.log('handleChangeUniqueIndex', index); + const handleChangeUniqueIndex = () => { + const { store } = app.value; + store.dispatch(changeIndexUniqueAction$(props.index.id)); }; - const handleChangeIndexName = (event: InputEvent, index: Index) => { - // TODO: change index name - console.log('handleChangeIndexName', event, index); + const handleChangeIndexName = (event: InputEvent) => { + const input = event.target as HTMLInputElement | null; + if (!input) return; + + const { store } = app.value; + store.dispatch( + changeIndexNameAction({ + id: props.index.id, + tableId: props.index.tableId, + value: input.value, + }) + ); }; return () => { @@ -41,9 +60,9 @@ const IndexesIndex: FC = (props, ctx) => { return html`
props.onSelect(index)} + @click=${handleSelect} > -
handleChangeUniqueIndex(index)}> +
<${ColumnOption} class=${styles.unique} checked=${index.unique} @@ -57,8 +76,7 @@ const IndexesIndex: FC = (props, ctx) => { class=${styles.input} placeholder="name" value=${index.name} - .onInput=${(event: InputEvent) => - handleChangeIndexName(event, index)} + .onInput=${handleChangeIndexName} />
<${Icon} @@ -66,7 +84,7 @@ const IndexesIndex: FC = (props, ctx) => { size=${12} name="xmark" title="Remove" - .onClick=${(event: MouseEvent) => handleRemoveIndex(event, index)} + .onClick=${handleRemoveIndex} />
`; diff --git a/packages/erd-editor/src/engine/actions.ts b/packages/erd-editor/src/engine/actions.ts index 55526661..7090770f 100644 --- a/packages/erd-editor/src/engine/actions.ts +++ b/packages/erd-editor/src/engine/actions.ts @@ -5,8 +5,10 @@ import { import { ActionMap as EditorActionMap } from '@/engine/modules/editor/actions'; import { actions as editorActions } from '@/engine/modules/editor/atom.actions'; import { actions$ as editorActions$ } from '@/engine/modules/editor/generator.actions'; +import { ActionMap as IndexActionMap } from '@/engine/modules/index/actions'; import { actions as indexActions } from '@/engine/modules/index/atom.actions'; import { actions$ as indexActions$ } from '@/engine/modules/index/generator.actions'; +import { ActionMap as IndexColumnActionMap } from '@/engine/modules/index-column/actions'; import { actions as indexColumnActions } from '@/engine/modules/index-column/atom.actions'; import { actions$ as indexColumnActions$ } from '@/engine/modules/index-column/generator.actions'; import { ActionMap as MemoActionMap } from '@/engine/modules/memo/actions'; @@ -47,7 +49,9 @@ export type RootActionMap = EditorActionMap & TableColumnActionMap & MemoActionMap & RelationshipActionMap & - SettingsActionMap; + SettingsActionMap & + IndexActionMap & + IndexColumnActionMap; export type ActionType = keyof RootActionMap; @@ -70,7 +74,6 @@ export const actions: Actions = Object.freeze({ ...tableColumnActions$, }); -// TODO: changeActionTypes export const ChangeActionTypes: ReadonlyArray = [ // table 'table.add', @@ -96,7 +99,15 @@ export const ChangeActionTypes: ReadonlyArray = [ 'relationship.remove', 'relationship.changeType', // index + 'index.add', + 'index.remove', + 'index.changeName', + 'index.changeUnique', // indexColumn + 'indexColumn.add', + 'indexColumn.remove', + 'indexColumn.move', + 'indexColumn.changeOrderType', // memo 'memo.add', 'memo.move', diff --git a/packages/erd-editor/src/engine/history.actions.ts b/packages/erd-editor/src/engine/history.actions.ts index ecfdd8cf..a6e8a28b 100644 --- a/packages/erd-editor/src/engine/history.actions.ts +++ b/packages/erd-editor/src/engine/history.actions.ts @@ -4,6 +4,8 @@ import { cloneDeep } from 'lodash-es'; import { History } from '@/engine/history'; import { editorPushUndoHistoryMap } from '@/engine/modules/editor/history'; +import { indexPushUndoHistoryMap } from '@/engine/modules/index/history'; +import { indexColumnPushUndoHistoryMap } from '@/engine/modules/index-column/history'; import { memoPushStreamHistoryMap, memoPushUndoHistoryMap, @@ -41,6 +43,8 @@ export const pushUndoHistoryMap: Record = { ...memoPushUndoHistoryMap, ...settingsPushUndoHistoryMap, ...editorPushUndoHistoryMap, + ...indexPushUndoHistoryMap, + ...indexColumnPushUndoHistoryMap, }; export const pushStreamHistoryMap: Record = { diff --git a/packages/erd-editor/src/engine/modules/index-column/actions.ts b/packages/erd-editor/src/engine/modules/index-column/actions.ts new file mode 100644 index 00000000..213873c6 --- /dev/null +++ b/packages/erd-editor/src/engine/modules/index-column/actions.ts @@ -0,0 +1,46 @@ +import { Reducer } from '@dineug/r-html'; + +import { EngineContext } from '@/engine/context'; +import { RootState } from '@/engine/state'; +import { ValuesType } from '@/internal-types'; + +export const ActionType = { + addIndexColumn: 'indexColumn.add', + removeIndexColumn: 'indexColumn.remove', + moveIndexColumn: 'indexColumn.move', + changeIndexColumnOrderType: 'indexColumn.changeOrderType', +} as const; +export type ActionType = ValuesType; + +export type ActionMap = { + [ActionType.addIndexColumn]: { + id: string; + indexId: string; + tableId: string; + columnId: string; + }; + [ActionType.removeIndexColumn]: { + id: string; + indexId: string; + tableId: string; + }; + [ActionType.moveIndexColumn]: { + id: string; + indexId: string; + tableId: string; + targetId: string; + }; + [ActionType.changeIndexColumnOrderType]: { + id: string; + indexId: string; + columnId: string; + value: number; + }; +}; + +export type ReducerType = Reducer< + RootState, + T, + ActionMap, + EngineContext +>; diff --git a/packages/erd-editor/src/engine/modules/index-column/atom.actions.ts b/packages/erd-editor/src/engine/modules/index-column/atom.actions.ts index 576d6d28..4a64f249 100644 --- a/packages/erd-editor/src/engine/modules/index-column/atom.actions.ts +++ b/packages/erd-editor/src/engine/modules/index-column/atom.actions.ts @@ -1 +1,132 @@ -export const actions = {}; +import { createAction } from '@dineug/r-html'; +import { arrayHas } from '@dineug/shared'; + +import { createIndex } from '@/utils/collection/index.entity'; +import { createIndexColumn } from '@/utils/collection/indexColumn.entity'; +import { query } from '@/utils/collection/query'; +import { addAndSort } from '@/utils/collection/sequence'; + +import { ActionMap, ActionType, ReducerType } from './actions'; + +export const addIndexColumnAction = createAction< + ActionMap[typeof ActionType.addIndexColumn] +>(ActionType.addIndexColumn); + +const addIndexColumn: ReducerType = ( + { collections, lww }, + { payload: { id, indexId, tableId, columnId }, timestamp } +) => { + const indexCollection = query(collections).collection('indexEntities'); + const index = indexCollection.getOrCreate(indexId, id => + createIndex({ id, tableId }) + ); + + query(collections) + .collection('indexColumnEntities') + .addOne(createIndexColumn({ id, indexId, columnId })) + .addOperator(lww, timestamp, id, () => { + if (!arrayHas(index.indexColumnIds)(id)) { + indexCollection.updateOne(indexId, index => { + addAndSort(index.indexColumnIds, index.seqIndexColumnIds, id); + }); + } + }); +}; + +export const removeIndexColumnAction = createAction< + ActionMap[typeof ActionType.removeIndexColumn] +>(ActionType.removeIndexColumn); + +const removeIndexColumn: ReducerType = ( + { collections, lww }, + { payload: { id, indexId, tableId }, timestamp } +) => { + const indexCollection = query(collections).collection('indexEntities'); + const index = indexCollection.getOrCreate(indexId, id => + createIndex({ id, tableId }) + ); + + query(collections) + .collection('indexColumnEntities') + .removeOperator(lww, timestamp, id, () => { + const i = index.indexColumnIds.indexOf(id); + if (i !== -1) { + indexCollection.updateOne(indexId, index => { + index.indexColumnIds.splice(i, 1); + }); + } + }); +}; + +export const moveIndexColumnAction = createAction< + ActionMap[typeof ActionType.moveIndexColumn] +>(ActionType.moveIndexColumn); + +const moveIndexColumn: ReducerType = ( + { collections }, + { payload: { id, indexId, tableId, targetId } } +) => { + if (id === targetId) { + return; + } + + const indexCollection = query(collections).collection('indexEntities'); + const index = indexCollection.getOrCreate(indexId, id => + createIndex({ id, tableId }) + ); + + const i = index.indexColumnIds.indexOf(id); + if (i === -1) return; + + const targetIndex = index.indexColumnIds.indexOf(targetId); + if (targetIndex === -1) return; + + indexCollection.updateOne(indexId, index => { + index.indexColumnIds.splice(i, 1); + index.indexColumnIds.splice(targetIndex, 0, id); + + const seqIndex = index.seqIndexColumnIds.indexOf(id); + const seqTargetIndex = index.seqIndexColumnIds.indexOf(targetId); + + if (seqIndex !== -1 && seqTargetIndex !== -1) { + index.seqIndexColumnIds.splice(seqIndex, 1); + index.seqIndexColumnIds.splice(seqTargetIndex, 0, id); + } + }); +}; + +export const changeIndexColumnOrderTypeAction = createAction< + ActionMap[typeof ActionType.changeIndexColumnOrderType] +>(ActionType.changeIndexColumnOrderType); + +const changeIndexColumnOrderType: ReducerType< + typeof ActionType.changeIndexColumnOrderType +> = ( + { collections, lww }, + { payload: { id, indexId, columnId, value }, timestamp } +) => { + const collection = query(collections).collection('indexColumnEntities'); + collection.getOrCreate(id, id => + createIndexColumn({ id, indexId, columnId }) + ); + + collection.replaceOperator(lww, timestamp, id, 'orderType', () => { + collection.updateOne(id, indexColumn => { + indexColumn.orderType = value; + }); + }); +}; + +export const indexColumnReducers = { + [ActionType.addIndexColumn]: addIndexColumn, + [ActionType.removeIndexColumn]: removeIndexColumn, + [ActionType.moveIndexColumn]: moveIndexColumn, + [ActionType.changeIndexColumnOrderType]: changeIndexColumnOrderType, +}; + +export const actions = { + addIndexColumnAction, + removeIndexColumnAction, + moveIndexColumnAction, + changeIndexColumnOrderTypeAction, +}; diff --git a/packages/erd-editor/src/engine/modules/index-column/generator.actions.ts b/packages/erd-editor/src/engine/modules/index-column/generator.actions.ts index c00bbcf4..446a032a 100644 --- a/packages/erd-editor/src/engine/modules/index-column/generator.actions.ts +++ b/packages/erd-editor/src/engine/modules/index-column/generator.actions.ts @@ -1 +1,120 @@ -export const actions$ = {}; +import { nanoid } from 'nanoid'; + +import { OrderType } from '@/constants/schema'; +import { GeneratorAction } from '@/engine/generator.actions'; +import { query } from '@/utils/collection/query'; + +import { + addIndexColumnAction, + changeIndexColumnOrderTypeAction, + moveIndexColumnAction, + removeIndexColumnAction, +} from './atom.actions'; + +export const addIndexColumnAction$ = ( + indexId: string, + columnId: string +): GeneratorAction => + function* ({ collections }) { + const index = query(collections) + .collection('indexEntities') + .selectById(indexId); + if (!index) return; + + const prevIndexColumn = query(collections) + .collection('indexColumnEntities') + .selectByIds(index.seqIndexColumnIds) + .find(indexColumn => indexColumn.columnId === columnId); + + if (prevIndexColumn) { + yield addIndexColumnAction({ + id: prevIndexColumn.id, + indexId, + tableId: index.tableId, + columnId, + }); + } else { + yield addIndexColumnAction({ + id: nanoid(), + indexId, + tableId: index.tableId, + columnId, + }); + } + }; + +export const removeIndexColumnAction$ = ( + indexId: string, + columnId: string +): GeneratorAction => + function* ({ collections }) { + const index = query(collections) + .collection('indexEntities') + .selectById(indexId); + if (!index) return; + + const indexColumns = query(collections) + .collection('indexColumnEntities') + .selectByIds(index.indexColumnIds) + .filter(indexColumn => indexColumn.columnId === columnId); + + for (const indexColumn of indexColumns) { + yield removeIndexColumnAction({ + id: indexColumn.id, + indexId, + tableId: index.tableId, + }); + } + }; + +export const changeIndexColumnOrderTypeAction$ = ( + indexColumnId: string +): GeneratorAction => + function* ({ collections }) { + const indexColumn = query(collections) + .collection('indexColumnEntities') + .selectById(indexColumnId); + if (!indexColumn) return; + + yield changeIndexColumnOrderTypeAction({ + id: indexColumnId, + indexId: indexColumn.indexId, + columnId: indexColumn.columnId, + value: + indexColumn.orderType === OrderType.ASC + ? OrderType.DESC + : OrderType.ASC, + }); + }; + +export const moveIndexColumnAction$ = ( + indexColumnId: string, + targetId: string +): GeneratorAction => + function* ({ collections }) { + if (indexColumnId === targetId) return; + + const indexColumn = query(collections) + .collection('indexColumnEntities') + .selectById(indexColumnId); + if (!indexColumn) return; + + const index = query(collections) + .collection('indexEntities') + .selectById(indexColumn.indexId); + if (!index) return; + + yield moveIndexColumnAction({ + id: indexColumnId, + indexId: indexColumn.indexId, + tableId: index.tableId, + targetId, + }); + }; + +export const actions$ = { + addIndexColumnAction$, + removeIndexColumnAction$, + changeIndexColumnOrderTypeAction$, + moveIndexColumnAction$, +}; diff --git a/packages/erd-editor/src/engine/modules/index-column/history.ts b/packages/erd-editor/src/engine/modules/index-column/history.ts index 576d6d28..a3e71fc8 100644 --- a/packages/erd-editor/src/engine/modules/index-column/history.ts +++ b/packages/erd-editor/src/engine/modules/index-column/history.ts @@ -1 +1,99 @@ -export const actions = {}; +import { PushUndoHistory } from '@/engine/history.actions'; +import { query } from '@/utils/collection/query'; + +import { ActionType } from './actions'; +import { + addIndexColumnAction, + changeIndexColumnOrderTypeAction, + moveIndexColumnAction, + removeIndexColumnAction, +} from './atom.actions'; + +const addIndexColumn: PushUndoHistory = ( + undoActions, + { payload: { id, indexId, tableId } }: ReturnType +) => { + undoActions.push(removeIndexColumnAction({ id, indexId, tableId })); +}; + +const removeIndexColumn: PushUndoHistory = ( + undoActions, + { + payload: { id, indexId, tableId }, + }: ReturnType, + { collections } +) => { + const indexColumn = query(collections) + .collection('indexColumnEntities') + .selectById(id); + if (!indexColumn) return; + + undoActions.push( + addIndexColumnAction({ + id, + indexId, + tableId, + columnId: indexColumn.columnId, + }) + ); +}; + +const moveIndexColumn: PushUndoHistory = ( + undoActions, + { + payload: { id, indexId, tableId, targetId }, + }: ReturnType, + { collections } +) => { + const index = query(collections) + .collection('indexEntities') + .selectById(indexId); + if (!index) return; + + const i = index.indexColumnIds.indexOf(id); + if (i === -1) return; + + const targetIndex = index.indexColumnIds.indexOf(targetId); + if (targetIndex === -1) return; + + const revertIndex = i < targetIndex ? i + 1 : i - 1; + const newTargetId = index.indexColumnIds[revertIndex]; + + undoActions.push( + moveIndexColumnAction({ + indexId, + tableId, + id, + targetId: newTargetId, + }) + ); +}; + +const changeIndexColumnOrderType: PushUndoHistory = ( + undoActions, + { + payload: { id, indexId, columnId }, + }: ReturnType, + { collections } +) => { + const indexColumn = query(collections) + .collection('indexColumnEntities') + .selectById(id); + if (!indexColumn) return; + + undoActions.push( + changeIndexColumnOrderTypeAction({ + id, + indexId, + columnId, + value: indexColumn.orderType, + }) + ); +}; + +export const indexColumnPushUndoHistoryMap = { + [ActionType.addIndexColumn]: addIndexColumn, + [ActionType.removeIndexColumn]: removeIndexColumn, + [ActionType.moveIndexColumn]: moveIndexColumn, + [ActionType.changeIndexColumnOrderType]: changeIndexColumnOrderType, +}; diff --git a/packages/erd-editor/src/engine/modules/index/actions.ts b/packages/erd-editor/src/engine/modules/index/actions.ts new file mode 100644 index 00000000..caea5934 --- /dev/null +++ b/packages/erd-editor/src/engine/modules/index/actions.ts @@ -0,0 +1,40 @@ +import { Reducer } from '@dineug/r-html'; + +import { EngineContext } from '@/engine/context'; +import { RootState } from '@/engine/state'; +import { ValuesType } from '@/internal-types'; + +export const ActionType = { + addIndex: 'index.add', + removeIndex: 'index.remove', + changeIndexName: 'index.changeName', + changeIndexUnique: 'index.changeUnique', +} as const; +export type ActionType = ValuesType; + +export type ActionMap = { + [ActionType.addIndex]: { + id: string; + tableId: string; + }; + [ActionType.removeIndex]: { + id: string; + }; + [ActionType.changeIndexName]: { + id: string; + tableId: string; + value: string; + }; + [ActionType.changeIndexUnique]: { + id: string; + tableId: string; + value: boolean; + }; +}; + +export type ReducerType = Reducer< + RootState, + T, + ActionMap, + EngineContext +>; diff --git a/packages/erd-editor/src/engine/modules/index/atom.actions.ts b/packages/erd-editor/src/engine/modules/index/atom.actions.ts index 576d6d28..b3ff7739 100644 --- a/packages/erd-editor/src/engine/modules/index/atom.actions.ts +++ b/packages/erd-editor/src/engine/modules/index/atom.actions.ts @@ -1 +1,93 @@ -export const actions = {}; +import { createAction } from '@dineug/r-html'; +import { arrayHas } from '@dineug/shared'; + +import { createIndex } from '@/utils/collection/index.entity'; +import { query } from '@/utils/collection/query'; + +import { ActionMap, ActionType, ReducerType } from './actions'; + +export const addIndexAction = createAction< + ActionMap[typeof ActionType.addIndex] +>(ActionType.addIndex); + +const addIndex: ReducerType = ( + { doc, collections, lww }, + { payload: { id, tableId }, timestamp } +) => { + query(collections) + .collection('indexEntities') + .addOne(createIndex({ id, tableId })) + .addOperator(lww, timestamp, id, () => { + if (!arrayHas(doc.indexIds)(id)) { + doc.indexIds.push(id); + } + }); +}; + +export const removeIndexAction = createAction< + ActionMap[typeof ActionType.removeIndex] +>(ActionType.removeIndex); + +const removeIndex: ReducerType = ( + { doc, collections, lww }, + { payload: { id }, timestamp } +) => { + query(collections) + .collection('indexEntities') + .removeOperator(lww, timestamp, id, () => { + const index = doc.indexIds.indexOf(id); + if (index !== -1) { + doc.indexIds.splice(index, 1); + } + }); +}; + +export const changeIndexNameAction = createAction< + ActionMap[typeof ActionType.changeIndexName] +>(ActionType.changeIndexName); + +const changeIndexName: ReducerType = ( + { collections, lww }, + { payload: { id, tableId, value }, timestamp } +) => { + const collection = query(collections).collection('indexEntities'); + collection.getOrCreate(id, id => createIndex({ id, tableId })); + + collection.replaceOperator(lww, timestamp, id, 'name', () => { + collection.updateOne(id, index => { + index.name = value; + }); + }); +}; + +export const changeIndexUniqueAction = createAction< + ActionMap[typeof ActionType.changeIndexUnique] +>(ActionType.changeIndexUnique); + +const changeIndexUnique: ReducerType = ( + { collections, lww }, + { payload: { id, tableId, value }, timestamp } +) => { + const collection = query(collections).collection('indexEntities'); + collection.getOrCreate(id, id => createIndex({ id, tableId })); + + collection.replaceOperator(lww, timestamp, id, 'unique', () => { + collection.updateOne(id, index => { + index.unique = value; + }); + }); +}; + +export const indexReducers = { + [ActionType.addIndex]: addIndex, + [ActionType.removeIndex]: removeIndex, + [ActionType.changeIndexName]: changeIndexName, + [ActionType.changeIndexUnique]: changeIndexUnique, +}; + +export const actions = { + addIndexAction, + removeIndexAction, + changeIndexNameAction, + changeIndexUniqueAction, +}; diff --git a/packages/erd-editor/src/engine/modules/index/generator.actions.ts b/packages/erd-editor/src/engine/modules/index/generator.actions.ts index c00bbcf4..9967a79a 100644 --- a/packages/erd-editor/src/engine/modules/index/generator.actions.ts +++ b/packages/erd-editor/src/engine/modules/index/generator.actions.ts @@ -1 +1,33 @@ -export const actions$ = {}; +import { nanoid } from 'nanoid'; + +import { GeneratorAction } from '@/engine/generator.actions'; +import { query } from '@/utils/collection/query'; + +import { addIndexAction, changeIndexUniqueAction } from './atom.actions'; + +export const addIndexAction$ = (tableId: string): GeneratorAction => + function* () { + yield addIndexAction({ + id: nanoid(), + tableId, + }); + }; + +export const changeIndexUniqueAction$ = (indexId: string): GeneratorAction => + function* ({ collections }) { + const index = query(collections) + .collection('indexEntities') + .selectById(indexId); + if (!index) return; + + yield changeIndexUniqueAction({ + id: indexId, + tableId: index.tableId, + value: !index.unique, + }); + }; + +export const actions$ = { + addIndexAction$, + changeIndexUniqueAction$, +}; diff --git a/packages/erd-editor/src/engine/modules/index/history.ts b/packages/erd-editor/src/engine/modules/index/history.ts index 576d6d28..27cbeab0 100644 --- a/packages/erd-editor/src/engine/modules/index/history.ts +++ b/packages/erd-editor/src/engine/modules/index/history.ts @@ -1 +1,76 @@ -export const actions = {}; +import { PushUndoHistory } from '@/engine/history.actions'; +import { query } from '@/utils/collection/query'; + +import { ActionType } from './actions'; +import { + addIndexAction, + changeIndexNameAction, + changeIndexUniqueAction, + removeIndexAction, +} from './atom.actions'; + +const addIndex: PushUndoHistory = ( + undoActions, + { payload: { id } }: ReturnType +) => { + undoActions.push(removeIndexAction({ id })); +}; + +const removeIndex: PushUndoHistory = ( + undoActions, + { payload: { id } }: ReturnType, + { collections } +) => { + const index = query(collections).collection('indexEntities').selectById(id); + if (!index) return; + + undoActions.push( + addIndexAction({ + id, + tableId: index.tableId, + }) + ); +}; + +const changeIndexName: PushUndoHistory = ( + undoActions, + { payload: { id, tableId } }: ReturnType, + { collections } +) => { + const index = query(collections).collection('indexEntities').selectById(id); + if (!index) return; + + undoActions.push( + changeIndexNameAction({ + id, + tableId, + value: index.name, + }) + ); +}; + +const changeIndexUnique: PushUndoHistory = ( + undoActions, + { + payload: { id, tableId, value }, + }: ReturnType, + { collections } +) => { + const index = query(collections).collection('indexEntities').selectById(id); + if (!index) return; + + undoActions.push( + changeIndexUniqueAction({ + id, + tableId, + value: !value, + }) + ); +}; + +export const indexPushUndoHistoryMap = { + [ActionType.addIndex]: addIndex, + [ActionType.removeIndex]: removeIndex, + [ActionType.changeIndexName]: changeIndexName, + [ActionType.changeIndexUnique]: changeIndexUnique, +}; diff --git a/packages/erd-editor/src/engine/modules/memo/atom.actions.ts b/packages/erd-editor/src/engine/modules/memo/atom.actions.ts index 68fa4e19..518d5e2b 100644 --- a/packages/erd-editor/src/engine/modules/memo/atom.actions.ts +++ b/packages/erd-editor/src/engine/modules/memo/atom.actions.ts @@ -15,11 +15,9 @@ const addMemo: ReducerType = ( { doc, collections, lww }, { payload: { id, ui }, timestamp } ) => { - const memo = createMemo({ id, ui }); - query(collections) .collection('memoEntities') - .addOne(memo) + .addOne(createMemo({ id, ui })) .addOperator(lww, timestamp, id, () => { if (!arrayHas(doc.memoIds)(id)) { doc.memoIds.push(id); diff --git a/packages/erd-editor/src/engine/modules/relationship/atom.actions.ts b/packages/erd-editor/src/engine/modules/relationship/atom.actions.ts index 98420622..503678d1 100644 --- a/packages/erd-editor/src/engine/modules/relationship/atom.actions.ts +++ b/packages/erd-editor/src/engine/modules/relationship/atom.actions.ts @@ -14,22 +14,22 @@ const addRelationship: ReducerType = ( { doc, collections, lww }, { payload: { id, relationshipType, start, end }, timestamp } ) => { - const relationship = createRelationship({ - id, - relationshipType, - start: { - tableId: start.tableId, - columnIds: start.columnIds, - }, - end: { - tableId: end.tableId, - columnIds: end.columnIds, - }, - }); - query(collections) .collection('relationshipEntities') - .addOne(relationship) + .addOne( + createRelationship({ + id, + relationshipType, + start: { + tableId: start.tableId, + columnIds: start.columnIds, + }, + end: { + tableId: end.tableId, + columnIds: end.columnIds, + }, + }) + ) .addOperator(lww, timestamp, id, () => { if (!arrayHas(doc.relationshipIds)(id)) { doc.relationshipIds.push(id); diff --git a/packages/erd-editor/src/engine/modules/table-column/atom.actions.ts b/packages/erd-editor/src/engine/modules/table-column/atom.actions.ts index 47a47c5d..492a9e80 100644 --- a/packages/erd-editor/src/engine/modules/table-column/atom.actions.ts +++ b/packages/erd-editor/src/engine/modules/table-column/atom.actions.ts @@ -20,11 +20,10 @@ const addColumn: ReducerType = ( ) => { const tableCollection = query(collections).collection('tableEntities'); const table = tableCollection.getOrCreate(tableId, id => createTable({ id })); - const column = createColumn({ id, tableId }); query(collections) .collection('tableColumnEntities') - .addOne(column) + .addOne(createColumn({ id, tableId })) .addOperator(lww, timestamp, id, () => { if (!arrayHas(table.columnIds)(id)) { tableCollection.updateOne(tableId, table => { diff --git a/packages/erd-editor/src/engine/modules/table-column/generator.actions.ts b/packages/erd-editor/src/engine/modules/table-column/generator.actions.ts index b7369161..89d905ea 100644 --- a/packages/erd-editor/src/engine/modules/table-column/generator.actions.ts +++ b/packages/erd-editor/src/engine/modules/table-column/generator.actions.ts @@ -10,6 +10,7 @@ import { } from '@/engine/modules/editor/atom.actions'; import { FocusType, SelectType } from '@/engine/modules/editor/state'; import { getRemoveFirstColumnId } from '@/engine/modules/editor/utils/focus'; +import { removeIndexAction } from '@/engine/modules/index/atom.actions'; import { removeRelationshipAction } from '@/engine/modules/relationship/atom.actions'; import { bHas } from '@/utils/bit'; import { query } from '@/utils/collection/query'; @@ -86,9 +87,8 @@ export const removeColumnAction$ = ( columnIds: string[] ): GeneratorAction => function* (state) { - // TODO: valid index const { - doc: { relationshipIds }, + doc: { relationshipIds, indexIds }, editor: { focusTable }, collections, } = state; @@ -121,7 +121,22 @@ export const removeColumnAction$ = ( (start.tableId === tableId && start.columnIds.some(hasColumnIds)) || (end.tableId === tableId && end.columnIds.some(hasColumnIds)) ); + const indexes = query(collections) + .collection('indexEntities') + .selectByIds(indexIds) + .filter( + index => + index.tableId === tableId && + query(collections) + .collection('indexColumnEntities') + .selectByIds(index.indexColumnIds) + .map(({ columnId }) => columnId) + .some(hasColumnIds) + ); + for (const { id } of indexes) { + yield removeIndexAction({ id }); + } for (const { id } of relationships) { yield removeRelationshipAction({ id }); } diff --git a/packages/erd-editor/src/engine/modules/table/atom.actions.ts b/packages/erd-editor/src/engine/modules/table/atom.actions.ts index ce911563..8f4b14f2 100644 --- a/packages/erd-editor/src/engine/modules/table/atom.actions.ts +++ b/packages/erd-editor/src/engine/modules/table/atom.actions.ts @@ -16,11 +16,9 @@ const addTable: ReducerType = ( { doc, collections, lww }, { payload: { id, ui }, timestamp } ) => { - const table = createTable({ id, ui }); - query(collections) .collection('tableEntities') - .addOne(table) + .addOne(createTable({ id, ui })) .addOperator(lww, timestamp, id, () => { if (!arrayHas(doc.tableIds)(id)) { doc.tableIds.push(id); diff --git a/packages/erd-editor/src/engine/modules/table/generator.actions.ts b/packages/erd-editor/src/engine/modules/table/generator.actions.ts index c94b5f91..f58f7d36 100644 --- a/packages/erd-editor/src/engine/modules/table/generator.actions.ts +++ b/packages/erd-editor/src/engine/modules/table/generator.actions.ts @@ -11,6 +11,7 @@ import { } from '@/engine/modules/editor/atom.actions'; import { drawStartAddRelationshipAction$ } from '@/engine/modules/editor/generator.actions'; import { SelectType } from '@/engine/modules/editor/state'; +import { removeIndexAction } from '@/engine/modules/index/atom.actions'; import { addRelationshipAction, removeRelationshipAction, @@ -59,19 +60,26 @@ export const addTableAction$ = (): GeneratorAction => export const removeTableAction$ = (id?: string): GeneratorAction => function* ({ - doc: { relationshipIds }, + doc: { relationshipIds, indexIds }, editor: { selectedMap }, collections, }) { - // TODO: valid index const relationships = query(collections) .collection('relationshipEntities') .selectByIds(relationshipIds); + const indexes = query(collections) + .collection('indexEntities') + .selectByIds(indexIds); if (id) { const removeRelationships = relationships.filter( ({ start, end }) => start.tableId === id || end.tableId === id ); + const removeIndexes = indexes.filter(({ tableId }) => tableId === id); + + for (const { id } of removeIndexes) { + yield removeIndexAction({ id }); + } for (const { id } of removeRelationships) { yield removeRelationshipAction({ id }); } @@ -87,7 +95,11 @@ export const removeTableAction$ = (id?: string): GeneratorAction => const removeRelationships = relationships.filter( ({ start, end }) => hasTableIds(start.tableId) || hasTableIds(end.tableId) ); + const removeIndexes = indexes.filter(({ tableId }) => hasTableIds(tableId)); + for (const { id } of removeIndexes) { + yield removeIndexAction({ id }); + } for (const { id } of removeRelationships) { yield removeRelationshipAction({ id }); } diff --git a/packages/erd-editor/src/engine/rx-store.ts b/packages/erd-editor/src/engine/rx-store.ts index 298bbce2..24999d0f 100644 --- a/packages/erd-editor/src/engine/rx-store.ts +++ b/packages/erd-editor/src/engine/rx-store.ts @@ -29,7 +29,7 @@ export type RxStore = Store & { change$: Observable>; }; -const HISTORY_LIMIT = 2000; +const HISTORY_LIMIT = 2048; export function createRxStore(context: EngineContext): RxStore { const subscriptions: Subscription[] = []; diff --git a/packages/erd-editor/src/engine/store.ts b/packages/erd-editor/src/engine/store.ts index 75f9bacd..63cd8533 100644 --- a/packages/erd-editor/src/engine/store.ts +++ b/packages/erd-editor/src/engine/store.ts @@ -5,6 +5,8 @@ import { RootActionMap } from '@/engine/actions'; import { EngineContext } from '@/engine/context'; import { editorReducers } from '@/engine/modules/editor/atom.actions'; import { createEditor } from '@/engine/modules/editor/state'; +import { indexReducers } from '@/engine/modules/index/atom.actions'; +import { indexColumnReducers } from '@/engine/modules/index-column/atom.actions'; import { memoReducers } from '@/engine/modules/memo/atom.actions'; import { relationshipReducers } from '@/engine/modules/relationship/atom.actions'; import { settingsReducers } from '@/engine/modules/settings/atom.actions'; @@ -28,6 +30,8 @@ export function createStore(context: EngineContext): Store { ...memoReducers, ...relationshipReducers, ...settingsReducers, + ...indexReducers, + ...indexColumnReducers, }, }); } diff --git a/packages/erd-editor/src/utils/collection/sequence.ts b/packages/erd-editor/src/utils/collection/sequence.ts index 96c160e9..c0183c9b 100644 --- a/packages/erd-editor/src/utils/collection/sequence.ts +++ b/packages/erd-editor/src/utils/collection/sequence.ts @@ -4,8 +4,25 @@ export function addAndSort(ids: string[], seqIds: string[], id: string) { const hasSeqId = arrayHas(seqIds); if (hasSeqId(id)) { + const idIndices = seqIds.reduce( + (acc: Record, cur, index) => { + acc[cur] = index; + return acc; + }, + {} + ); + ids.push(id); - ids.sort((a, b) => seqIds.indexOf(a) - seqIds.indexOf(b)); + ids.sort((a, b) => { + const indexA = idIndices[a]; + const indexB = idIndices[b]; + + return indexA === undefined + ? 1 + : indexB === undefined + ? -1 + : indexA - indexB; + }); } else { ids.push(id); seqIds.push(id); diff --git a/packages/erd-editor/src/utils/schema-sql/MSSQL.ts b/packages/erd-editor/src/utils/schema-sql/MSSQL.ts index 31e29f7d..257ceaae 100644 --- a/packages/erd-editor/src/utils/schema-sql/MSSQL.ts +++ b/packages/erd-editor/src/utils/schema-sql/MSSQL.ts @@ -21,6 +21,7 @@ import { orderByNameASC, primaryKey, primaryKeyColumns, + toOrderName, unique, uniqueColumns, } from './utils'; @@ -257,10 +258,12 @@ export function formatIndex( .map(indexColumn => { const column = query(collections) .collection('tableColumnEntities') - .selectById(indexColumn.id); + .selectById(indexColumn.columnId); if (column) { return { - name: `${bracket}${column.name}${bracket} ${indexColumn.orderType}`, + name: `${bracket}${column.name}${bracket} ${toOrderName( + indexColumn.orderType + )}`, }; } return null; diff --git a/packages/erd-editor/src/utils/schema-sql/MariaDB.ts b/packages/erd-editor/src/utils/schema-sql/MariaDB.ts index bcaeac41..aacbdb62 100644 --- a/packages/erd-editor/src/utils/schema-sql/MariaDB.ts +++ b/packages/erd-editor/src/utils/schema-sql/MariaDB.ts @@ -20,6 +20,7 @@ import { orderByNameASC, primaryKey, primaryKeyColumns, + toOrderName, unique, uniqueColumns, } from './utils'; @@ -234,10 +235,12 @@ export function formatIndex( .map(indexColumn => { const column = query(collections) .collection('tableColumnEntities') - .selectById(indexColumn.id); + .selectById(indexColumn.columnId); if (column) { return { - name: `${bracket}${column.name}${bracket} ${indexColumn.orderType}`, + name: `${bracket}${column.name}${bracket} ${toOrderName( + indexColumn.orderType + )}`, }; } return null; diff --git a/packages/erd-editor/src/utils/schema-sql/MySQL.ts b/packages/erd-editor/src/utils/schema-sql/MySQL.ts index 466c05fe..c609aecc 100644 --- a/packages/erd-editor/src/utils/schema-sql/MySQL.ts +++ b/packages/erd-editor/src/utils/schema-sql/MySQL.ts @@ -20,6 +20,7 @@ import { orderByNameASC, primaryKey, primaryKeyColumns, + toOrderName, unique, uniqueColumns, } from './utils'; @@ -234,10 +235,12 @@ export function formatIndex( .map(indexColumn => { const column = query(collections) .collection('tableColumnEntities') - .selectById(indexColumn.id); + .selectById(indexColumn.columnId); if (column) { return { - name: `${bracket}${column.name}${bracket} ${indexColumn.orderType}`, + name: `${bracket}${column.name}${bracket} ${toOrderName( + indexColumn.orderType + )}`, }; } return null; diff --git a/packages/erd-editor/src/utils/schema-sql/Oracle.ts b/packages/erd-editor/src/utils/schema-sql/Oracle.ts index 10a459c1..1a12d654 100644 --- a/packages/erd-editor/src/utils/schema-sql/Oracle.ts +++ b/packages/erd-editor/src/utils/schema-sql/Oracle.ts @@ -21,6 +21,7 @@ import { orderByNameASC, primaryKey, primaryKeyColumns, + toOrderName, unique, uniqueColumns, } from './utils'; @@ -288,10 +289,12 @@ export function formatIndex( .map(indexColumn => { const column = query(collections) .collection('tableColumnEntities') - .selectById(indexColumn.id); + .selectById(indexColumn.columnId); if (column) { return { - name: `${bracket}${column.name}${bracket} ${indexColumn.orderType}`, + name: `${bracket}${column.name}${bracket} ${toOrderName( + indexColumn.orderType + )}`, }; } return null; diff --git a/packages/erd-editor/src/utils/schema-sql/PostgreSQL.ts b/packages/erd-editor/src/utils/schema-sql/PostgreSQL.ts index 0c258f36..bc5adcad 100644 --- a/packages/erd-editor/src/utils/schema-sql/PostgreSQL.ts +++ b/packages/erd-editor/src/utils/schema-sql/PostgreSQL.ts @@ -21,6 +21,7 @@ import { orderByNameASC, primaryKey, primaryKeyColumns, + toOrderName, } from './utils'; export function createSchema(state: RootState): string { @@ -234,10 +235,12 @@ export function formatIndex( .map(indexColumn => { const column = query(collections) .collection('tableColumnEntities') - .selectById(indexColumn.id); + .selectById(indexColumn.columnId); if (column) { return { - name: `${bracket}${column.name}${bracket} ${indexColumn.orderType}`, + name: `${bracket}${column.name}${bracket} ${toOrderName( + indexColumn.orderType + )}`, }; } return null; diff --git a/packages/erd-editor/src/utils/schema-sql/SQLite.ts b/packages/erd-editor/src/utils/schema-sql/SQLite.ts index 3ff4509b..92c90dde 100644 --- a/packages/erd-editor/src/utils/schema-sql/SQLite.ts +++ b/packages/erd-editor/src/utils/schema-sql/SQLite.ts @@ -19,6 +19,7 @@ import { orderByNameASC, primaryKey, primaryKeyColumns, + toOrderName, } from './utils'; export function createSchema(state: RootState): string { @@ -230,10 +231,12 @@ export function formatIndex( .map(indexColumn => { const column = query(collections) .collection('tableColumnEntities') - .selectById(indexColumn.id); + .selectById(indexColumn.columnId); if (column) { return { - name: `${bracket}${column.name}${bracket} ${indexColumn.orderType}`, + name: `${bracket}${column.name}${bracket} ${toOrderName( + indexColumn.orderType + )}`, }; } return null; diff --git a/packages/erd-editor/src/utils/schema-sql/index.ts b/packages/erd-editor/src/utils/schema-sql/index.ts index 42d9ac43..d1183134 100644 --- a/packages/erd-editor/src/utils/schema-sql/index.ts +++ b/packages/erd-editor/src/utils/schema-sql/index.ts @@ -66,7 +66,8 @@ export function createSchemaSQLTable(state: RootState, table: Table) { const indexNames: Name[] = []; const indexes = query(collections) .collection('indexEntities') - .selectByIds(indexIds); + .selectByIds(indexIds) + .filter(index => index.tableId === table.id); switch (database) { case Database.MariaDB: diff --git a/packages/erd-editor/src/utils/schema-sql/utils.ts b/packages/erd-editor/src/utils/schema-sql/utils.ts index ed4a2ba6..c94a32e5 100644 --- a/packages/erd-editor/src/utils/schema-sql/utils.ts +++ b/packages/erd-editor/src/utils/schema-sql/utils.ts @@ -1,4 +1,4 @@ -import { BracketTypeMap, ColumnOption } from '@/constants/schema'; +import { BracketTypeMap, ColumnOption, OrderType } from '@/constants/schema'; import { Column, Index, Relationship, Table } from '@/internal-types'; import { bHas } from '@/utils/bit'; @@ -145,3 +145,14 @@ export function autoName( } return autoName(list, id, name.replace(/[0-9]/g, '') + num, num + 1); } + +export function toOrderName(orderType: number) { + switch (orderType) { + case OrderType.ASC: + return 'ASC'; + case OrderType.DESC: + return 'DESC'; + default: + return ''; + } +} diff --git a/packages/r-html/src/render/directives/node/repeat.ts b/packages/r-html/src/render/directives/node/repeat.ts index 5bafaea0..81386295 100644 --- a/packages/r-html/src/render/directives/node/repeat.ts +++ b/packages/r-html/src/render/directives/node/repeat.ts @@ -43,7 +43,9 @@ export const repeat = createNodeDirective( return ([list, getKey, getResult]) => { const newDiffValue = valuesToDiffItems(list, getKey, getResult); const values = newDiffValue.values; - const diff = difference(partsToDiffItems(parts), newDiffValue); + const diff = difference(partsToDiffItems(parts), newDiffValue, { + strict: true, + }); const arrayLike: any = { length: values.length }; diff.update.forEach(({ action, from, to }) => { diff --git a/packages/r-html/src/render/part/node/text/arrayDiff.ts b/packages/r-html/src/render/part/node/text/arrayDiff.ts index b0198ab0..b0ef2149 100644 --- a/packages/r-html/src/render/part/node/text/arrayDiff.ts +++ b/packages/r-html/src/render/part/node/text/arrayDiff.ts @@ -67,7 +67,16 @@ export function valuesToDiffItems(values: any[]): DiffValue { }; } -export function difference(oldDiffValue: DiffValue, newDiffValue: DiffValue) { +type DifferenceOptions = { + strict?: boolean; +}; + +export function difference( + oldDiffValue: DiffValue, + newDiffValue: DiffValue, + options?: DifferenceOptions +) { + const strict = Boolean(options?.strict); const diff: Diff = { update: [], delete: [], @@ -87,7 +96,11 @@ export function difference(oldDiffValue: DiffValue, newDiffValue: DiffValue) { ); if (to === -1) { - updateOldItems.push(oldItem); + if (strict) { + diff.delete.push({ from }); + } else { + updateOldItems.push(oldItem); + } } else { move.add(to); diff.update.push({ action: Action.move, from, to });