diff --git a/cal/main.go b/cal/main.go index 1816c1f..84ef091 100644 --- a/cal/main.go +++ b/cal/main.go @@ -40,7 +40,7 @@ func main() { os.Exit(1) } for _, e := range all { - fmt.Printf("%s\t%s\t%s\t%s\n", e.ID, e.Title, e.Start.Format(time.DateTime), e.End.Format(time.DateTime)) + fmt.Printf("%s\t%s\t%s\t%s\n", e.ID, e.Title, e.Start.Format(time.DateTime), e.Duration.String()) } default: fmt.Printf("unkown command %s\n", os.Args[1]) diff --git a/cal/sqlite.go b/cal/sqlite.go index 20b153b..7855010 100644 --- a/cal/sqlite.go +++ b/cal/sqlite.go @@ -14,7 +14,7 @@ const ( ) var migrations = []string{ - `CREATE TABLE events ("id" TEXT UNIQUE, "title" TEXT, "start" TIMESTAMP, "end" TIMESTAMP)`, + `CREATE TABLE events ("id" TEXT UNIQUE, "title" TEXT, "start" TIMESTAMP, "duration" TEXT)`, `PRAGMA journal_mode=WAL`, `PRAGMA synchronous=NORMAL`, `PRAGMA cache_size=2000`, @@ -51,16 +51,16 @@ func NewSqlite(dbPath string) (*Sqlite, error) { func (s *Sqlite) Store(event item.Event) error { if _, err := s.db.Exec(` INSERT INTO events -(id, title, start, end) +(id, title, start, duration) VALUES (?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET title=?, start=?, -end=?`, - event.ID, event.Title, event.Start.Format(timestampFormat), event.End.Format(timestampFormat), - event.Title, event.Start.Format(timestampFormat), event.End.Format(timestampFormat)); err != nil { +duration=?`, + event.ID, event.Title, event.Start.Format(timestampFormat), event.Duration.String(), + event.Title, event.Start.Format(timestampFormat), event.Duration.String()); err != nil { return fmt.Errorf("%w: %v", ErrSqliteFailure, err) } return nil @@ -69,9 +69,9 @@ end=?`, func (s *Sqlite) Find(id string) (item.Event, error) { var event item.Event err := s.db.QueryRow(` -SELECT id, title, start, end +SELECT id, title, start, duration FROM events -WHERE id = ?`, id).Scan(&event.ID, &event.Title, &event.Start, &event.End) +WHERE id = ?`, id).Scan(&event.ID, &event.Title, &event.Start, &event.Duration) if err == sql.ErrNoRows { return event, fmt.Errorf("event not found: %w", err) @@ -85,7 +85,7 @@ WHERE id = ?`, id).Scan(&event.ID, &event.Title, &event.Start, &event.End) func (s *Sqlite) FindAll() ([]item.Event, error) { rows, err := s.db.Query(` -SELECT id, title, start, end +SELECT id, title, start, duration FROM events`) if err != nil { return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) @@ -95,7 +95,7 @@ FROM events`) defer rows.Close() for rows.Next() { var event item.Event - if err := rows.Scan(&event.ID, &event.Title, &event.Start, &event.End); err != nil { + if err := rows.Scan(&event.ID, &event.Title, &event.Start, &event.Duration); err != nil { return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) } result = append(result, event) diff --git a/item/event.go b/item/event.go index 03fd096..aa11e5d 100644 --- a/item/event.go +++ b/item/event.go @@ -7,24 +7,49 @@ import ( ) type EventBody struct { - Title string `json:"title"` - Start time.Time `json:"start"` - End time.Time `json:"end"` + Title string `json:"title"` + Start time.Time `json:"start"` + Duration time.Duration `json:"duration"` } func (e EventBody) MarshalJSON() ([]byte, error) { type Alias EventBody return json.Marshal(&struct { - Start string `json:"start"` - End string `json:"end"` + Start string `json:"start"` + Duration string `json:"duration"` *Alias }{ - Start: e.Start.UTC().Format(time.RFC3339), - End: e.End.UTC().Format(time.RFC3339), - Alias: (*Alias)(&e), + Start: e.Start.UTC().Format(time.RFC3339), + Duration: e.Duration.String(), + Alias: (*Alias)(&e), }) } +func (e *EventBody) UnmarshalJSON(data []byte) error { + type Alias EventBody + aux := &struct { + Start string `json:"start"` + Duration string `json:"duration"` + *Alias + }{ + Alias: (*Alias)(e), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + var err error + if e.Start, err = time.Parse(time.RFC3339, aux.Start); err != nil { + return err + } + + if e.Duration, err = time.ParseDuration(aux.Duration); err != nil { + return err + } + + return nil +} + type Event struct { ID string `json:"id"` EventBody @@ -47,9 +72,9 @@ func NewEvent(i Item) (Event, error) { func (e Event) Item() (Item, error) { body, err := json.Marshal(EventBody{ - Title: e.Title, - Start: e.Start, - End: e.End, + Title: e.Title, + Start: e.Start, + Duration: e.Duration, }) if err != nil { return Item{}, fmt.Errorf("could not marshal event to json") diff --git a/item/event_test.go b/item/event_test.go index 28489d0..39c5fb3 100644 --- a/item/event_test.go +++ b/item/event_test.go @@ -11,6 +11,10 @@ import ( func TestNewEvent(t *testing.T) { t.Parallel() + oneHour, err := time.ParseDuration("1h") + if err != nil { + t.Errorf("exp nil, got %v", err) + } for _, tc := range []struct { name string it item.Item @@ -25,7 +29,7 @@ func TestNewEvent(t *testing.T) { Body: `{ "title":"title", "start":"2024-09-20T08:00:00Z", - "end":"2024-09-20T10:00:00Z" + "duration":"1h" }`, }, expErr: true, @@ -47,15 +51,15 @@ func TestNewEvent(t *testing.T) { Body: `{ "title":"title", "start":"2024-09-20T08:00:00Z", - "end":"2024-09-20T10:00:00Z" + "duration":"1h" }`, }, expEvent: item.Event{ ID: "a", EventBody: item.EventBody{ - Title: "title", - Start: time.Date(2024, 9, 20, 8, 0, 0, 0, time.UTC), - End: time.Date(2024, 9, 20, 10, 0, 0, 0, time.UTC), + Title: "title", + Start: time.Date(2024, 9, 20, 8, 0, 0, 0, time.UTC), + Duration: oneHour, }, }, }, @@ -78,6 +82,10 @@ func TestNewEvent(t *testing.T) { func TestEventItem(t *testing.T) { t.Parallel() + oneHour, err := time.ParseDuration("1h") + if err != nil { + t.Errorf("exp nil, got %v", err) + } for _, tc := range []struct { name string event item.Event @@ -89,7 +97,7 @@ func TestEventItem(t *testing.T) { expItem: item.Item{ Kind: item.KindEvent, Updated: time.Time{}, - Body: `{"start":"0001-01-01T00:00:00Z","end":"0001-01-01T00:00:00Z","title":""}`, + Body: `{"start":"0001-01-01T00:00:00Z","duration":"0s","title":""}`, }, }, { @@ -97,16 +105,16 @@ func TestEventItem(t *testing.T) { event: item.Event{ ID: "a", EventBody: item.EventBody{ - Title: "title", - Start: time.Date(2024, 9, 23, 8, 0, 0, 0, time.UTC), - End: time.Date(2024, 9, 23, 10, 0, 0, 0, time.UTC), + Title: "title", + Start: time.Date(2024, 9, 23, 8, 0, 0, 0, time.UTC), + Duration: oneHour, }, }, expItem: item.Item{ ID: "a", Kind: item.KindEvent, Updated: time.Time{}, - Body: `{"start":"2024-09-23T08:00:00Z","end":"2024-09-23T10:00:00Z","title":"title"}`, + Body: `{"start":"2024-09-23T08:00:00Z","duration":"1h0m0s","title":"title"}`, }, }, } {