From c822f8ec91f37863a99986fe0d930d6f69ae1826 Mon Sep 17 00:00:00 2001 From: isthisnagee Date: Sun, 26 Dec 2021 11:22:22 -0800 Subject: [PATCH] Add delete method :) --- cmd/add.go | 45 +++++++++++++++++++++++ cmd/delete.go | 67 ++++++++++++++++++++++++++++++++++ cmd/root.go | 1 + cmd/{diary/main.go => util.go} | 11 ++++-- model/errors.go | 11 ++++++ model/model.go | 42 +++++++++++++++++++++ model/model_test.go | 61 ++++++++++++++++++++++++++++++- 7 files changed, 233 insertions(+), 5 deletions(-) create mode 100644 cmd/add.go create mode 100644 cmd/delete.go rename cmd/{diary/main.go => util.go} (73%) create mode 100644 model/errors.go diff --git a/cmd/add.go b/cmd/add.go new file mode 100644 index 0000000..5ace645 --- /dev/null +++ b/cmd/add.go @@ -0,0 +1,45 @@ +/* +Copyright © 2021 NAME HERE + +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// addCmd represents the add command +var addCmd = &cobra.Command{ + Use: "add [entry title]", + Args: cobra.ExactArgs(1), + Short: "Add a new diary entry with the given title", + Long: `Add a new diary entry, for example +and usage of using your command. For example: + +$ diary add "Issue when fixing bad data in prod" +1134 + +The returned number is the ID of the added entry. +This ID can be used in other commands. +`, + Run: func(cmd *cobra.Command, args []string) { + var entry = App.NewDiaryEntry(args[0]) + fmt.Println(entry.Id) + }, +} + +func init() { + rootCmd.AddCommand(addCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // addCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // addCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/delete.go b/cmd/delete.go new file mode 100644 index 0000000..5fa7005 --- /dev/null +++ b/cmd/delete.go @@ -0,0 +1,67 @@ +/* +Copyright © 2021 NAME HERE + +*/ +package cmd + +import ( + "fmt" + "strconv" + + "github.com/spf13/cobra" + "os" +) + +// deleteCmd represents the delete command +var deleteCmd = &cobra.Command{ + Use: "delete [Id]", + Args: cobra.ExactArgs(1), + Short: "Delete the given entry. Will ask for confirmation", + Long: `We do not recommend using delete, unless something was truly added by mistake. + Delete is a hard delete. There is no recovery.`, + PreRunE: func(cmd *cobra.Command, args []string) error { + id, err := strconv.Atoi(args[0]) + if err != nil { + return err + } + entry, err := App.GetDiaryEntry(id) + if err != nil { + return err + } + fmt.Println("Are you sure you want to delete the following entry? (y/n)") + fmt.Println(entry.Title) + var response string + fmt.Scanln(&response) + if response == "y" { + return nil + } else { + fmt.Println("Will not delete entry " + args[0]) + os.Exit(0) + } + return nil + }, + Run: func(cmd *cobra.Command, args []string) { + id, err := strconv.Atoi(args[0]) + if err != nil { + panic(err) + } + _, err = App.DeleteDiaryEntry(id) + if err != nil { + panic(err) + } + }, +} + +func init() { + rootCmd.AddCommand(deleteCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // deleteCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // deleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/root.go b/cmd/root.go index 28a2683..acb256f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -43,6 +43,7 @@ func Execute() { } func init() { + cobra.OnInitialize(InitApp) // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. diff --git a/cmd/diary/main.go b/cmd/util.go similarity index 73% rename from cmd/diary/main.go rename to cmd/util.go index f9f483a..cd856e3 100644 --- a/cmd/diary/main.go +++ b/cmd/util.go @@ -1,14 +1,16 @@ -package main +package cmd import ( "errors" - "isthisnagee.com/tools/diary/db" + "isthisnagee.com/tools/diary/model" "log" "os" "path" ) -func main() { +var App *model.App + +func InitApp() { home_dir, err := os.UserHomeDir() if err != nil { @@ -24,8 +26,9 @@ func main() { } } - _, err = db.Init(db_path) if err != nil { log.Fatal(err.Error()) } + var app = model.NewApp(db_path) + App = &app } diff --git a/model/errors.go b/model/errors.go new file mode 100644 index 0000000..98473ed --- /dev/null +++ b/model/errors.go @@ -0,0 +1,11 @@ +package model + +import "fmt" + +type NotFoundError struct { + given_id int +} + +func (e *NotFoundError) Error() string { + return fmt.Sprintf("Could not find id %d", e.given_id) +} diff --git a/model/model.go b/model/model.go index fe70022..57cb42d 100644 --- a/model/model.go +++ b/model/model.go @@ -3,7 +3,9 @@ package model import ( + "database/sql" "isthisnagee.com/tools/diary/db" + "log" ) type DiaryEntry struct { @@ -17,6 +19,15 @@ type App struct { *db.DbCtx } +func NewApp(db_path string) App { + app, err := db.Init(db_path) + if err != nil { + log.Fatal(err.Error()) + } + return App{app} + +} + func (app *App) NewDiaryEntry(title string) *DiaryEntry { var diary_entry DiaryEntry @@ -39,3 +50,34 @@ func (app *App) NewDiaryEntry(title string) *DiaryEntry { return &diary_entry } + +func (app *App) GetDiaryEntry(id int) (*DiaryEntry, error) { + var diary_entry DiaryEntry + + if err := app.Db.QueryRow( + "SELECT id, title, created_at, version FROM diary_log where id=?", + id, + ).Scan(&diary_entry.Id, &diary_entry.Title, &diary_entry.CreatedAt, &diary_entry.Version); err != nil { + if err == sql.ErrNoRows { + return nil, &NotFoundError{given_id: id} + } + return nil, err + } + return &diary_entry, nil +} + +func (app *App) DeleteDiaryEntry(id int) (bool, error) { + result, err := app.Db.Exec("DELETE FROM diary_log where id=?", id) + if err != nil { + return false, err + } + + num_rows_affected, err := result.RowsAffected() + if err != nil { + return false, err + } + if num_rows_affected == 0 { + return false, &NotFoundError{given_id: id} + } + return true, nil +} diff --git a/model/model_test.go b/model/model_test.go index 78cee80..2f05baf 100644 --- a/model/model_test.go +++ b/model/model_test.go @@ -7,7 +7,19 @@ import ( func assert_string(t *testing.T, expected string, actual string) { if actual != expected { - t.Fatalf("(%s, %s)", expected, actual) + t.Fatalf("(%v, %v)", expected, actual) + } +} + +func assert_int(t *testing.T, expected int, actual int) { + if actual != expected { + t.Fatalf("(%v, %v)", expected, actual) + } +} + +func assert_bool(t *testing.T, expected bool, actual bool) { + if actual != expected { + t.Fatalf("(%v, %v)", expected, actual) } } @@ -41,3 +53,50 @@ func TestNewDiaryEntry(t *testing.T) { teardown(app) } + +func TestGetDiaryEntry(t *testing.T) { + var app = setup() + + var inserted_result = app.NewDiaryEntry("Met with Nagee @ 1PM") + queried_result, _ := app.GetDiaryEntry(inserted_result.Id) + + assert_int(t, inserted_result.Id, queried_result.Id) + assert_int(t, inserted_result.CreatedAt, queried_result.CreatedAt) + assert_int(t, inserted_result.Version, queried_result.Version) + assert_string(t, inserted_result.Title, queried_result.Title) + + teardown(app) +} + +func DeleteDiaryEntry(t *testing.T) { + var app = setup() + + var inserted_result = app.NewDiaryEntry("Met with Nagee @ 1PM") + is_deleted, _ := app.DeleteDiaryEntry(inserted_result.Id) + assert_bool(t, true, is_deleted) + _, err := app.GetDiaryEntry(inserted_result.Id) + switch err_type := err.(type) { + case *NotFoundError: + // Do nothing + break + default: + t.Fatalf("Expected NotFoundError, got %s", err_type) + } + + teardown(app) +} + +func DeleteDiaryEntryNotFound(t *testing.T) { + var app = setup() + + _, err := app.DeleteDiaryEntry(-1) + switch err_type := err.(type) { + case *NotFoundError: + // Do nothing + break + default: + t.Fatalf("Expected NotFoundError, got %s", err_type) + } + + teardown(app) +}