This commit is contained in:
Guy Ben-Aharon
2024-08-19 13:31:55 +03:00
parent fb805d2938
commit fbf6015efa
6 changed files with 308 additions and 111 deletions

View File

@@ -1,7 +1,7 @@
import React from 'react';
import React, { useCallback } from 'react';
import { DBTable } from '@/lib/domain/db-table';
import { generateId, randomHSLA } from '@/lib/utils';
import { chartDBContext } from './chartdb-context';
import { ChartDBContext, chartDBContext } from './chartdb-context';
import { DatabaseType } from '@/lib/domain/database-type';
import { DBField } from '@/lib/domain/db-field';
import { DBIndex } from '@/lib/domain/db-index';
@@ -12,7 +12,7 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const [diagramId, setDiagramId] = React.useState('');
const { getDiagram } = useData();
const db = useData();
const [diagramName, setDiagramName] = React.useState('New Diagram');
const [databaseType, setDatabaseType] = React.useState<DatabaseType>(
DatabaseType.GENERIC
@@ -22,15 +22,35 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
[]
);
const updateDatabaseType = setDatabaseType;
const updateDiagramId = setDiagramId;
const updateDiagramName = setDiagramName;
const addTable = (table: DBTable) => {
setTables((tables) => [...tables, table]);
const updateDatabaseType: ChartDBContext['updateDatabaseType'] = async (
databaseType
) => {
setDatabaseType(databaseType);
await db.updateDiagram({
id: diagramId,
attributes: {
databaseType,
},
});
};
const updateDiagramId: ChartDBContext['updateDiagramId'] = async (id) => {
const prevId = diagramId;
setDiagramId(id);
await db.updateDiagram({ id: prevId, attributes: { id } });
};
const updateDiagramName: ChartDBContext['updateDiagramName'] = async (
name
) => {
setDiagramName(name);
await db.updateDiagram({ id: diagramId, attributes: { name } });
};
const createTable = () => {
const addTable: ChartDBContext['addTable'] = (table: DBTable) => {
setTables((tables) => [...tables, table]);
return db.addTable({ diagramId, table });
};
const createTable: ChartDBContext['createTable'] = async () => {
const table: DBTable = {
id: generateId(),
name: `table_${tables.length + 1}`,
@@ -51,36 +71,51 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
color: randomHSLA(),
createdAt: Date.now(),
};
addTable(table);
await addTable(table);
return table;
};
const getTable = (id: string) =>
const getTable: ChartDBContext['getTable'] = (id: string) =>
tables.find((table) => table.id === id) ?? null;
const removeTable = (id: string) => {
const removeTable: ChartDBContext['removeTable'] = async (id: string) => {
setTables((tables) => tables.filter((table) => table.id !== id));
await db.deleteTable({ diagramId, id });
};
const updateTable = (id: string, table: Partial<DBTable>) => {
const updateTable: ChartDBContext['updateTable'] = async (
id: string,
table: Partial<DBTable>
) => {
setTables((tables) =>
tables.map((t) => (t.id === id ? { ...t, ...table } : t))
);
await db.updateTable({ id, attributes: table });
};
const updateTables = (tables: PartialExcept<DBTable, 'id'>[]) => {
const updateTables: ChartDBContext['updateTables'] = async (
tables: PartialExcept<DBTable, 'id'>[]
) => {
setTables((currentTables) =>
currentTables.map((table) => {
const updatedTable = tables.find((t) => t.id === table.id);
return updatedTable ? { ...table, ...updatedTable } : table;
})
);
const promises = [];
for (const table of tables) {
promises.push(db.updateTable({ id: table.id, attributes: table }));
}
await Promise.all(promises);
};
const updateTablesState = (
const updateTablesState: ChartDBContext['updateTablesState'] = async (
updateFn: (tables: DBTable[]) => PartialExcept<DBTable, 'id'>[]
) => {
const updatedTables = updateFn(tables);
setTables((prevTables) => {
const updatedTables = updateFn(prevTables);
return prevTables
@@ -96,9 +131,29 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
updatedTables.some((t) => t.id === prevTable.id)
);
});
const promises = [];
for (const updatedTable of updatedTables) {
promises.push(
db.updateTable({
id: updatedTable.id,
attributes: updatedTable,
})
);
}
const tablesToDelete = tables.filter(
(table) => !updatedTables.some((t) => t.id === table.id)
);
for (const table of tablesToDelete) {
promises.push(db.deleteTable({ diagramId, id: table.id }));
}
await Promise.all(promises);
};
const updateField = (
const updateField: ChartDBContext['updateField'] = async (
tableId: string,
fieldId: string,
field: Partial<DBField>
@@ -115,9 +170,27 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
: table
)
);
const table = await db.getTable({ diagramId, id: tableId });
if (!table) {
return;
}
await db.updateTable({
id: tableId,
attributes: {
...table,
fields: table.fields.map((f) =>
f.id === fieldId ? { ...f, ...field } : f
),
},
});
};
const removeField = (tableId: string, fieldId: string) => {
const removeField: ChartDBContext['removeField'] = async (
tableId: string,
fieldId: string
) => {
setTables((tables) =>
tables.map((table) =>
table.id === tableId
@@ -128,9 +201,25 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
: table
)
);
const table = await db.getTable({ diagramId, id: tableId });
if (!table) {
return;
}
await db.updateTable({
id: tableId,
attributes: {
...table,
fields: table.fields.filter((f) => f.id !== fieldId),
},
});
};
const addField = (tableId: string, field: DBField) => {
const addField: ChartDBContext['addField'] = async (
tableId: string,
field: DBField
) => {
setTables((tables) =>
tables.map((table) =>
table.id === tableId
@@ -138,14 +227,33 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
: table
)
);
const table = await db.getTable({ diagramId, id: tableId });
if (!table) {
return;
}
await db.updateTable({
id: tableId,
attributes: {
...table,
fields: [...table.fields, field],
},
});
};
const getField = (tableId: string, fieldId: string) => {
const getField: ChartDBContext['getField'] = (
tableId: string,
fieldId: string
) => {
const table = getTable(tableId);
return table?.fields.find((f) => f.id === fieldId) ?? null;
};
const createField = (tableId: string) => {
const createField: ChartDBContext['createField'] = async (
tableId: string
) => {
const table = getTable(tableId);
const field: DBField = {
id: generateId(),
@@ -157,12 +265,15 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
createdAt: Date.now(),
};
addField(tableId, field);
await addField(tableId, field);
return field;
};
const addIndex = (tableId: string, index: DBIndex) => {
const addIndex: ChartDBContext['addIndex'] = async (
tableId: string,
index: DBIndex
) => {
setTables((tables) =>
tables.map((table) =>
table.id === tableId
@@ -170,9 +281,25 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
: table
)
);
const dbTable = await db.getTable({ diagramId, id: tableId });
if (!dbTable) {
return;
}
await db.updateTable({
id: tableId,
attributes: {
...dbTable,
indexes: [...dbTable.indexes, index],
},
});
};
const removeIndex = (tableId: string, indexId: string) => {
const removeIndex: ChartDBContext['removeIndex'] = async (
tableId: string,
indexId: string
) => {
setTables((tables) =>
tables.map((table) =>
table.id === tableId
@@ -185,9 +312,28 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
: table
)
);
const dbTable = await db.getTable({
diagramId,
id: tableId,
});
if (!dbTable) {
return;
}
await db.updateTable({
id: tableId,
attributes: {
...dbTable,
indexes: dbTable.indexes.filter((i) => i.id !== indexId),
},
});
};
const createIndex = (tableId: string) => {
const createIndex: ChartDBContext['createIndex'] = async (
tableId: string
) => {
const table = getTable(tableId);
const index: DBIndex = {
id: generateId(),
@@ -197,17 +343,20 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
createdAt: Date.now(),
};
addIndex(tableId, index);
await addIndex(tableId, index);
return index;
};
const getIndex = (tableId: string, indexId: string) => {
const getIndex: ChartDBContext['getIndex'] = (
tableId: string,
indexId: string
) => {
const table = getTable(tableId);
return table?.indexes.find((i) => i.id === indexId) ?? null;
};
const updateIndex = (
const updateIndex: ChartDBContext['updateIndex'] = async (
tableId: string,
indexId: string,
index: Partial<DBIndex>
@@ -224,22 +373,37 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
: table
)
);
const dbTable = await db.getTable({ diagramId, id: tableId });
if (!dbTable) {
return;
}
await db.updateTable({
id: tableId,
attributes: {
...dbTable,
indexes: dbTable.indexes.map((i) =>
i.id === indexId ? { ...i, ...index } : i
),
},
});
};
const addRelationship = (relationship: DBRelationship) => {
const addRelationship: ChartDBContext['addRelationship'] = async (
relationship: DBRelationship
) => {
setRelationships((relationships) => [...relationships, relationship]);
await db.addRelationship({ diagramId, relationship });
};
const createRelationship = ({
const createRelationship: ChartDBContext['createRelationship'] = async ({
sourceTableId,
targetTableId,
sourceFieldId,
targetFieldId,
}: {
sourceTableId: string;
targetTableId: string;
sourceFieldId: string;
targetFieldId: string;
}) => {
const sourceTableName = getTable(sourceTableId)?.name ?? '';
const targetTableName = getTable(targetTableId)?.name ?? '';
@@ -254,29 +418,39 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
createdAt: Date.now(),
};
addRelationship(relationship);
await addRelationship(relationship);
return relationship;
};
const getRelationship = (id: string) =>
const getRelationship: ChartDBContext['getRelationship'] = (id: string) =>
relationships.find((relationship) => relationship.id === id) ?? null;
const removeRelationship = (id: string) => {
const removeRelationship: ChartDBContext['removeRelationship'] = async (
id: string
) => {
setRelationships((relationships) =>
relationships.filter((relationship) => relationship.id !== id)
);
await db.deleteRelationship({ diagramId, id });
};
const removeRelationships = (...ids: string[]) => {
const removeRelationships: ChartDBContext['removeRelationships'] = async (
...ids: string[]
) => {
setRelationships((relationships) =>
relationships.filter(
(relationship) => !ids.includes(relationship.id)
)
);
await Promise.all(
ids.map((id) => db.deleteRelationship({ diagramId, id }))
);
};
const updateRelationship = (
const updateRelationship: ChartDBContext['updateRelationship'] = async (
id: string,
relationship: Partial<DBRelationship>
) => {
@@ -285,24 +459,36 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
r.id === id ? { ...r, ...relationship } : r
)
);
await db.updateRelationship({ id, attributes: relationship });
};
const loadDiagram = async (diagramId: string) => {
const diagram = await getDiagram(diagramId, {
includeRelationships: true,
includeTables: true,
});
const loadDiagram: ChartDBContext['loadDiagram'] = useCallback(
async (diagramId: string) => {
const diagram = await db.getDiagram(diagramId, {
includeRelationships: true,
includeTables: true,
});
if (diagram) {
setDiagramId(diagram.id);
setDiagramName(diagram.name);
setDatabaseType(diagram.databaseType);
setTables(diagram.tables);
setRelationships(diagram.relationships);
}
if (diagram) {
setDiagramId(diagram.id);
setDiagramName(diagram.name);
setDatabaseType(diagram.databaseType);
setTables(diagram.tables);
setRelationships(diagram.relationships);
}
return diagram;
};
return diagram;
},
[
db,
setDiagramId,
setDiagramName,
setDatabaseType,
setTables,
setRelationships,
]
);
return (
<chartDBContext.Provider