From 05fb886b9b82706919688fe88673597f4f1159ec Mon Sep 17 00:00:00 2001 From: Richie Varghese Date: Thu, 10 Feb 2022 00:14:18 +0530 Subject: [PATCH] add new key-value done --- VERSION | 2 +- database/{db.go => database.go} | 98 ++++++++-------- database/{db_test.go => database_test.go} | 0 server/db.go | 103 ++--------------- server/server.go | 3 + ui/package.json | 3 +- ui/src/components/AddEntryModal.tsx | 132 ++++++++++++++++++++++ ui/src/components/DatagridComponents.tsx | 40 ++----- ui/src/controllers/DatagridList.tsx | 12 +- 9 files changed, 214 insertions(+), 179 deletions(-) rename database/{db.go => database.go} (95%) rename database/{db_test.go => database_test.go} (100%) create mode 100644 ui/src/components/AddEntryModal.tsx diff --git a/VERSION b/VERSION index 26789e8..f25fde5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v.0.0.1 +v.0.0.3 diff --git a/database/db.go b/database/database.go similarity index 95% rename from database/db.go rename to database/database.go index a729370..f064a8a 100644 --- a/database/db.go +++ b/database/database.go @@ -1,49 +1,49 @@ -package database - -import "errors" - -const ( - // BOLT_DB - BoltDB - BOLT_DB = "boltdb" - // BUNT_DB - BuntDB - BUNT_DB = "buntdb" -) - -type KeyValuePair struct { - Key string - Value string -} - -// DB interface for underlying database packages -type DB interface { - Add(string, string, ...interface{}) error - CloseDB() - Get(key string) (string, error) // TODO: add list all keys - Delete(string) error - List(args ...interface{}) ([]KeyValuePair, error) -} - -// Buckets interface for underlying bolt DB buckets -type Buckets interface { - Add() - Get() - List() - Delete() -} - -// DBType for identifying underlying database packages -type DBType string - -// NewDB godoc - creates a new DB instance abstracting the underlying database package -func NewDB(fileName string, dbtype string) (DB, error) { - - // TODO: Add support for other database packages - switch dbtype { - case BOLT_DB: - return openBolt(fileName) - case BUNT_DB: - return openBunt(fileName) - default: - return nil, errors.New("invalid database type") - } -} +package database + +import "errors" + +const ( + // BOLT_DB - BoltDB + BOLT_DB = "boltdb" + // BUNT_DB - BuntDB + BUNT_DB = "buntdb" +) + +type KeyValuePair struct { + Key string + Value string +} + +// DB interface for underlying database packages +type DB interface { + Add(string, string, ...interface{}) error + CloseDB() + Get(key string) (string, error) // TODO: add list all keys + Delete(string) error + List(args ...interface{}) ([]KeyValuePair, error) +} + +// Buckets interface for underlying bolt DB buckets +type Buckets interface { + Add() + Get() + List() + Delete() +} + +// DBType for identifying underlying database packages +type DBType string + +// NewDB godoc - creates a new DB instance abstracting the underlying database package +func NewDB(fileName string, dbtype string) (DB, error) { + + // TODO: Add support for other database packages + switch dbtype { + case BOLT_DB: + return openBolt(fileName) + case BUNT_DB: + return openBunt(fileName) + default: + return nil, errors.New("invalid database type") + } +} diff --git a/database/db_test.go b/database/database_test.go similarity index 100% rename from database/db_test.go rename to database/database_test.go diff --git a/server/db.go b/server/db.go index 7f0e1e2..f1c43a2 100644 --- a/server/db.go +++ b/server/db.go @@ -11,7 +11,6 @@ import ( "github.com/google/uuid" "github.com/ric-v/divulge-keyvalue-db-ui/database" - boltdb "github.com/ric-v/golang-key-value-db-browser/bolt-db" "github.com/valyala/fasthttp" ) @@ -157,6 +156,7 @@ func loadFile(ctx *fasthttp.RequestCtx) { ctx.Error("Error reading db folder: "+err.Error(), fasthttp.StatusInternalServerError) return } + log.Println("dbTypes:", dbTypes) // iterate over files for _, dbType := range dbTypes { @@ -168,9 +168,11 @@ func loadFile(ctx *fasthttp.RequestCtx) { ctx.Error("Error reading db folder: "+err.Error(), fasthttp.StatusInternalServerError) return } + log.Println("dbKeys:", dbKeys) // iterate over files for _, dbkey := range dbKeys { + log.Println("dbkey:", dbkey.Name(), " | dbKey:", dbkey) if dbkey.Name() == dbKey { @@ -185,6 +187,8 @@ func loadFile(ctx *fasthttp.RequestCtx) { // get the file name file := files[0].Name() userSession = Session{dbKey, file, dbType.Name(), nil} + log.Println("userSession: ", userSession) + session.Store(dbKey, userSession) } } } @@ -414,7 +418,7 @@ func insertKeyValue(ctx *fasthttp.RequestCtx) { } // get the dbKey from params - dbKey := string(ctx.UserValue("dbKey").(string)) + dbKey := string(ctx.QueryArgs().Peek("dbkey")) log.Println("dbKey:", dbKey) // load the db from user session @@ -434,32 +438,13 @@ func insertKeyValue(ctx *fasthttp.RequestCtx) { ctx.Error(err.Error(), fasthttp.StatusInternalServerError) return } - fmt.Println("data:", data) - - switch sessionInfo.DBType { - - case database.BOLT_DB: - - // get the DB type from params - bucket := string(ctx.QueryArgs().Peek("bucket")) - log.Println("bucket:", bucket) - // open the boltdb file from temp dir - db, err := boltdb.New("temp" + string(os.PathSeparator) + dbKey + string(os.PathSeparator) + sessionInfo.FileName) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } - defer db.Close() - - // add the key-value pair to the boltdb file - err = db.Add([]byte(bucket), []byte(data.Key), []byte(data.Value)) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } + // add new entry to DB + err = sessionInfo.DB.Add(data.Key, data.Value) + if err != nil { + log.Println(err) + ctx.Error(err.Error(), fasthttp.StatusInternalServerError) + return } // return success message to UI @@ -497,22 +482,6 @@ func insertBucket(ctx *fasthttp.RequestCtx) { bucket := string(ctx.QueryArgs().Peek("bucket")) log.Println("bucket:", bucket) - // open the boltdb file from temp dir - db, err := boltdb.New("temp" + string(os.PathSeparator) + dbKey + string(os.PathSeparator) + sessionInfo.FileName) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } - defer db.Close() - - // remove the bucket from the boltdb file - err = db.AddBucket([]byte(bucket)) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } } // return success message to UI @@ -550,22 +519,6 @@ func deleteBucket(ctx *fasthttp.RequestCtx) { bucket := string(ctx.QueryArgs().Peek("bucket")) log.Println("bucket:", bucket) - // open the boltdb file from temp dir - db, err := boltdb.New("temp" + string(os.PathSeparator) + dbKey + string(os.PathSeparator) + sessionInfo.FileName) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } - defer db.Close() - - // remove the bucket from the boltdb file - err = db.RemoveBucket([]byte(bucket)) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } } // return success message to UI @@ -608,22 +561,6 @@ func deleteKeyValue(ctx *fasthttp.RequestCtx) { bucket := string(ctx.QueryArgs().Peek("bucket")) log.Println("bucket:", bucket) - // open the boltdb file from temp dir - db, err := boltdb.New("temp" + string(os.PathSeparator) + dbKey + string(os.PathSeparator) + sessionInfo.FileName) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } - defer db.Close() - - // delete the key from the boltdb file - err = db.Delete([]byte(bucket), []byte(key)) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } } // return success message to UI @@ -675,22 +612,6 @@ func updateKeyValue(ctx *fasthttp.RequestCtx) { bucket := string(ctx.QueryArgs().Peek("bucket")) log.Println("bucket:", bucket) - // open the boltdb file from temp dir - db, err := boltdb.New("temp" + string(os.PathSeparator) + dbKey + string(os.PathSeparator) + sessionInfo.FileName) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } - defer db.Close() - - // update the key in the boltdb file - err = db.Update([]byte(bucket), []byte(key), []byte(value)) - if err != nil { - log.Println(err) - ctx.Error(err.Error(), fasthttp.StatusInternalServerError) - return - } } // return success message to UI diff --git a/server/server.go b/server/server.go index d8458e9..495bf71 100644 --- a/server/server.go +++ b/server/server.go @@ -23,6 +23,7 @@ func Serve(port string, debug bool) { // create a new router r := router.New() + r.HandleOPTIONS = true // /api/v1/ routes v1 := r.Group("/api/v1") @@ -34,6 +35,7 @@ func Serve(port string, debug bool) { // create new database file v1.POST("/new", newFile) + // load existing file from browser cache v1.POST("/load", loadFile) // close the boltdb file and remove the entries @@ -100,5 +102,6 @@ func Serve(port string, debug bool) { LogAllErrors: true, } // serve the handlers on the router + log.Println("starting server on port:", port) log.Fatal(server.ListenAndServe(":" + port)) } diff --git a/ui/package.json b/ui/package.json index ec76635..7e41d10 100644 --- a/ui/package.json +++ b/ui/package.json @@ -53,5 +53,6 @@ "last 1 firefox version", "last 1 safari version" ] - } + }, + "proxy": "http://127.0.0.1:8080" } diff --git a/ui/src/components/AddEntryModal.tsx b/ui/src/components/AddEntryModal.tsx new file mode 100644 index 0000000..497e0d9 --- /dev/null +++ b/ui/src/components/AddEntryModal.tsx @@ -0,0 +1,132 @@ +import { useEffect, useState } from "react"; +import AddIcon from "@material-ui/icons/Add"; +import { + Tooltip, + Fab, + Typography, + Button, + TextField, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, +} from "@mui/material"; +import http from "../services/axios-common"; +import { useSnackbar } from "notistack"; + +type AddEntryModalProps = { + setUpdated: React.Dispatch>; +}; + +const AddEntryModal = ({ setUpdated }: AddEntryModalProps) => { + const [open, setOpen] = useState(false); + const [key, setKey] = useState(""); + const [value, setValue] = useState(""); + const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + + const handleClickOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + setKey(""); + setValue(""); + }; + + const handleSubmit = () => { + console.log(key, value); + + const payload = { + key, + value, + }; + + http + .post("/api/v1/db?dbkey=" + localStorage.getItem("dbkey"), payload) + .then((resp) => { + enqueueSnackbar("File created successfully", { + key: "success", + variant: "success", + draggable: true, + onClick: () => { + closeSnackbar("success"); + }, + }); + console.log(resp); + setUpdated(true); + handleClose(); + }) + .catch((err) => { + enqueueSnackbar(err.response.data.message, { + key: "error", + variant: "error", + draggable: true, + onClick: () => { + closeSnackbar("error"); + }, + }); + }); + }; + + return ( + <> + + handleClickOpen()} + > + + Add + + + + Add New Key-Value Pair + + + Insert new key-value pair to the DB. Key must be unique if not the + existing record will be overwritten, and the value will be updated. + Value can be any text type data. + + setKey(e.target.value)} + /> + setValue(e.target.value)} + /> + + + + + + + + ); +}; + +export default AddEntryModal; diff --git a/ui/src/components/DatagridComponents.tsx b/ui/src/components/DatagridComponents.tsx index feed57f..bfd0178 100644 --- a/ui/src/components/DatagridComponents.tsx +++ b/ui/src/components/DatagridComponents.tsx @@ -12,8 +12,7 @@ import { gridPageSelector, gridPageCountSelector, } from "@mui/x-data-grid"; -import { Fab, Tooltip } from "@mui/material"; -import AddIcon from "@material-ui/icons/Add"; +import AddEntryModal from "./AddEntryModal"; export const CustomToolbar = () => { return ( @@ -105,11 +104,13 @@ export const CustomNoRowsOverlay = () => { type CustomFooterStatusComponentProps = { status: string; + setUpdated: React.Dispatch>; }; -export const CustomFooterStatusComponent = ( - props: CustomFooterStatusComponentProps -) => { +export const CustomFooterStatusComponent = ({ + status, + setUpdated, +}: CustomFooterStatusComponentProps) => { const apiRef = useGridApiContext(); const page = useGridSelector(apiRef, gridPageSelector); const pageCount = useGridSelector(apiRef, gridPageCountSelector); @@ -124,34 +125,7 @@ export const CustomFooterStatusComponent = ( }} alignItems={["center"]} > - :not(style)": { m: 1 }, - display: "flex", - flexDirection: "row", - }} - justifyContent="flex-start" - alignItems={["center"]} - > - - - - // props.setStatus((current: string) => { - // closedbConnection( - // props.dbkey, - // props.setDbname, - // props.setDbkey - // ); - // return current === "connected" ? "disconnected" : "connected"; - // }) - // } - /> - {/* {props.status === "connected" ? "Disconnect" : "Connect"} */} - - - + { http .get("/api/v1/db/?dbkey=" + props.dbkey) .then((resp) => { + const now = new Date().getTime().toString(); enqueueSnackbar("Updating tables", { - key: "load", + key: now, variant: "info", onClick: () => { - closeSnackbar("load"); + closeSnackbar(now); }, }); console.log("setting data", resp.data); setDataGrid(resp.data.data); + setUpdated(false); }) .catch((err) => { enqueueSnackbar(err.response.data.message, { @@ -53,7 +56,8 @@ export default function FixedSizeGrid(props: Props) { }, }); }); - }, []); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [updated]); return ( @@ -68,7 +72,7 @@ export default function FixedSizeGrid(props: Props) { Footer: CustomFooterStatusComponent, }} componentsProps={{ - footer: { status: props.status }, + footer: { status: props.status, setUpdated: setUpdated }, }} pageSize={15} {...dataGrid}