init the index schema

This commit is contained in:
KarimTamani
2025-05-27 16:42:43 +01:00
parent ed13965f61
commit 1c831c9902
36 changed files with 177 additions and 81 deletions
+2 -2
View File
@@ -7,7 +7,7 @@
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint -c .eslintrc.json ./src/**/**/*.{ts,tsx} --fix",
"preview": "vite preview"
"preview": "vite preview"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
@@ -65,4 +65,4 @@
"vite-plugin-top-level-await": "^1.5.0",
"vite-tsconfig-paths": "^4.3.2"
}
}
}
-1
View File
@@ -7,7 +7,6 @@ import useAppRoutes from "./routes/app-route";
import { SyncProvider } from "./providers/sync-provider/sync-provider";
import DatabaseProvider from "./providers/database-provider/database-provider";
import DiagramProvider from "./providers/diagram-provider/diagram-provider";
import { NextUIProvider } from "@nextui-org/react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { HeroUIProvider, ToastProvider } from "@heroui/react";
+3 -3
View File
@@ -1,5 +1,5 @@
import { Dropdown, DropdownMenu as HeroDropdownMenu, DropdownItem, DropdownTrigger, Button, useDisclosure, Popover, PopoverTrigger, PopoverContent, Divider, DropdownSection } from "@heroui/react";
import { useCallback, useMemo, useState } from "react";
import { Dropdown, DropdownMenu as HeroDropdownMenu, DropdownItem, DropdownTrigger, Button } from "@heroui/react";
import { useMemo } from "react";
import SubmenuDropdown from "./submenu-dropdown";
@@ -22,7 +22,7 @@ export interface MenuDropdownProps {
isOpen?: boolean ,
clickHandler? : () => void
}
const DropdownMenu: React.FC<MenuDropdownProps> = ({ title, children, isOpen , clickHandler }) => {
const DropdownMenu: React.FC<MenuDropdownProps> = ({ title, children, clickHandler }) => {
const disabledChilds: string[] = useMemo(() => {
return children ? children?.filter((child: MenuDropdownProps) => child.isDisabled && child.title).map((child: MenuDropdownProps) => child.title as string) : []
}, [children]);
+1 -2
View File
@@ -1,8 +1,7 @@
import { useTheme } from "next-themes";
import DropdownMenu, { MenuDropdownProps } from "./menu-dropdown";
import React, { useMemo } from "react";
import { menuItem } from "@heroui/react";
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
+2 -2
View File
@@ -3,7 +3,7 @@ import { Wifi, WifiOff } from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react";
import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip/tooltip";
import { cn, Divider, Progress } from "@heroui/react";
import { differenceInHours, differenceInMinutes, lastDayOfYear } from "date-fns";
import { differenceInHours, differenceInMinutes } from "date-fns";
const ConnectionStatus: React.FC = () => {
@@ -19,7 +19,7 @@ const ConnectionStatus: React.FC = () => {
})
useEffect(() => {
const getLastUploadAtValue = (event: any) => {
const getLastUploadAtValue = () => {
const last_upload_at = localStorage.getItem("last_upload_at");
if (last_upload_at)
setLastUploadAt(new Date(last_upload_at));
+4 -4
View File
@@ -1,6 +1,6 @@
import { NavbarBrand, NavbarContent, Navbar as NavbarContainer, Image, Dropdown, DropdownTrigger, Button, DropdownMenu, DropdownItem } from "@heroui/react";
import Menu from "../menu/menu";
import { useTheme } from "next-themes";
import Menu from "../menu/menu";
import ConnectionStatus from "./connection-status";
interface Props {
@@ -9,8 +9,8 @@ interface Props {
const Navbar: React.FC<Props> = ({ }) => {
const { resolvedTheme } = useTheme();
return (
<nav className="h-12 fixed z-50 bg-background w-full flex items-center p-4 border-b border-default-200">
+1 -1
View File
@@ -1,4 +1,4 @@
import { BookOpen, EarthLock, GitCommitHorizontal, Github, Settings, Sparkles, Table, TableProperties, Waypoints, Workflow, X, Zap } from "lucide-react";
import { BookOpen, EarthLock, GitCommitHorizontal, Github, Settings, Sparkles, TableProperties, Waypoints, Workflow, Zap } from "lucide-react";
import SidebarItem, { SidebarItemProps } from "./sidebar-item";
import { useMemo } from "react";
import { useLocation } from "react-router-dom";
+1 -1
View File
@@ -1,7 +1,7 @@
import { TableType } from "@/lib/schemas/table-schema";
import { isTablesOverlapping } from "@/utils/tables";
import { areArraysEqual } from "@/utils/utils";
import { Node, useReactFlow } from "@xyflow/react";
import { useReactFlow } from "@xyflow/react";
import { useCallback, useEffect, useMemo, useState } from "react";
// Return type of the hook
+1 -1
View File
@@ -1,4 +1,4 @@
import { Cardinality, RelationshipType } from "@/lib/schemas/relationship-schema";
import { RelationshipType } from "@/lib/schemas/relationship-schema";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
+7 -1
View File
@@ -5,6 +5,8 @@ import { tables, tablesRelations } from './table-schema';
import { fields, fieldsRelations } from './field-schema';
import { relationshipRelations, relationships } from './relationship-schema';
import { databaseRelations, databases } from './database-schema';
import { indices, indicesRlationships } from './index-schema';
import { field_indices, fieldIndicesRelationships } from './field_index-schema';
export const drizzleSchema = {
data_types ,
@@ -12,13 +14,17 @@ export const drizzleSchema = {
fields ,
relationships ,
databases ,
indices ,
field_indices ,
// relationships
tablesRelations ,
fieldsRelations ,
relationshipRelations ,
dataTypeRelations ,
databaseRelations
databaseRelations ,
indicesRlationships ,
fieldIndicesRelationships
};
// Infer the PowerSync schema from your Drizzle schema
+12 -8
View File
@@ -1,8 +1,10 @@
import { sqliteTable, text, real, 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 } from './field_index-schema';
import { indices } from './index-schema';
export const fields = sqliteTable("fields", {
@@ -21,24 +23,26 @@ export const fields = sqliteTable("fields", {
sequence: integer("sequence").default(0),
});
export const fieldsRelations = relations(fields, ({ one }) => ({
export const fieldsRelations = relations(fields, ({ one, many }) => ({
table: one(tables, {
fields: [fields.tableId],
references: [tables.id],
}),
type : one(data_types , {
fields : [ fields.typeId] ,
references : [data_types.id]
}) ,
type: one(data_types, {
fields: [fields.typeId],
references: [data_types.id]
}),
sourceRelations: one(relationships),
targetRelations: one(relationships),
fieldIndices: many(field_indices),
indices: many(indices)
}));
export interface FieldType extends InferSelectModel<typeof fields> {
sequence: number ,
type : DataType
sequence: number,
type: DataType
};
+31
View File
@@ -0,0 +1,31 @@
import { sqliteTable, text } 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" }),
});
export const fieldIndicesRelationships = relations(field_indices, ({ one }) => ({
field: one(fields, {
fields: [field_indices.fieldId],
references: [fields.id]
}),
index: one(indices, {
fields: [field_indices.indexId],
references: [indices.id]
}),
}))
export interface FieldIndexType extends InferSelectModel<typeof field_indices> {};
export interface FieldIndexInsertType extends InferInsertModel<typeof field_indices> { };
+40
View File
@@ -0,0 +1,40 @@
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 { fields } from './field-schema';
export const indices = sqliteTable("indices", {
id: text("id").primaryKey().notNull(),
tableId: text("tableId")
.notNull()
.references(() => tables.id, { onDelete: "cascade" }),
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 interface IndexType extends InferSelectModel<typeof indices> {
fieldIndices : FieldIndexType[]
};
export interface IndexInsertType extends InferInsertModel<typeof indices> {
};
+6 -2
View File
@@ -3,6 +3,7 @@ import { sqliteTable, text, real, integer } from 'drizzle-orm/sqlite-core';
import { fields, FieldType } from './field-schema';
import { relationships } from './relationship-schema';
import { databases } from './database-schema';
import { IndexType, indices } from './index-schema';
export const tables = sqliteTable('tables', {
id: text('id')
@@ -31,14 +32,17 @@ export const tablesRelations = relations(tables, ({ many, one }) => ({
database: one(databases, {
fields: [tables.databaseId],
references: [databases.id],
})
}) ,
indices : many(indices) ,
}));
export interface TableType extends InferSelectModel<typeof tables> {
fields: FieldType[];
indices : IndexType[] ;
};
+1 -2
View File
@@ -1,6 +1,5 @@
import Sidebar from "@/components/sidebar/sidebar";
import DatabasePage from "../database/database-page";
import Sidebar from "@/components/sidebar/sidebar";
import Navbar from "@/components/navbar/navbar";
import { Outlet } from "react-router-dom";
@@ -1,6 +1,6 @@
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/tooltip/tooltip";
import { useDatabaseHistory } from "@/providers/database-history/database-history-provider";
import { Button, cn, Divider, Navbar, NavbarContent } from "@heroui/react";
import { Button, cn, Divider, Navbar } from "@heroui/react";
import { useOnViewportChange, useReactFlow } from "@xyflow/react";
import { LayoutGrid, Redo, Scan, Undo, ZoomIn, ZoomOut } from "lucide-react";
+1 -1
View File
@@ -38,7 +38,7 @@ import { useTranslation } from "react-i18next";
import useOverlappingTables from "@/hooks/use-overlapping-tables";
const DatabasePage: React.FC<never> = () => {
const DatabasePage: React.FC = () => {
const { t } = useTranslation();
// Extract database state and operations
const { database, getField } = useDatabase();
@@ -3,7 +3,7 @@ import { FieldType } from "@/lib/schemas/field-schema";
import { RelationshipInsertType } from "@/lib/schemas/relationship-schema";
import { TableType } from "@/lib/schemas/table-schema";
import { useDatabase } from "@/providers/database-provider/database-provider";
import { FileKey, FileMinus2, FileOutput, Key, KeyRound } from "lucide-react";
import { FileKey, FileMinus2, FileOutput, KeyRound } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -1,10 +1,10 @@
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/tooltip/tooltip";
import { Cardinality, RelationshipInsertType, RelationshipType } from "@/lib/schemas/relationship-schema";
import { useDatabase, useDatabaseOperations } from "@/providers/database-provider/database-provider";
import { useDatabaseOperations } from "@/providers/database-provider/database-provider";
import { Button, Select, SelectItem, SharedSelection } from "@heroui/react";
import { ChevronsLeftRightEllipsis, FileMinus2, FileOutput, SquareArrowLeft, SquareArrowRight, Trash2 } from "lucide-react";
import { Key, useEffect, useState } from "react";
import { ChevronsLeftRightEllipsis, FileMinus2, FileOutput, Trash2 } from "lucide-react";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -1,7 +1,7 @@
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/tooltip/tooltip"
import { Accordion, AccordionItem, Button, Input, useDisclosure } from "@heroui/react"
import { Code, List, ListCollapse, Table, Workflow } from "lucide-react"
import { Ref, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { ListCollapse, Workflow } from "lucide-react"
import { Ref, useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import RelationshipAccordionHeader from "./relationship-accordion-item/relationship-accordion-header";
import RelationshipAccordionBody from "./relationship-accordion-item/relationship-accordion-body";
@@ -1,4 +1,4 @@
import { Button, Select, SelectItem } from "@heroui/react";
import { Button, } from "@heroui/react";
import IndexItem from "./index-item";
import { Plus } from "lucide-react";
import { useTranslation } from "react-i18next";
@@ -1,14 +1,14 @@
import { Accordion, AccordionItem, Button, cn, Textarea } from "@heroui/react";
import { ChevronLeft, FileKey, FileType, Key, MessageSquareQuote, Plus } from "lucide-react";
import { ChevronLeft, FileKey, FileType, MessageSquareQuote, Plus } from "lucide-react";
import React, { MouseEventHandler, 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 { useDatabase, useDatabaseOperations } from "@/providers/database-provider/database-provider";
import { useDatabaseOperations } from "@/providers/database-provider/database-provider";
import { getNextSequence } from "@/utils/field";
import { v4 } from "uuid";
@@ -1,8 +1,8 @@
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/tooltip/tooltip";
import { Button, cn, Input, Listbox, ListboxItem, Popover, PopoverContent, PopoverTrigger, useDisclosure } from "@heroui/react";
import { Button, cn, Input, Listbox, ListboxItem, Popover, PopoverContent, PopoverTrigger } from "@heroui/react";
import { Check, ChevronRight, Copy, EllipsisVertical, FileKey, FileType, Focus, Pencil, Trash } from "lucide-react";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { TableInsertType, TableType } from "@/lib/schemas/table-schema";
@@ -1,6 +1,6 @@
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/tooltip/tooltip"
import { Accordion, AccordionItem, Button, Input } from "@heroui/react"
import { ChevronDown, Code, EllipsisVertical, Focus, Grid, Grip, List, Pencil, Table } from "lucide-react"
import { Code, List, Table } from "lucide-react"
import { useTranslation } from "react-i18next";
import { Ref, useCallback, useEffect, useRef, useState } from "react";
import TableAccordionHeader from "./table-accordion-item/table-accordion-header";
@@ -9,7 +9,7 @@ import { useDatabase, useDatabaseOperations } from "@/providers/database-provide
import { TableInsertType, TableType } from "@/lib/schemas/table-schema";
import { v4 } from "uuid";
import { useDiagram } from "@/providers/diagram-provider/diagram-provider";
import { useReactFlow, useViewport } from "@xyflow/react";
import { useReactFlow } from "@xyflow/react";
interface Props { }
+2 -4
View File
@@ -65,15 +65,13 @@ const Field: React.FC<Props> = (props) => {
>
{fieldName}
{
field.note && !editMode &&
field.note && !editMode &&
<Tooltip>
<TooltipTrigger>
<MessageSquareQuote className="size-3.5 text-icon" />
</TooltipTrigger>
<TooltipContent >
<TooltipContent>
{field.note}
</TooltipContent>
</Tooltip>
}
+5 -5
View File
@@ -1,12 +1,12 @@
import { Cardinality, RelationshipType } from "@/lib/schemas/relationship-schema";
import { useDiagram, useDiagramOps } from "@/providers/diagram-provider/diagram-provider";
import { card, cn } from "@heroui/react";
import { Edge, EdgeProps, getBezierPath, getSmoothStepPath, InternalNode, Node, Position, useReactFlow } from "@xyflow/react";
import React, { useEffect, useMemo } from "react";
import { useDiagramOps } from "@/providers/diagram-provider/diagram-provider";
import { cn } from "@heroui/react";
import { Edge, EdgeProps, getSmoothStepPath, Position, useReactFlow } from "@xyflow/react";
import React, { useMemo } from "react";
import hash from 'object-hash';
export type RelationshipProps = Edge<{
@@ -1,7 +1,5 @@
import { DatabaseType } from "@/lib/schemas/database-schema";
import { RelationshipType } from "@/lib/schemas/relationship-schema";
import { TableType } from "@/lib/schemas/table-schema";
import { createContext, Dispatch, SetStateAction } from "react";
import { DatabaseType } from "@/lib/schemas/database-schema";
import { createContext } from "react";
@@ -2,8 +2,8 @@
import { DataType } from "@/lib/schemas/data-type-schema";
import { DatabaseType } from "@/lib/schemas/database-schema";
import { FieldInsertType, FieldType } from "@/lib/schemas/field-schema";
import { RelationshipInsertType, RelationshipType } from "@/lib/schemas/relationship-schema";
import { TableInsertType, TableType } from "@/lib/schemas/table-schema";
import { RelationshipInsertType } from "@/lib/schemas/relationship-schema";
import { TableInsertType } from "@/lib/schemas/table-schema";
import { DBDiffOperation } from "@/utils/database";
import { QueryResult } from "@powersync/web";
import { createContext } from "react";
@@ -12,6 +12,8 @@ import DatabaseHistoryProvider from "../database-history/database-history-provid
import { DBDiffOperation } from "@/utils/database";
import { DatabaseType } from "@/lib/schemas/database-schema";
import { getTimestamp } from "@/utils/utils";
import { indices } from "@/lib/schemas/index-schema";
import { field_indices } from "@/lib/schemas/field_index-schema";
interface Props { children: React.ReactNode }
@@ -43,6 +45,12 @@ const DatabaseProvider: React.FC<Props> = ({ children }) => {
with: {
type: true
}
},
indices: {
orderBy: asc(indices.createdAt),
with: {
fieldIndices: true
}
}
}
},
@@ -60,6 +68,8 @@ const DatabaseProvider: React.FC<Props> = ({ children }) => {
)
);
// Normalize result to single object
if (database.length == 1)
database = database[0] as any;
@@ -254,7 +264,7 @@ const DatabaseProvider: React.FC<Props> = ({ children }) => {
return (
<DatabaseDataContext.Provider value={{
database: database as unknown as DatabaseType,
isLoading,
getField,
@@ -1,4 +1,4 @@
import { createContext, Dispatch, SetStateAction } from "react";
import { createContext, Dispatch } from "react";
interface DiagramDataContextType {
@@ -1,6 +1,6 @@
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
import { useCallback, useContext, useMemo, useState } from "react";
import { FitViewOptions, useReactFlow } from "@xyflow/react";
import { useReactFlow } from "@xyflow/react";
import { useNavigate } from "react-router-dom";
import { RelationshipType } from "@/lib/schemas/relationship-schema";
import { DiagramDataContext, DiagramOpsContext } from "./diagram-context";
@@ -6,7 +6,7 @@ import { AppSchema, drizzleSchema } from '@/lib/schemas/app-schema';
import { StackRenderConnector } from '@/utils/stackrender-connector';
import { CircularProgress } from '@heroui/react';
import { PowerSyncSQLiteDatabase, wrapPowerSyncWithDrizzle } from '@powersync/drizzle-driver';
import { ExtractTablesWithRelations } from 'drizzle-orm';
export const powerSyncDb = new PowerSyncDatabase({
database: {
+1 -1
View File
@@ -1,5 +1,5 @@
import { Navigate, Route, Routes } from 'react-router-dom';
import { Routes } from 'react-router-dom';
import useDashboardRoutes from './dashboard-route';
const useAppRoutes = () => {
const dashboardRoutes = useDashboardRoutes();
-1
View File
@@ -1,6 +1,5 @@
import DashboardPage from '@/pages/dashboard/dashboard-page';
import DatabasePage from '@/pages/database/database-page';
import { Route } from 'react-router-dom';
import useDatabaseRoutes from './database-route';
+1 -2
View File
@@ -1,9 +1,8 @@
import DashboardPage from '@/pages/dashboard/dashboard-page';
import DatabasePage from '@/pages/database/database-page';
import RelationshipController from '@/pages/database/db-controller/relationship-controller/relationship-controller';
import TablesController from '@/pages/database/db-controller/tables-controller/tables-controller';
import { Navigate, Route, Routes } from 'react-router-dom';
import { Route } from 'react-router-dom';
const useDatabaseRoutes = () => {
+21 -11
View File
@@ -2,13 +2,18 @@
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"lib": [
"ES2020",
"DOM",
"DOM.Iterable"
],
"module": "ESNext",
"skipLibCheck": true,
"paths": {
"@/*": ["./src/*"]
"@/*": [
"./src/*"
]
},
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
@@ -16,13 +21,18 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
"strict": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": false,
"noUnusedParameters": false
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
"include": [
"src"
],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}