Add notes to diary entries

pull/8/head
isthisnagee 3 years ago
parent 91b76a3a20
commit afecf9628c

@ -10,33 +10,36 @@ import (
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
var __version = 1 var migrations = []func(*sql.Tx) error{migration0, migration1}
var __version = len(migrations)
type DbCtx struct { type DbCtx struct {
Db *sql.DB Db *sql.DB
Version int Version int
} }
func initVersion(tx *sql.Tx) (int, error) { func initVersion(tx *sql.Tx) (int, int, error) {
var version int var version int
// Check the version // Check the version
if err := tx.QueryRow("PRAGMA user_version").Scan(&version); err != nil { if err := tx.QueryRow("PRAGMA user_version").Scan(&version); err != nil {
tx.Rollback() tx.Rollback()
return 0, fmt.Errorf("Could not select user_version. %w", err) return 0, 0, fmt.Errorf("Could not select user_version. %w", err)
} }
if version == 0 { if version == 0 {
_, err := tx.Exec(fmt.Sprintf("PRAGMA user_version=%d", __version)) _, err := tx.Exec(fmt.Sprintf("PRAGMA user_version=%d", __version))
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return 0, fmt.Errorf("Could not update pragma version. %w", err) return 0, 0, fmt.Errorf("Could not update pragma version. %w", err)
} }
version = __version // Start from 1 so that all migrations are applied
return 0, __version, nil
} else if version != __version { } else if version != __version {
tx.Rollback() tx.Rollback()
return 0, errors.New(fmt.Sprintf("Wrong version. Expected %d got %d", __version, version)) return 0, 0, errors.New(fmt.Sprintf("Wrong version. Expected %d got %d", __version, version))
} }
return version, nil // User is on the latest version, migrations do not need to be ran.
return version, version, nil
} }
func migration0(tx *sql.Tx) error { func migration0(tx *sql.Tx) error {
@ -54,12 +57,28 @@ func migration0(tx *sql.Tx) error {
return nil return nil
} }
func initMigrations(tx *sql.Tx, start_from_versiono int) error { func migration1(tx *sql.Tx) error {
var migrations = []func(*sql.Tx) error{migration0} if _, err := tx.Exec(`
create table diary_log_note (
id integer not null primary key,
log_id integer,
body text,
created_at int not null default (strftime('%s','now')),
version int not null default 0,
foreign key(log_id) references diary_log(id)
)
`); err != nil {
tx.Rollback()
return fmt.Errorf("Could not create diary_log_note. %w", err)
}
return nil
}
func initMigrations(tx *sql.Tx, start_from_version int) error {
for migration_idx, migration := range migrations { for migration_idx, migration := range migrations {
// Version is 1 indexed, while the migration_idx is 0 indexed // Version is 1 indexed, while the migration_idx is 0 indexed
var migration_num = migration_idx + 1 var migration_num = migration_idx + 1
if migration_num < start_from_versiono { if migration_num < start_from_version {
continue continue
} }
err := migration(tx) err := migration(tx)
@ -87,17 +106,17 @@ func Init(db_location string) (*DbCtx, error) {
return nil, err return nil, err
} }
version, err := initVersion(tx) old_version, new_version, err := initVersion(tx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = initMigrations(tx, version) err = initMigrations(tx, old_version)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tx.Commit() tx.Commit()
return &DbCtx{db, version}, nil return &DbCtx{db, new_version}, nil
} }

@ -0,0 +1,87 @@
package model
type DiaryEntryNote struct {
Id int `json:"id"`
Body string `json:"body"`
CreatedAt int `json:"created_at"`
Version int `json:"version"`
LogId int `json:"log_id"`
}
func (app *App) NewDiaryEntryNote(entry_id int, body string) *DiaryEntryNote {
var diary_entry_note DiaryEntryNote
var result, err = app.Db.Exec("INSERT INTO diary_log_note (body, log_id) values (?, ?);", body, entry_id)
if err != nil {
panic(err)
}
id, err := result.LastInsertId()
if err != nil {
panic(err)
}
if err := app.Db.QueryRow(
"SELECT id, body, created_at, version, log_id FROM diary_log_note where id=?",
id,
).Scan(
&diary_entry_note.Id,
&diary_entry_note.Body,
&diary_entry_note.CreatedAt,
&diary_entry_note.Version,
&diary_entry_note.LogId,
); err != nil {
panic(err)
}
return &diary_entry_note
}
func (app *App) GetDiaryEntryNotes(entry_id int) []*DiaryEntryNote {
// not sure if it should be descending.
rows, err := app.Db.Query(
// The second ordering is necessary to break ties.
`SELECT id, body, created_at, version, log_id FROM diary_log_note WHERE log_id=?
ORDER BY created_at desc,
id desc`,
entry_id,
)
if err != nil {
panic(err)
}
defer rows.Close()
var result []*DiaryEntryNote
for rows.Next() {
var id, created_at, version, log_id int
var body string
err := rows.Scan(&id, &body, &created_at, &version, &log_id)
if err != nil {
panic(err)
}
result = append(result, &DiaryEntryNote{
Id: id, Body: body, CreatedAt: created_at, Version: version, LogId: log_id,
})
}
if err := rows.Err(); err != nil {
panic(err)
}
return result
}
func (app *App) DeleteDiaryEntryNote(note_id int) (bool, error) {
result, err := app.Db.Exec("DELETE FROM diary_log_note where id=?", note_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: note_id}
}
return true, nil
}

@ -0,0 +1,69 @@
package model
import (
"testing"
)
func TestNewEntryNote(t *testing.T) {
var app = setup()
var entry = app.NewDiaryEntry("Met with Nagee @ 1PM")
var note = app.NewDiaryEntryNote(entry.Id, "A note")
assert_string(t, "A note", note.Body)
assert_exists(t, note.Id)
assert_exists(t, note.CreatedAt)
assert_exists(t, note.Version)
teardown(app)
}
func TestGetDiaryEntryNotes(t *testing.T) {
var app = setup()
var entry = app.NewDiaryEntry("Met with Nagee @ 1PM")
var note_1 = app.NewDiaryEntryNote(entry.Id, "A note")
var note_2 = app.NewDiaryEntryNote(entry.Id, "Another note")
// The first note should be the latest one created
var notes = app.GetDiaryEntryNotes(entry.Id)
assert_string(t, notes[0].Body, note_2.Body)
assert_int(t, notes[0].Id, note_2.Id)
assert_int(t, notes[0].CreatedAt, note_2.CreatedAt)
assert_int(t, notes[0].Version, note_2.Version)
assert_string(t, notes[1].Body, note_1.Body)
assert_int(t, notes[1].Id, note_1.Id)
assert_int(t, notes[1].CreatedAt, note_1.CreatedAt)
assert_int(t, notes[1].Version, note_1.Version)
teardown(app)
}
func DeleteDiaryEntryNote(t *testing.T) {
var app = setup()
var entry = app.NewDiaryEntry("Met with Nagee @ 1PM")
var note = app.NewDiaryEntryNote(entry.Id, "A note")
is_deleted, _ := app.DeleteDiaryEntry(note.Id)
assert_bool(t, true, is_deleted)
teardown(app)
}
func DeleteDiaryEntryNoteNotFound(t *testing.T) {
var app = setup()
_, err := app.DeleteDiaryEntryNote(-1)
switch err_type := err.(type) {
case *NotFoundError:
// Do nothing
break
default:
t.Fatalf("Expected NotFoundError, got %s", err_type)
}
teardown(app)
}
Loading…
Cancel
Save