Skip to content

Commit aa0073e

Browse files
committed
feat: implement add, get, delete, and summarize commands
- Added `add`, `get`, `delete`, and `summarize` commands with corresponding handlers. - Modified the `entry` model to include an auto-incrementing `id` field. - Updated the database layer to support retrieving entries by id and deleting entries by id. - Implemented validation for date ranges to ensure "from" date is not after "to" date. - Enhanced the `get` command to allow retrieving a single entry by id or a list of entries with date range filters. - Added flags and argument parsing for the new commands. - Refactored option handling to include validation functions. - Fixed a bug where max id was not being set properly. - Removed homebrew cask from `.goreleaser.yml`.
1 parent 4d122c6 commit aa0073e

File tree

18 files changed

+337
-191
lines changed

18 files changed

+337
-191
lines changed

.goreleaser.yml

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,3 @@ changelog:
2424
exclude:
2525
- "^docs:"
2626
- "^test:"
27-
28-
homebrew_casks:
29-
- name: llog
30-
repository:
31-
owner: ethn1ee
32-
name: homebrew-tap
33-
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
34-
commit_author:
35-
name: goreleaserbot
36-
email: bot@goreleaser.com
37-
homepage: "https://github.com/ethn1ee/llog"
38-
description: "A simple life logger"
39-
license: "MIT"

cmd/add.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ import (
1111
var addOpts = &handler.AddOpts{}
1212

1313
var addCmd = &cobra.Command{
14-
Use: "add [body]",
15-
Short: "Add a log entry",
16-
Long: `Add a log entry.`,
17-
Args: cobra.ExactArgs(1),
18-
PreRunE: handler.ValidateOptions(cfg, addOpts),
19-
RunE: handler.Add(cfg, db, addOpts),
14+
Use: "add [body]",
15+
Short: "Add a log entry",
16+
Long: `Add a log entry.`,
17+
Args: cobra.ExactArgs(1),
18+
PreRunE: handler.ValidateOptions(cfg, addOpts),
19+
RunE: handler.Add(cfg, db, addOpts),
20+
SilenceUsage: true,
2021
}
2122

2223
func init() {

cmd/delete.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/*
32
Copyright © 2025 Ethan Lee <ethantlee21@gmail.com>
43
*/
@@ -12,11 +11,13 @@ import (
1211
var deleteOpts = &handler.DeleteOpts{}
1312

1413
var deleteCmd = &cobra.Command{
15-
Use: "delete",
16-
Short: "Delete log entries",
17-
Long: `Delete log entries. You can delete with id or interactively`,
18-
PreRunE: handler.ValidateOptions(cfg, deleteOpts),
19-
RunE: handler.Delete(cfg, db, deleteOpts),
14+
Use: "delete [id]",
15+
Short: "Delete log entries",
16+
Long: `Delete log entries. You can delete with entry id or interactively select them.`,
17+
Args: cobra.ExactArgs(1),
18+
PreRunE: handler.ValidateOptions(cfg, deleteOpts),
19+
RunE: handler.Delete(cfg, db, deleteOpts),
20+
SilenceUsage: true,
2021
}
2122

2223
func init() {

cmd/get.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ import (
1111
var getOpts = &handler.GetOpts{}
1212

1313
var getCmd = &cobra.Command{
14-
Use: "get",
15-
Short: "Get log entries",
16-
Long: `Get log entries. You can specify date range with flags.`,
17-
Args: cobra.NoArgs,
18-
PreRunE: handler.ValidateOptions(cfg, getOpts),
19-
RunE: handler.Get(cfg, db, getOpts),
14+
Use: "get [ID]",
15+
Short: "Get log entries",
16+
Long: `Get log entries.
17+
18+
You can retrieve a single entry by providing its ID as an argument.
19+
Alternatively, you can retrieve a list of entries by using flags to filter by date range or limit the count.
20+
21+
Note: Providing an ID is mutually exclusive with using any flags.`,
22+
Args: cobra.MaximumNArgs(1),
23+
PreRunE: handler.ValidateOptions(cfg, getOpts),
24+
RunE: handler.Get(cfg, db, getOpts),
25+
SilenceUsage: true,
2026
}
2127

2228
func init() {

cmd/root.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Copyright © 2025 Ethan Lee <ethantlee21@gmail.com>
44
package cmd
55

66
import (
7-
"log/slog"
87
"os"
98

109
"github.com/ethn1ee/llog/internal/config"
@@ -15,30 +14,23 @@ import (
1514
)
1615

1716
var (
18-
cfg = &config.Config{}
19-
db = &_db.DB{}
20-
lg = &logger.Logger{}
21-
cmdAttr slog.Attr
17+
cfg = &config.Config{}
18+
db = &_db.DB{}
19+
lg = &logger.Logger{}
2220
)
2321

2422
var rootCmd = &cobra.Command{
2523
Use: "llog",
2624
Short: "Life log",
2725
Long: `Record your fleeting moments with llog.`,
2826
PersistentPreRunE: handler.Init(cfg, db, lg),
29-
PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
30-
slog.Info("command completed", cmdAttr)
31-
return nil
32-
},
27+
SilenceUsage: true,
3328
}
3429

3530
func Execute() {
3631
err := rootCmd.Execute()
3732
if err != nil {
38-
slog.Error("command failed", cmdAttr, slog.Any("error", err))
3933
os.Exit(1)
4034
}
41-
if err := lg.Close(); err != nil {
42-
slog.Error("failed to close log file", cmdAttr, slog.Any("error", err))
43-
}
35+
_ = lg.Close()
4436
}

cmd/summarize.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import (
1111
var summarizeOpts = &handler.SummarizeOpts{}
1212

1313
var summarizeCmd = &cobra.Command{
14-
Use: "summarize",
15-
Short: "Summarize log entries",
16-
Long: `Summarize log entries. You can specify date range with flags.`,
17-
PreRunE: handler.ValidateOptions(cfg, summarizeOpts),
18-
RunE: handler.Summarize(cfg, db, summarizeOpts),
14+
Use: "summarize",
15+
Short: "Summarize log entries",
16+
Long: `Summarize log entries. You can specify date range with flags.`,
17+
PreRunE: handler.ValidateOptions(cfg, summarizeOpts),
18+
RunE: handler.Summarize(cfg, db, summarizeOpts),
19+
SilenceUsage: true,
1920
}
2021

2122
func init() {

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.25.0
55
require (
66
github.com/fatih/color v1.18.0
77
github.com/spf13/cobra v1.10.1
8+
github.com/spf13/pflag v1.0.10
89
github.com/spf13/viper v1.21.0
910
gorm.io/driver/sqlite v1.6.0
1011
gorm.io/gorm v1.31.0
@@ -24,7 +25,6 @@ require (
2425
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
2526
github.com/spf13/afero v1.15.0 // indirect
2627
github.com/spf13/cast v1.10.0 // indirect
27-
github.com/spf13/pflag v1.0.10 // indirect
2828
github.com/subosito/gotenv v1.6.0 // indirect
2929
go.yaml.in/yaml/v3 v3.0.4 // indirect
3030
golang.org/x/sys v0.29.0 // indirect

internal/config/internal.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
type internalConfig struct {
4-
MaxId uint
5-
MaxIdDigits int
4+
EntryCount int64
5+
MaxEntryId uint64
6+
MaxEntryIdDigits int
67
}

internal/db/db.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,22 @@ func Load(cfg *config.Config, ctx context.Context, db *DB) error {
3535

3636
db.Entry = &entryDB{gorm.G[model.Entry](gormdb)}
3737

38-
last, err := db.Entry.GetLast(ctx)
38+
count, err := db.Entry.Count(ctx)
3939
if err != nil {
4040
return err
4141
}
4242

43-
cfg.Internal.MaxId = last.ID
44-
cfg.Internal.MaxIdDigits = len(strconv.FormatUint(uint64(last.ID), 10))
43+
cfg.Internal.EntryCount = count
44+
45+
if count > 0 {
46+
last, err := db.Entry.GetLast(ctx)
47+
if err != nil {
48+
return err
49+
}
50+
51+
cfg.Internal.MaxEntryId = last.ID
52+
cfg.Internal.MaxEntryIdDigits = len(strconv.FormatUint(uint64(last.ID), 10))
53+
}
4554

4655
return nil
4756
}

internal/db/entry.go

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package db
22

33
import (
44
"context"
5+
"errors"
56
"time"
67

78
"github.com/ethn1ee/llog/internal/model"
@@ -12,6 +13,10 @@ type entryDB struct {
1213
i gorm.Interface[model.Entry]
1314
}
1415

16+
func (db *entryDB) Count(ctx context.Context) (int64, error) {
17+
return db.i.Count(ctx, "id")
18+
}
19+
1520
func (db *entryDB) Add(ctx context.Context, entry *model.Entry) error {
1621
return db.i.Create(ctx, entry)
1722
}
@@ -20,18 +25,37 @@ func (db *entryDB) GetAll(ctx context.Context) ([]model.Entry, error) {
2025
return db.i.Find(ctx)
2126
}
2227

23-
func (db *entryDB) GetFrom(ctx context.Context, from time.Time) ([]model.Entry, error) {
24-
return db.i.Where("created_at >= ?", from).Find(ctx)
25-
}
26-
27-
func (db *entryDB) GetTo(ctx context.Context, to time.Time) ([]model.Entry, error) {
28-
return db.i.Where("created_at <= ?", to).Find(ctx)
29-
}
30-
3128
func (db *entryDB) GetRange(ctx context.Context, from time.Time, to time.Time) ([]model.Entry, error) {
29+
if from.IsZero() && to.IsZero() {
30+
return nil, errors.New("range unspecified")
31+
}
32+
if from.IsZero() {
33+
return db.i.Where("created_at <= ?", to).Find(ctx)
34+
}
35+
if to.IsZero() {
36+
return db.i.Where("created_at >= ?", from).Find(ctx)
37+
}
3238
return db.i.Where("created_at >= ? AND created_at <= ?", from, to).Find(ctx)
3339
}
3440

3541
func (db *entryDB) GetLast(ctx context.Context) (model.Entry, error) {
3642
return db.i.Last(ctx)
3743
}
44+
45+
func (db *entryDB) GetById(ctx context.Context, id uint64) (model.Entry, error) {
46+
match, err := db.i.Where("id = ?", id).Find(ctx)
47+
if err != nil {
48+
return model.Entry{}, err
49+
}
50+
51+
return match[0], nil
52+
}
53+
54+
func (db *entryDB) DeleteById(ctx context.Context, id uint64) error {
55+
_, err := db.i.Where("id = ?", id).Delete(ctx)
56+
if err != nil {
57+
return err
58+
}
59+
60+
return nil
61+
}

0 commit comments

Comments
 (0)