diff --git a/src/i18/languages/en.ts b/src/i18/languages/en.ts index a3f6187..75fa55f 100644 --- a/src/i18/languages/en.ts +++ b/src/i18/languages/en.ts @@ -20,8 +20,8 @@ export const en = { add_table: "Add Table", add_field: "Add Field", add_index: "Add Index", - delete_table : "Delete Table" , - duplicate : "Duplicate" , + delete_table: "Delete Table", + duplicate: "Duplicate", add_relationship: "Add Relationship", show_code: "Show code", fields: "Fields", @@ -57,25 +57,29 @@ export const en = { }, delete: "Delete", field_setting: "Field Setting", + index_setting: "Index Setting", table_actions: "Table Actions", actions: "Actions", field_note: "Field note", delete_field: "Delete Field", + delete_index: "Delete Index", + index_name: "Index name", + create_relationship: "Create Relationship", relationship_error: "To create a relationship, the primary key and foreign key must be of the same type.", - + invalid_relationship: { title: "Invalid Relationship", description: "The source key type does not match the referenced key type. Please ensure both keys have the same data type." } }, table: { - double_click: "Double click to edit" , - overlapping_tables : "Overlapping Tables" , - show_more : "Show more" , - show_less : "Show less" + double_click: "Double click to edit", + overlapping_tables: "Overlapping Tables", + show_more: "Show more", + show_less: "Show less" }, control_buttons: { redo: "Redo", diff --git a/src/lib/schemas/field_index-schema.ts b/src/lib/schemas/field_index-schema.ts index 39fbdba..195a613 100644 --- a/src/lib/schemas/field_index-schema.ts +++ b/src/lib/schemas/field_index-schema.ts @@ -1,14 +1,15 @@ - - -import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; - +import { sqliteTable, text, primaryKey } from 'drizzle-orm/sqlite-core'; import { indices } from './index-schema'; import { fields } from './field-schema'; import { InferInsertModel, InferSelectModel, relations } from 'drizzle-orm'; export const field_indices = sqliteTable("field_indices", { - fieldId: text("fieldId").references(() => fields.id, { onDelete: "cascade" }), - indexId: text("indexId").references(() => indices.id, { onDelete: "cascade" }), + id: text('id') + .primaryKey() + .notNull() + .unique(), + fieldId: text("fieldId").notNull().references(() => fields.id, { onDelete: "cascade" }), + indexId: text("indexId").notNull().references(() => indices.id, { onDelete: "cascade" }), }); @@ -25,7 +26,7 @@ export const fieldIndicesRelationships = relations(field_indices, ({ one }) => ( })) -export interface FieldIndexType extends InferSelectModel {}; +export interface FieldIndexType extends InferSelectModel { }; export interface FieldIndexInsertType extends InferInsertModel { }; \ No newline at end of file diff --git a/src/lib/schemas/index-schema.ts b/src/lib/schemas/index-schema.ts index 6ce479e..eee4b81 100644 --- a/src/lib/schemas/index-schema.ts +++ b/src/lib/schemas/index-schema.ts @@ -1,11 +1,9 @@ -import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'; +import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'; import { tables } from './table-schema'; -import { data_types, DataType } from './data-type-schema'; import { InferInsertModel, InferSelectModel, relations } from 'drizzle-orm'; -import { relationships } from './relationship-schema'; -import { field_indices, FieldIndexType } from './field_index-schema'; +import { field_indices, FieldIndexInsertType, FieldIndexType } from './field_index-schema'; import { fields } from './field-schema'; @@ -19,22 +17,23 @@ export const indices = sqliteTable("indices", { name: text("name").notNull(), unique: integer("unique", { mode: "boolean" }), createdAt: text('createdAt'), + }); -export const indicesRlationships = relations(indices, ({ one , many}) => ({ - table : one(tables , { - references : [tables.id] , - fields : [indices.tableId] - }) , - fieldIndices : many(field_indices) , - fields : many(fields) +export const indicesRlationships = relations(indices, ({ one, many }) => ({ + table: one(tables, { + references: [tables.id], + fields: [indices.tableId] + }), + fieldIndices: many(field_indices), + fields: many(fields) })) -export interface IndexType extends InferSelectModel { - fieldIndices : FieldIndexType[] +export interface IndexType extends InferSelectModel { + fieldIndices: FieldIndexType[] }; -export interface IndexInsertType extends InferInsertModel { - +export interface IndexInsertType extends InferInsertModel { + fieldIndices? : FieldIndexInsertType[] }; \ No newline at end of file diff --git a/src/pages/database/db-controller/tables-controller/table-accordion-item/index/index-item.tsx b/src/pages/database/db-controller/tables-controller/table-accordion-item/index/index-item.tsx index 5c113b6..7c712ab 100644 --- a/src/pages/database/db-controller/tables-controller/table-accordion-item/index/index-item.tsx +++ b/src/pages/database/db-controller/tables-controller/table-accordion-item/index/index-item.tsx @@ -1,34 +1,69 @@ +import ToggleButton from "@/components/toggle/toggle"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/tooltip/tooltip"; -import { Button, Select, SelectItem } from "@heroui/react"; -import { EllipsisVertical } from "lucide-react"; +import { FieldType } from "@/lib/schemas/field-schema"; +import { FieldIndexType } from "@/lib/schemas/field_index-schema"; +import { IndexInsertType, IndexType } from "@/lib/schemas/index-schema"; +import { useDatabaseOperations } from "@/providers/database-provider/database-provider"; +import { areArraysEqual } from "@/utils/utils"; +import { Button, Input, Popover, PopoverContent, PopoverTrigger, Select, SelectItem, SharedSelection } from "@heroui/react"; +import { EllipsisVertical, Trash2 } from "lucide-react"; +import { Key, useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -export const animals = [ - { key: "cat", label: "Cat" }, - { key: "dog", label: "Dog" }, - { key: "elephant", label: "Elephant" }, - { key: "lion", label: "Lion" }, - { key: "tiger", label: "Tiger" }, - { key: "giraffe", label: "Giraffe" }, - { key: "dolphin", label: "Dolphin" }, - { key: "penguin", label: "Penguin" }, - { key: "zebra", label: "Zebra" }, - { key: "shark", label: "Shark" }, - { key: "whale", label: "Whale" }, - { key: "otter", label: "Otter" }, - { key: "crocodile", label: "Crocodile" }, -]; interface Props { - + index: IndexType; + fields: FieldType[] } -const IndexItem: React.FC = ({ }) => { +const IndexItem: React.FC = ({ index, fields }) => { const { t } = useTranslation(); + const { editIndex, deleteIndex, editFieldIndices } = useDatabaseOperations(); + const [popOverOpen, setPopOverOpen] = useState(false); + const [fieldIndices, setFieldIndices] = useState>(new Set()); + + useEffect(() => { + + setFieldIndices( + new Set( index.fieldIndices.map((fieldIndex : FieldIndexType) => fieldIndex.fieldId)) + ) + } , [index.fieldIndices]) + + const toggleUnique = (unique: boolean) => { + + editIndex({ + id: index.id, + unique + } as IndexInsertType); + } + + const editIndexName = (event: any) => { + editIndex({ + id: index.id, + name: event.target.value + } as IndexInsertType); + + } + const removeIndex = () => { + deleteIndex(index.id) + } + + + const onInexFieldChange = (keys: SharedSelection | Set) => { + setFieldIndices(keys as Set) + } + + + const openChange = useCallback((isOpen: boolean) => { + if (isOpen == false) { + if (!areArraysEqual(Array.from(fieldIndices), index.fieldIndices.map((fieldIndex: FieldIndexType) => fieldIndex.fieldId))) + editFieldIndices(index.id, Array.from(fieldIndices)); + } + }, [fieldIndices]) return (
- - - - - - {t("db_controller.unique")}? - - - + U + + + + + + +
+

+ {t("db_controller.index_setting")} +

+
+ + + + + +
+ + +
+
+
diff --git a/src/pages/database/db-controller/tables-controller/table-accordion-item/index/indexes-list.tsx b/src/pages/database/db-controller/tables-controller/table-accordion-item/index/indexes-list.tsx index 3d6a0a5..5e4b26d 100644 --- a/src/pages/database/db-controller/tables-controller/table-accordion-item/index/indexes-list.tsx +++ b/src/pages/database/db-controller/tables-controller/table-accordion-item/index/indexes-list.tsx @@ -1,21 +1,43 @@ -import { Button, } from "@heroui/react"; +import { Button, } from "@heroui/react"; import IndexItem from "./index-item"; -import { Plus } from "lucide-react"; +import { Plus } from "lucide-react"; import { useTranslation } from "react-i18next"; +import { IndexInsertType, IndexType } from "@/lib/schemas/index-schema"; +import hash from "object-hash"; +import React from "react"; +import { FieldType } from "@/lib/schemas/field-schema"; +import { useDatabaseOperations } from "@/providers/database-provider/database-provider"; +import { v4 } from "uuid"; -interface Props { +interface IndexesListProps { + indices: IndexType[], + fields: FieldType[], + tableId: string } -const IndexesList: React.FC = ({ }) => { - const { t} = useTranslation() ; +const IndexesList: React.FC = ({ indices, fields, tableId }) => { + + const { t } = useTranslation(); + const { createIndex } = useDatabaseOperations(); + + const addIndex = (event: any) => { + event.stopPropagation && event.stopPropagation(); + createIndex({ + id: v4(), + name: `index_${indices.length + 1}`, + unique: true, + tableId: tableId + } as IndexInsertType); + } return (
-
- -
+ { + indices.map((index: IndexType) => ) + } + @@ -33,4 +55,9 @@ const IndexesList: React.FC = ({ }) => { } -export default IndexesList; \ No newline at end of file + + + +export default React.memo(IndexesList, (prevState, newState) => { + return hash(prevState) == hash(newState); +}); \ No newline at end of file diff --git a/src/pages/database/db-controller/tables-controller/table-accordion-item/table-accordion-body.tsx b/src/pages/database/db-controller/tables-controller/table-accordion-item/table-accordion-body.tsx index 1856cdd..04df59a 100644 --- a/src/pages/database/db-controller/tables-controller/table-accordion-item/table-accordion-body.tsx +++ b/src/pages/database/db-controller/tables-controller/table-accordion-item/table-accordion-body.tsx @@ -1,16 +1,17 @@ import { Accordion, AccordionItem, Button, cn, Textarea } from "@heroui/react"; -import { ChevronLeft, FileKey, FileType, MessageSquareQuote, Plus } from "lucide-react"; +import { ChevronLeft, FileKey, FileType, MessageSquareQuote, Plus } from "lucide-react"; -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import ColorPicker from "@/components/color-picker/color-picker"; import FieldList from "./field/field-list"; import IndexesList from "./index/indexes-list"; import { TableType } from "@/lib/schemas/table-schema"; -import { useDatabaseOperations } from "@/providers/database-provider/database-provider"; +import { useDatabaseOperations } from "@/providers/database-provider/database-provider"; import { getNextSequence } from "@/utils/field"; import { v4 } from "uuid"; +import { IndexInsertType } from "@/lib/schemas/index-schema"; export interface TableAccordionBodyProps { @@ -22,7 +23,7 @@ const TableAccordionBody: React.FC = ({ table }) => { const [selectedKeys, setSelectedKeys] = useState(new Set(["fields"])); const [note, setNote] = useState(table.note ? table.note : ""); const { t } = useTranslation(); - const { editTable, createField } = useDatabaseOperations(); + const { editTable, createField, createIndex } = useDatabaseOperations(); const onColorChange = useCallback((color: string | undefined) => { editTable({ id: table.id, color: color ? color : null } as TableType); @@ -40,6 +41,15 @@ const TableAccordionBody: React.FC = ({ table }) => { }) } + const addIndex = (event: any) => { + event.stopPropagation && event.stopPropagation(); + createIndex({ + id: v4(), + name: `index_${table.indices.length + 1}`, + unique: true, + tableId: table.id + } as IndexInsertType); + } const saveNote = () => { editTable({ id: table.id, @@ -50,10 +60,10 @@ const TableAccordionBody: React.FC = ({ table }) => { useEffect(() => { setNote(table.note ? table.note : ""); - }, [table.note]) ; + }, [table.note]); + - return (
@@ -87,7 +97,7 @@ const TableAccordionBody: React.FC = ({ table }) => {
} > - + ( @@ -102,14 +112,20 @@ const TableAccordionBody: React.FC = ({ table }) => { trigger: "hover:bg-default h-6 dark:hover:bg-background" }} subtitle={ -
+
+
}> - + ( @@ -154,6 +170,7 @@ const TableAccordionBody: React.FC = ({ table }) => {