From 14b0cf623fe7123b72beea175c416d38b5373959 Mon Sep 17 00:00:00 2001 From: Sung Won Cho Date: Tue, 1 Jan 2019 14:59:57 +1100 Subject: [PATCH] Find command (#149) * Implement basic full text search * Avoid lag in log while making network calls * Allow to restrict search by book name --- .travis.yml | 2 +- Gopkg.lock | 6 +- Gopkg.toml | 2 +- client/client.go | 12 +- cmd/add/add.go | 2 +- cmd/cat/cat.go | 8 +- cmd/edit/edit.go | 10 +- cmd/find/find.go | 180 +++++++++++++ cmd/find/lexer.go | 82 ++++++ cmd/find/lexer_test.go | 213 +++++++++++++++ cmd/ls/ls.go | 29 +- cmd/remove/remove.go | 16 +- cmd/sync/sync.go | 31 ++- cmd/sync/sync_test.go | 336 ++++++++++++------------ core/models.go | 14 +- core/models_test.go | 186 +++++++++---- infra/main.go | 1 - main.go | 3 +- main_test.go | 64 ++--- migrate/fixtures/local-8-pre-schema.sql | 25 ++ migrate/fixtures/local-9-pre-schema.sql | 23 ++ migrate/migrate.go | 3 + migrate/migrate_test.go | 110 ++++++++ migrate/migrations.go | 75 ++++++ scripts/build.sh | 2 + scripts/dev.sh | 2 +- scripts/release.sh | 11 +- scripts/test.sh | 5 +- testutils/fixtures/schema.sql | 50 +++- testutils/main.go | 2 +- testutils/setup.go | 14 +- 31 files changed, 1181 insertions(+), 338 deletions(-) create mode 100644 cmd/find/find.go create mode 100644 cmd/find/lexer.go create mode 100644 cmd/find/lexer_test.go create mode 100644 migrate/fixtures/local-8-pre-schema.sql create mode 100644 migrate/fixtures/local-9-pre-schema.sql diff --git a/.travis.yml b/.travis.yml index 5935a093..c92613d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: go go: - - 1.9.x + - 1.11.x install: - curl -L https://github.com/golang/dep/releases/download/v0.3.2/dep-linux-amd64 -o ./dep && chmod +x ./dep diff --git a/Gopkg.lock b/Gopkg.lock index b8fab672..231a4cc2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -58,12 +58,12 @@ version = "v0.0.4" [[projects]] - digest = "1:bc03901fc8f0965ccba8bc453eae21a9b04f95999eab664c7de6dc7290f4e8f4" + digest = "1:8bbdb2b3dce59271877770d6fe7dcbb8362438fa7d2e1e1f688e4bf2aac72706" name = "github.com/mattn/go-sqlite3" packages = ["."] pruneopts = "" - revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4" - version = "v1.9.0" + revision = "c7c4067b79cc51e6dfdcef5c702e74b1e0fa7c75" + version = "v1.10.0" [[projects]] digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca" diff --git a/Gopkg.toml b/Gopkg.toml index 9e1b26cf..17dea643 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -47,4 +47,4 @@ [[constraint]] name = "github.com/mattn/go-sqlite3" - version = "1.9.0" + version = "1.10.0" diff --git a/client/client.go b/client/client.go index 45765a27..cc8311d9 100644 --- a/client/client.go +++ b/client/client.go @@ -55,7 +55,7 @@ type SyncFragNote struct { UpdatedAt time.Time `json:"updated_at"` AddedOn int64 `json:"added_on"` EditedOn int64 `json:"edited_on"` - Content string `json:"content"` + Body string `json:"content"` Public bool `json:"public"` Deleted bool `json:"deleted"` } @@ -252,7 +252,7 @@ func DeleteBook(ctx infra.DnoteCtx, apiKey, uuid string) (DeleteBookResp, error) // CreateNotePayload is a payload for creating a note type CreateNotePayload struct { BookUUID string `json:"book_uuid"` - Content string `json:"content"` + Body string `json:"content"` } // CreateNoteResp is the response from create note endpoint @@ -274,7 +274,7 @@ type RespNote struct { UUID string `json:"uuid"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` - Content string `json:"content"` + Body string `json:"content"` AddedOn int64 `json:"added_on"` Public bool `json:"public"` USN int `json:"usn"` @@ -286,7 +286,7 @@ type RespNote struct { func CreateNote(ctx infra.DnoteCtx, apiKey, bookUUID, content string) (CreateNoteResp, error) { payload := CreateNotePayload{ BookUUID: bookUUID, - Content: content, + Body: content, } b, err := json.Marshal(payload) if err != nil { @@ -316,7 +316,7 @@ func CreateNote(ctx infra.DnoteCtx, apiKey, bookUUID, content string) (CreateNot type updateNotePayload struct { BookUUID *string `json:"book_uuid"` - Content *string `json:"content"` + Body *string `json:"content"` Public *bool `json:"public"` } @@ -330,7 +330,7 @@ type UpdateNoteResp struct { func UpdateNote(ctx infra.DnoteCtx, apiKey, uuid, bookUUID, content string, public bool) (UpdateNoteResp, error) { payload := updateNotePayload{ BookUUID: &bookUUID, - Content: &content, + Body: &content, Public: &public, } b, err := json.Marshal(payload) diff --git a/cmd/add/add.go b/cmd/add/add.go index d752deb1..55c3967b 100644 --- a/cmd/add/add.go +++ b/cmd/add/add.go @@ -35,7 +35,7 @@ func preRun(cmd *cobra.Command, args []string) error { // NewCmd returns a new add command func NewCmd(ctx infra.DnoteCtx) *cobra.Command { cmd := &cobra.Command{ - Use: "add ", + Use: "add ", Short: "Add a note", Aliases: []string{"a", "n", "new"}, Example: example, diff --git a/cmd/cat/cat.go b/cmd/cat/cat.go index dedfbb7c..b02821cd 100644 --- a/cmd/cat/cat.go +++ b/cmd/cat/cat.go @@ -58,7 +58,7 @@ func NewRun(ctx infra.DnoteCtx) core.RunEFunc { return func(cmd *cobra.Command, args []string) error { db := ctx.DB bookLabel := args[0] - noteID := args[1] + noteRowID := args[1] var bookUUID string err := db.QueryRow("SELECT uuid FROM books WHERE label = ?", bookLabel).Scan(&bookUUID) @@ -69,13 +69,13 @@ func NewRun(ctx infra.DnoteCtx) core.RunEFunc { } var info noteInfo - err = db.QueryRow(`SELECT books.label, notes.uuid, notes.content, notes.added_on, notes.edited_on + err = db.QueryRow(`SELECT books.label, notes.uuid, notes.body, notes.added_on, notes.edited_on FROM notes INNER JOIN books ON books.uuid = notes.book_uuid - WHERE notes.id = ? AND books.uuid = ?`, noteID, bookUUID). + WHERE notes.rowid = ? AND books.uuid = ?`, noteRowID, bookUUID). Scan(&info.BookLabel, &info.UUID, &info.Content, &info.AddedOn, &info.EditedOn) if err == sql.ErrNoRows { - return errors.Errorf("note %s not found in the book '%s'", noteID, bookLabel) + return errors.Errorf("note %s not found in the book '%s'", noteRowID, bookLabel) } else if err != nil { return errors.Wrap(err, "querying the note") } diff --git a/cmd/edit/edit.go b/cmd/edit/edit.go index 455ee8fb..8dedd7aa 100644 --- a/cmd/edit/edit.go +++ b/cmd/edit/edit.go @@ -51,7 +51,7 @@ func newRun(ctx infra.DnoteCtx) core.RunEFunc { return func(cmd *cobra.Command, args []string) error { db := ctx.DB bookLabel := args[0] - noteID := args[1] + noteRowID := args[1] bookUUID, err := core.GetBookUUID(ctx, bookLabel) if err != nil { @@ -59,9 +59,9 @@ func newRun(ctx infra.DnoteCtx) core.RunEFunc { } var noteUUID, oldContent string - err = db.QueryRow("SELECT uuid, content FROM notes WHERE id = ? AND book_uuid = ?", noteID, bookUUID).Scan(¬eUUID, &oldContent) + err = db.QueryRow("SELECT uuid, body FROM notes WHERE rowid = ? AND book_uuid = ?", noteRowID, bookUUID).Scan(¬eUUID, &oldContent) if err == sql.ErrNoRows { - return errors.Errorf("note %s not found in the book '%s'", noteID, bookLabel) + return errors.Errorf("note %s not found in the book '%s'", noteRowID, bookLabel) } else if err != nil { return errors.Wrap(err, "querying the book") } @@ -93,8 +93,8 @@ func newRun(ctx infra.DnoteCtx) core.RunEFunc { } _, err = tx.Exec(`UPDATE notes - SET content = ?, edited_on = ?, dirty = ? - WHERE id = ? AND book_uuid = ?`, newContent, ts, true, noteID, bookUUID) + SET body = ?, edited_on = ?, dirty = ? + WHERE rowid = ? AND book_uuid = ?`, newContent, ts, true, noteRowID, bookUUID) if err != nil { tx.Rollback() return errors.Wrap(err, "updating the note") diff --git a/cmd/find/find.go b/cmd/find/find.go new file mode 100644 index 00000000..38fb1c0e --- /dev/null +++ b/cmd/find/find.go @@ -0,0 +1,180 @@ +package find + +import ( + "database/sql" + "fmt" + "strings" + + "github.com/dnote/cli/core" + "github.com/dnote/cli/infra" + "github.com/dnote/cli/log" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var example = ` + # find notes by a keyword + dnote find rpoplpush + + # find notes by multiple keywords + dnote find "building a heap" + + # find notes within a book + dnote find "merge sort" -b algorithm + ` + +var bookName string + +func preRun(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("Incorrect number of argument") + } + + return nil +} + +// NewCmd returns a new remove command +func NewCmd(ctx infra.DnoteCtx) *cobra.Command { + cmd := &cobra.Command{ + Use: "find", + Short: "Find notes by keywords", + Aliases: []string{"f"}, + Example: example, + PreRunE: preRun, + RunE: newRun(ctx), + } + + f := cmd.Flags() + f.StringVarP(&bookName, "book", "b", "", "book name to find notes in") + + return cmd +} + +// noteInfo is an information about the note to be printed on screen +type noteInfo struct { + RowID int + BookLabel string + Body string +} + +// formatFTSSnippet turns the matched snippet from a full text search +// into a format suitable for CLI output +func formatFTSSnippet(s string) (string, error) { + // first, strip all new lines + body := newLineReg.ReplaceAllString(s, " ") + + var format, buf strings.Builder + var args []interface{} + + toks := tokenize(body) + + for _, tok := range toks { + if tok.Kind == tokenKindHLBegin || tok.Kind == tokenKindEOL { + format.WriteString("%s") + args = append(args, buf.String()) + + buf.Reset() + } else if tok.Kind == tokenKindHLEnd { + format.WriteString("%s") + str := log.SprintfYellow("%s", buf.String()) + args = append(args, str) + + buf.Reset() + } else { + if err := buf.WriteByte(tok.Value); err != nil { + return "", errors.Wrap(err, "building string") + } + } + } + + return fmt.Sprintf(format.String(), args...), nil +} + +// escapePhrase escapes the user-supplied FTS keywords by wrapping each term around +// double quotations so that they are treated as 'strings' as defined by SQLite FTS5. +func escapePhrase(s string) (string, error) { + var b strings.Builder + + terms := strings.Fields(s) + + for idx, term := range terms { + if _, err := b.WriteString(fmt.Sprintf("\"%s\"", term)); err != nil { + return "", errors.Wrap(err, "writing string to builder") + } + + if idx != len(term)-1 { + if err := b.WriteByte(' '); err != nil { + return "", errors.Wrap(err, "writing space to builder") + } + } + } + + return b.String(), nil +} + +func doQuery(ctx infra.DnoteCtx, query, bookName string) (*sql.Rows, error) { + db := ctx.DB + + sql := `SELECT + notes.rowid, + books.label AS book_label, + snippet(note_fts, 0, '', '', '...', 28) + FROM note_fts + INNER JOIN notes ON notes.rowid = note_fts.rowid + INNER JOIN books ON notes.book_uuid = books.uuid + WHERE note_fts MATCH ?` + args := []interface{}{query} + + if bookName != "" { + sql = fmt.Sprintf("%s AND books.label = ?", sql) + args = append(args, bookName) + } + + rows, err := db.Query(sql, args...) + + return rows, err +} + +func newRun(ctx infra.DnoteCtx) core.RunEFunc { + return func(cmd *cobra.Command, args []string) error { + phrase, err := escapePhrase(args[0]) + if err != nil { + return errors.Wrap(err, "escaping phrase") + } + + rows, err := doQuery(ctx, phrase, bookName) + if err != nil { + return errors.Wrap(err, "querying notes") + } + defer rows.Close() + + infos := []noteInfo{} + for rows.Next() { + var info noteInfo + + var body string + err = rows.Scan(&info.RowID, &info.BookLabel, &body) + if err != nil { + return errors.Wrap(err, "scanning a row") + } + + body, err := formatFTSSnippet(body) + if err != nil { + return errors.Wrap(err, "formatting a body") + } + + info.Body = body + + infos = append(infos, info) + } + + for _, info := range infos { + bookLabel := log.SprintfYellow("(%s)", info.BookLabel) + rowid := log.SprintfYellow("(%d)", info.RowID) + + log.Plainf("%s %s %s\n", bookLabel, rowid, info.Body) + } + + return nil + } +} diff --git a/cmd/find/lexer.go b/cmd/find/lexer.go new file mode 100644 index 00000000..93fe0918 --- /dev/null +++ b/cmd/find/lexer.go @@ -0,0 +1,82 @@ +package find + +import ( + "regexp" +) + +var newLineReg = regexp.MustCompile(`\r?\n`) + +const ( + // tokenKindChar represents utf-8 character + tokenKindChar = iota + // tokenKindHLBegin represents a beginning of a highlighted section + tokenKindHLBegin + // tokenKindHLEnd represents an end of a highlighted section + tokenKindHLEnd + // tokenKindEOL represents an end of line + tokenKindEOL +) + +type token struct { + Value byte + Kind int +} + +// getNextIdx validates that the given index is within the range of the given string. +// If so, it returns the given index. Otherwise it returns -1. +func getNextIdx(candidate int, s string) int { + if candidate <= len(s)-1 { + return candidate + } + + return -1 +} + +// scanToken scans the given string for a token at the given index. It returns +// a token and the next index to look for a token. If the given string is exhausted, +// the next index will be -1. +func scanToken(idx int, s string) (token, int) { + if s[idx] == '<' { + if len(s)-idx >= 9 { + lookahead := 9 + candidate := s[idx : idx+lookahead] + + if candidate == "" { + nextIdx := getNextIdx(idx+lookahead, s) + return token{Kind: tokenKindHLBegin}, nextIdx + } + } + + if len(s)-idx >= 10 { + lookahead := 10 + candidate := s[idx : idx+lookahead] + + if candidate == "" { + nextIdx := getNextIdx(idx+lookahead, s) + return token{Kind: tokenKindHLEnd}, nextIdx + } + } + } + + nextIdx := getNextIdx(idx+1, s) + + return token{Value: s[idx], Kind: tokenKindChar}, nextIdx +} + +// tokenize lexically analyzes the given matched snippet from a full text search +// and builds a slice of tokens +func tokenize(s string) []token { + var ret []token + + idx := 0 + for idx != -1 { + var tok token + tok, idx = scanToken(idx, s) + + ret = append(ret, tok) + } + + ret = append(ret, token{Kind: tokenKindEOL}) + + return ret +} diff --git a/cmd/find/lexer_test.go b/cmd/find/lexer_test.go new file mode 100644 index 00000000..3e2fa754 --- /dev/null +++ b/cmd/find/lexer_test.go @@ -0,0 +1,213 @@ +package find + +import ( + "fmt" + "testing" + + "github.com/dnote/cli/testutils" +) + +func TestScanToken(t *testing.T) { + testCases := []struct { + input string + idx int + retTok token + retIdx int + }{ + { + input: "foo bar", + idx: 1, + retTok: token{Value: 'o', Kind: tokenKindChar}, + retIdx: 2, + }, + { + input: "foo bar", + idx: 6, + retTok: token{Value: 'r', Kind: tokenKindChar}, + retIdx: -1, + }, + { + input: "foo ", + idx: 4, + retTok: token{Value: '<', Kind: tokenKindChar}, + retIdx: 5, + }, + { + input: "foo ", + idx: 4, + retTok: token{Value: '<', Kind: tokenKindChar}, + retIdx: 5, + }, + { + input: "foo bar foo bar", + idx: 4, + retTok: token{Kind: tokenKindHLBegin}, + retIdx: 13, + }, + { + input: "foo bar foo bar", + idx: 4, + retTok: token{Kind: tokenKindHLBegin}, + retIdx: 13, + }, + { + input: "foo bar foo bar", + idx: 27, + retTok: token{Kind: tokenKindHLBegin}, + retIdx: 36, + }, + { + input: "foo bar foo bar", + idx: 13, + retTok: token{Value: 'b', Kind: tokenKindChar}, + retIdx: 14, + }, + { + input: "foo bar foo bar", + idx: 16, + retTok: token{Kind: tokenKindHLEnd}, + retIdx: 26, + }, + { + input: "tehl>", + idx: 0, + retTok: token{Value: '<', Kind: tokenKindChar}, + retIdx: 1, + }, + { + input: "tehl>", + idx: 4, + retTok: token{Kind: tokenKindHLBegin}, + retIdx: 13, + }, + { + input: "foo bar", + idx: 16, + retTok: token{Kind: tokenKindHLEnd}, + retIdx: -1, + }, + // user writes reserved token + { + input: "foo ", + idx: 4, + retTok: token{Kind: tokenKindHLBegin}, + retIdx: -1, + }, + } + + for tcIdx, tc := range testCases { + t.Run(fmt.Sprintf("test case %d", tcIdx), func(t *testing.T) { + tok, nextIdx := scanToken(tc.idx, tc.input) + + testutils.AssertEqual(t, nextIdx, tc.retIdx, "retIdx mismatch") + testutils.AssertDeepEqual(t, tok, tc.retTok, "retTok mismatch") + }) + } +} + +func TestTokenize(t *testing.T) { + testCases := []struct { + input string + tokens []token + }{ + { + input: "abc", + tokens: []token{ + token{ + Kind: tokenKindChar, + Value: 'a', + }, + token{ + Kind: tokenKindChar, + Value: 'b', + }, + token{ + Kind: tokenKindHLBegin, + }, + token{ + Kind: tokenKindChar, + Value: 'c', + }, + token{ + Kind: tokenKindHLEnd, + }, + token{ + Kind: tokenKindEOL, + }, + }, + }, + { + input: "abcd", + tokens: []token{ + token{ + Kind: tokenKindChar, + Value: 'a', + }, + token{ + Kind: tokenKindChar, + Value: 'b', + }, + token{ + Kind: tokenKindHLBegin, + }, + token{ + Kind: tokenKindChar, + Value: 'c', + }, + token{ + Kind: tokenKindHLEnd, + }, + token{ + Kind: tokenKindChar, + Value: 'd', + }, + token{ + Kind: tokenKindEOL, + }, + }, + }, + // user writes a reserved token + { + input: "", + tokens: []token{ + token{ + Kind: tokenKindHLBegin, + }, + token{ + Kind: tokenKindHLBegin, + }, + token{ + Kind: tokenKindHLEnd, + }, + token{ + Kind: tokenKindEOL, + }, + }, + }, + { + input: "", + tokens: []token{ + token{ + Kind: tokenKindHLBegin, + }, + token{ + Kind: tokenKindHLEnd, + }, + token{ + Kind: tokenKindHLEnd, + }, + token{ + Kind: tokenKindEOL, + }, + }, + }, + } + + for tcIdx, tc := range testCases { + t.Run(fmt.Sprintf("test case %d", tcIdx), func(t *testing.T) { + tokens := tokenize(tc.input) + + testutils.AssertDeepEqual(t, tokens, tc.tokens, "tokens mismatch") + }) + } +} diff --git a/cmd/ls/ls.go b/cmd/ls/ls.go index 930f0d4f..32a472ce 100644 --- a/cmd/ls/ls.go +++ b/cmd/ls/ls.go @@ -20,7 +20,7 @@ var example = ` dnote ls javascript ` -var deprecationWarning = `and "view" will replace it in v0.5.0. +var deprecationWarning = `and "view" will replace it in v1.0.0. Run "dnote view --help" for more information. ` @@ -48,6 +48,7 @@ func NewCmd(ctx infra.DnoteCtx) *cobra.Command { return cmd } +// NewRun returns a new run function for ls func NewRun(ctx infra.DnoteCtx) core.RunEFunc { return func(cmd *cobra.Command, args []string) error { if len(args) == 0 { @@ -75,8 +76,8 @@ type bookInfo struct { // noteInfo is an information about the note to be printed on screen type noteInfo struct { - ID int - Content string + RowID int + Body string } // getNewlineIdx returns the index of newline character in a string @@ -92,18 +93,18 @@ func getNewlineIdx(str string) int { return ret } -// formatContent returns an excerpt of the given raw note content and a boolean +// formatBody returns an excerpt of the given raw note content and a boolean // indicating if the returned string has been excertped -func formatContent(noteContent string) (string, bool) { - newlineIdx := getNewlineIdx(noteContent) +func formatBody(noteBody string) (string, bool) { + newlineIdx := getNewlineIdx(noteBody) if newlineIdx > -1 { - ret := strings.Trim(noteContent[0:newlineIdx], " ") + ret := strings.Trim(noteBody[0:newlineIdx], " ") return ret, true } - return strings.Trim(noteContent, " "), false + return strings.Trim(noteBody, " "), false } func printBooks(ctx infra.DnoteCtx) error { @@ -148,7 +149,7 @@ func printNotes(ctx infra.DnoteCtx, bookName string) error { return errors.Wrap(err, "querying the book") } - rows, err := db.Query(`SELECT id, content FROM notes WHERE book_uuid = ? ORDER BY added_on ASC;`, bookUUID) + rows, err := db.Query(`SELECT rowid, body FROM notes WHERE book_uuid = ? ORDER BY added_on ASC;`, bookUUID) if err != nil { return errors.Wrap(err, "querying notes") } @@ -157,7 +158,7 @@ func printNotes(ctx infra.DnoteCtx, bookName string) error { infos := []noteInfo{} for rows.Next() { var info noteInfo - err = rows.Scan(&info.ID, &info.Content) + err = rows.Scan(&info.RowID, &info.Body) if err != nil { return errors.Wrap(err, "scanning a row") } @@ -168,14 +169,14 @@ func printNotes(ctx infra.DnoteCtx, bookName string) error { log.Infof("on book %s\n", bookName) for _, info := range infos { - content, isExcerpt := formatContent(info.Content) + body, isExcerpt := formatBody(info.Body) - index := log.SprintfYellow("(%d)", info.ID) + rowid := log.SprintfYellow("(%d)", info.RowID) if isExcerpt { - content = fmt.Sprintf("%s %s", content, log.SprintfYellow("[---More---]")) + body = fmt.Sprintf("%s %s", body, log.SprintfYellow("[---More---]")) } - log.Plainf("%s %s\n", index, content) + log.Plainf("%s %s\n", rowid, body) } return nil diff --git a/cmd/remove/remove.go b/cmd/remove/remove.go index c40bd87c..b2e67dcc 100644 --- a/cmd/remove/remove.go +++ b/cmd/remove/remove.go @@ -52,9 +52,9 @@ func newRun(ctx infra.DnoteCtx) core.RunEFunc { } targetBook := args[0] - noteID := args[1] + noteRowID := args[1] - if err := removeNote(ctx, noteID, targetBook); err != nil { + if err := removeNote(ctx, noteRowID, targetBook); err != nil { return errors.Wrap(err, "removing the note") } @@ -62,7 +62,7 @@ func newRun(ctx infra.DnoteCtx) core.RunEFunc { } } -func removeNote(ctx infra.DnoteCtx, noteID, bookLabel string) error { +func removeNote(ctx infra.DnoteCtx, noteRowID, bookLabel string) error { db := ctx.DB bookUUID, err := core.GetBookUUID(ctx, bookLabel) @@ -71,15 +71,15 @@ func removeNote(ctx infra.DnoteCtx, noteID, bookLabel string) error { } var noteUUID, noteContent string - err = db.QueryRow("SELECT uuid, content FROM notes WHERE id = ? AND book_uuid = ?", noteID, bookUUID).Scan(¬eUUID, ¬eContent) + err = db.QueryRow("SELECT uuid, body FROM notes WHERE rowid = ? AND book_uuid = ?", noteRowID, bookUUID).Scan(¬eUUID, ¬eContent) if err == sql.ErrNoRows { - return errors.Errorf("note %s not found in the book '%s'", noteID, bookLabel) + return errors.Errorf("note %s not found in the book '%s'", noteRowID, bookLabel) } else if err != nil { return errors.Wrap(err, "querying the book") } // todo: multiline - log.Printf("content: \"%s\"\n", noteContent) + log.Printf("body: \"%s\"\n", noteContent) ok, err := utils.AskConfirmation("remove this note?", false) if err != nil { @@ -95,7 +95,7 @@ func removeNote(ctx infra.DnoteCtx, noteID, bookLabel string) error { return errors.Wrap(err, "beginning a transaction") } - if _, err = tx.Exec("UPDATE notes SET deleted = ?, dirty = ?, content = ? WHERE uuid = ? AND book_uuid = ?", true, true, "", noteUUID, bookUUID); err != nil { + if _, err = tx.Exec("UPDATE notes SET deleted = ?, dirty = ?, body = ? WHERE uuid = ? AND book_uuid = ?", true, true, "", noteUUID, bookUUID); err != nil { return errors.Wrap(err, "removing the note") } tx.Commit() @@ -127,7 +127,7 @@ func removeBook(ctx infra.DnoteCtx, bookLabel string) error { return errors.Wrap(err, "beginning a transaction") } - if _, err = tx.Exec("UPDATE notes SET deleted = ?, dirty = ?, content = ? WHERE book_uuid = ?", true, true, "", bookUUID); err != nil { + if _, err = tx.Exec("UPDATE notes SET deleted = ?, dirty = ?, body = ? WHERE book_uuid = ?", true, true, "", bookUUID); err != nil { return errors.Wrap(err, "removing notes in the book") } diff --git a/cmd/sync/sync.go b/cmd/sync/sync.go index 772b845a..6968e1c5 100644 --- a/cmd/sync/sync.go +++ b/cmd/sync/sync.go @@ -252,8 +252,8 @@ func mergeNote(tx *sql.Tx, serverNote client.SyncFragNote, localNote core.Note) // if the local copy is deleted, and the it was edited on the server, override with server values and mark it not dirty. if localNote.Deleted { - if _, err := tx.Exec("UPDATE notes SET usn = ?, book_uuid = ?, content = ?, edited_on = ?, deleted = ?, public = ?, dirty = ? WHERE uuid = ?", - serverNote.USN, serverNote.BookUUID, serverNote.Content, serverNote.EditedOn, serverNote.Deleted, serverNote.Public, false, serverNote.UUID); err != nil { + if _, err := tx.Exec("UPDATE notes SET usn = ?, book_uuid = ?, body = ?, edited_on = ?, deleted = ?, public = ?, dirty = ? WHERE uuid = ?", + serverNote.USN, serverNote.BookUUID, serverNote.Body, serverNote.EditedOn, serverNote.Deleted, serverNote.Public, false, serverNote.UUID); err != nil { return errors.Wrapf(err, "updating local note %s", serverNote.UUID) } @@ -261,8 +261,8 @@ func mergeNote(tx *sql.Tx, serverNote client.SyncFragNote, localNote core.Note) } // TODO: if the client copy is dirty, perform field-by-field merge and report conflict instead of overwriting - if _, err := tx.Exec("UPDATE notes SET usn = ?, book_uuid = ?, content = ?, edited_on = ?, deleted = ?, public = ? WHERE uuid = ?", - serverNote.USN, serverNote.BookUUID, serverNote.Content, serverNote.EditedOn, serverNote.Deleted, serverNote.Public, serverNote.UUID); err != nil { + if _, err := tx.Exec("UPDATE notes SET usn = ?, book_uuid = ?, body = ?, edited_on = ?, deleted = ?, public = ? WHERE uuid = ?", + serverNote.USN, serverNote.BookUUID, serverNote.Body, serverNote.EditedOn, serverNote.Deleted, serverNote.Public, serverNote.UUID); err != nil { return errors.Wrapf(err, "updating local note %s", serverNote.UUID) } @@ -279,7 +279,7 @@ func stepSyncNote(tx *sql.Tx, n client.SyncFragNote) error { // if note exists in the server and does not exist in the client, insert the note. if err == sql.ErrNoRows { - note := core.NewNote(n.UUID, n.BookUUID, n.Content, n.AddedOn, n.EditedOn, n.USN, n.Public, n.Deleted, false) + note := core.NewNote(n.UUID, n.BookUUID, n.Body, n.AddedOn, n.EditedOn, n.USN, n.Public, n.Deleted, false) if err := note.Insert(tx); err != nil { return errors.Wrapf(err, "inserting note with uuid %s", n.UUID) @@ -303,7 +303,7 @@ func fullSyncNote(tx *sql.Tx, n client.SyncFragNote) error { // if note exists in the server and does not exist in the client, insert the note. if err == sql.ErrNoRows { - note := core.NewNote(n.UUID, n.BookUUID, n.Content, n.AddedOn, n.EditedOn, n.USN, n.Public, n.Deleted, false) + note := core.NewNote(n.UUID, n.BookUUID, n.Body, n.AddedOn, n.EditedOn, n.USN, n.Public, n.Deleted, false) if err := note.Insert(tx); err != nil { return errors.Wrapf(err, "inserting note with uuid %s", n.UUID) @@ -506,13 +506,14 @@ func cleanLocalBooks(tx *sql.Tx, fullList *syncList) error { func fullSync(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) error { log.Debug("performing a full sync\n") + log.Info("resolving delta.") list, err := getSyncList(ctx, apiKey, 0) if err != nil { return errors.Wrap(err, "getting sync list") } - log.Infof("resolving delta (total %d).", list.getLength()) + fmt.Printf(" (total %d).", list.getLength()) // clean resources that are in erroneous states if err := cleanLocalNotes(tx, &list); err != nil { @@ -557,12 +558,14 @@ func fullSync(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) error { func stepSync(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string, afterUSN int) error { log.Debug("performing a step sync\n") + log.Info("resolving delta.") + list, err := getSyncList(ctx, apiKey, afterUSN) if err != nil { return errors.Wrap(err, "getting sync list") } - log.Infof("resolving delta (total %d).", list.getLength()) + fmt.Printf(" (total %d).", list.getLength()) for _, note := range list.Notes { if err := stepSyncNote(tx, note); err != nil { @@ -703,7 +706,7 @@ func sendBooks(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) (bool, error) { func sendNotes(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) (bool, error) { isBehind := false - rows, err := tx.Query("SELECT uuid, book_uuid, content, public, deleted, usn FROM notes WHERE dirty") + rows, err := tx.Query("SELECT uuid, book_uuid, body, public, deleted, usn FROM notes WHERE dirty") if err != nil { return isBehind, errors.Wrap(err, "getting syncable notes") } @@ -712,7 +715,7 @@ func sendNotes(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) (bool, error) { for rows.Next() { var note core.Note - if err = rows.Scan(¬e.UUID, ¬e.BookUUID, ¬e.Content, ¬e.Public, ¬e.Deleted, ¬e.USN); err != nil { + if err = rows.Scan(¬e.UUID, ¬e.BookUUID, ¬e.Body, ¬e.Public, ¬e.Deleted, ¬e.USN); err != nil { return isBehind, errors.Wrap(err, "scanning a syncable note") } @@ -731,7 +734,7 @@ func sendNotes(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) (bool, error) { continue } else { - resp, err := client.CreateNote(ctx, apiKey, note.BookUUID, note.Content) + resp, err := client.CreateNote(ctx, apiKey, note.BookUUID, note.Body) if err != nil { return isBehind, errors.Wrap(err, "creating a note") } @@ -764,7 +767,7 @@ func sendNotes(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) (bool, error) { respUSN = resp.Result.USN } else { - resp, err := client.UpdateNote(ctx, apiKey, note.UUID, note.BookUUID, note.Content, note.Public) + resp, err := client.UpdateNote(ctx, apiKey, note.UUID, note.BookUUID, note.Body, note.Public) if err != nil { return isBehind, errors.Wrap(err, "updating a note") } @@ -801,10 +804,12 @@ func sendNotes(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) (bool, error) { } func sendChanges(ctx infra.DnoteCtx, tx *sql.Tx, apiKey string) (bool, error) { + log.Info("sending changes.") + var delta int err := tx.QueryRow("SELECT (SELECT count(*) FROM notes WHERE dirty) + (SELECT count(*) FROM books WHERE dirty)").Scan(&delta) - log.Infof("sending changes (total %d).", delta) + fmt.Printf(" (total %d).", delta) behind1, err := sendBooks(ctx, tx, apiKey) if err != nil { diff --git a/cmd/sync/sync_test.go b/cmd/sync/sync_test.go index f4ffc913..9ca9b44a 100644 --- a/cmd/sync/sync_test.go +++ b/cmd/sync/sync_test.go @@ -157,17 +157,17 @@ func TestSyncDeleteNote(t *testing.T) { db := ctx.DB testutils.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label") - testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 content", 1541108743, false, true) - testutils.MustExec(t, "inserting n2 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b1UUID, 11, "n2 content", 1541108743, false, true) + testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, true) + testutils.MustExec(t, "inserting n2 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b1UUID, 11, "n2 body", 1541108743, false, true) var n1 core.Note testutils.MustScan(t, "getting n1 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", "n1-uuid"), - &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Content, &n1.Public, &n1.Deleted, &n1.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", "n1-uuid"), + &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Body, &n1.Public, &n1.Deleted, &n1.Dirty) var n2 core.Note testutils.MustScan(t, "getting n2 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", "n2-uuid"), - &n2.UUID, &n2.BookUUID, &n2.USN, &n2.AddedOn, &n2.EditedOn, &n2.Content, &n2.Public, &n2.Deleted, &n2.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", "n2-uuid"), + &n2.UUID, &n2.BookUUID, &n2.USN, &n2.AddedOn, &n2.EditedOn, &n2.Body, &n2.Public, &n2.Deleted, &n2.Dirty) // execute tx, err := db.Begin() @@ -193,19 +193,19 @@ func TestSyncDeleteNote(t *testing.T) { var n1Record core.Note testutils.MustScan(t, "getting n1 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n1.UUID), - &n1Record.UUID, &n1Record.BookUUID, &n1Record.USN, &n1Record.AddedOn, &n1Record.EditedOn, &n1Record.Content, &n1Record.Public, &n1Record.Deleted, &n1Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n1.UUID), + &n1Record.UUID, &n1Record.BookUUID, &n1Record.USN, &n1Record.AddedOn, &n1Record.EditedOn, &n1Record.Body, &n1Record.Public, &n1Record.Deleted, &n1Record.Dirty) var n2Record core.Note testutils.MustScan(t, "getting n2 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), - &n2Record.UUID, &n2Record.BookUUID, &n2Record.USN, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.Content, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), + &n2Record.UUID, &n2Record.BookUUID, &n2Record.USN, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.Body, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) testutils.AssertEqual(t, n1Record.UUID, n1.UUID, "n1 UUID mismatch for test case") testutils.AssertEqual(t, n1Record.BookUUID, n1.BookUUID, "n1 BookUUID mismatch for test case") testutils.AssertEqual(t, n1Record.USN, n1.USN, "n1 USN mismatch for test case") testutils.AssertEqual(t, n1Record.AddedOn, n1.AddedOn, "n1 AddedOn mismatch for test case") testutils.AssertEqual(t, n1Record.EditedOn, n1.EditedOn, "n1 EditedOn mismatch for test case") - testutils.AssertEqual(t, n1Record.Content, n1.Content, "n1 Content mismatch for test case") + testutils.AssertEqual(t, n1Record.Body, n1.Body, "n1 Body mismatch for test case") testutils.AssertEqual(t, n1Record.Public, n1.Public, "n1 Public mismatch for test case") testutils.AssertEqual(t, n1Record.Deleted, n1.Deleted, "n1 Deleted mismatch for test case") testutils.AssertEqual(t, n1Record.Dirty, n1.Dirty, "n1 Dirty mismatch for test case") @@ -215,7 +215,7 @@ func TestSyncDeleteNote(t *testing.T) { testutils.AssertEqual(t, n2Record.USN, n2.USN, "n2 USN mismatch for test case") testutils.AssertEqual(t, n2Record.AddedOn, n2.AddedOn, "n2 AddedOn mismatch for test case") testutils.AssertEqual(t, n2Record.EditedOn, n2.EditedOn, "n2 EditedOn mismatch for test case") - testutils.AssertEqual(t, n2Record.Content, n2.Content, "n2 Content mismatch for test case") + testutils.AssertEqual(t, n2Record.Body, n2.Body, "n2 Body mismatch for test case") testutils.AssertEqual(t, n2Record.Public, n2.Public, "n2 Public mismatch for test case") testutils.AssertEqual(t, n2Record.Deleted, n2.Deleted, "n2 Deleted mismatch for test case") testutils.AssertEqual(t, n2Record.Dirty, n2.Dirty, "n2 Dirty mismatch for test case") @@ -231,17 +231,17 @@ func TestSyncDeleteNote(t *testing.T) { db := ctx.DB testutils.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label") - testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 content", 1541108743, false, false) - testutils.MustExec(t, "inserting n2 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b1UUID, 11, "n2 content", 1541108743, false, false) + testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, false) + testutils.MustExec(t, "inserting n2 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b1UUID, 11, "n2 body", 1541108743, false, false) var n1 core.Note testutils.MustScan(t, "getting n1 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", "n1-uuid"), - &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Content, &n1.Public, &n1.Deleted, &n1.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", "n1-uuid"), + &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Body, &n1.Public, &n1.Deleted, &n1.Dirty) var n2 core.Note testutils.MustScan(t, "getting n2 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", "n2-uuid"), - &n2.UUID, &n2.BookUUID, &n2.USN, &n2.AddedOn, &n2.EditedOn, &n2.Content, &n2.Public, &n2.Deleted, &n2.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", "n2-uuid"), + &n2.UUID, &n2.BookUUID, &n2.USN, &n2.AddedOn, &n2.EditedOn, &n2.Body, &n2.Public, &n2.Deleted, &n2.Dirty) // execute tx, err := db.Begin() @@ -266,15 +266,15 @@ func TestSyncDeleteNote(t *testing.T) { var n2Record core.Note testutils.MustScan(t, "getting n2 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), - &n2Record.UUID, &n2Record.BookUUID, &n2Record.USN, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.Content, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), + &n2Record.UUID, &n2Record.BookUUID, &n2Record.USN, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.Body, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) testutils.AssertEqual(t, n2Record.UUID, n2.UUID, "n2 UUID mismatch for test case") testutils.AssertEqual(t, n2Record.BookUUID, n2.BookUUID, "n2 BookUUID mismatch for test case") testutils.AssertEqual(t, n2Record.USN, n2.USN, "n2 USN mismatch for test case") testutils.AssertEqual(t, n2Record.AddedOn, n2.AddedOn, "n2 AddedOn mismatch for test case") testutils.AssertEqual(t, n2Record.EditedOn, n2.EditedOn, "n2 EditedOn mismatch for test case") - testutils.AssertEqual(t, n2Record.Content, n2.Content, "n2 Content mismatch for test case") + testutils.AssertEqual(t, n2Record.Body, n2.Body, "n2 Body mismatch for test case") testutils.AssertEqual(t, n2Record.Public, n2.Public, "n2 Public mismatch for test case") testutils.AssertEqual(t, n2Record.Deleted, n2.Deleted, "n2 Deleted mismatch for test case") testutils.AssertEqual(t, n2Record.Dirty, n2.Dirty, "n2 Dirty mismatch for test case") @@ -337,7 +337,7 @@ func TestSyncDeleteBook(t *testing.T) { db := ctx.DB testutils.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", b1UUID, "b1-label", 12, true) - testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 content", 1541108743, false, true) + testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, true) var b1 core.Book testutils.MustScan(t, "getting b1 for test case", @@ -345,8 +345,8 @@ func TestSyncDeleteBook(t *testing.T) { &b1.UUID, &b1.Label, &b1.USN, &b1.Dirty) var n1 core.Note testutils.MustScan(t, "getting n1 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", "n1-uuid"), - &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Content, &n1.Public, &n1.Deleted, &n1.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", "n1-uuid"), + &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Body, &n1.Public, &n1.Deleted, &n1.Dirty) // execute tx, err := db.Begin() @@ -376,8 +376,8 @@ func TestSyncDeleteBook(t *testing.T) { &b1Record.UUID, &b1Record.Label, &b1Record.USN, &b1Record.Dirty) var n1Record core.Note testutils.MustScan(t, "getting n1 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n1.UUID), - &n1Record.UUID, &n1Record.BookUUID, &n1Record.USN, &n1Record.AddedOn, &n1Record.EditedOn, &n1Record.Content, &n1Record.Public, &n1Record.Deleted, &n1Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n1.UUID), + &n1Record.UUID, &n1Record.BookUUID, &n1Record.USN, &n1Record.AddedOn, &n1Record.EditedOn, &n1Record.Body, &n1Record.Public, &n1Record.Deleted, &n1Record.Dirty) testutils.AssertEqual(t, b1Record.UUID, b1.UUID, "b1 UUID mismatch for test case") testutils.AssertEqual(t, b1Record.Label, b1.Label, "b1 Label mismatch for test case") @@ -389,7 +389,7 @@ func TestSyncDeleteBook(t *testing.T) { testutils.AssertEqual(t, n1Record.USN, n1.USN, "n1 USN mismatch for test case") testutils.AssertEqual(t, n1Record.AddedOn, n1.AddedOn, "n1 AddedOn mismatch for test case") testutils.AssertEqual(t, n1Record.EditedOn, n1.EditedOn, "n1 EditedOn mismatch for test case") - testutils.AssertEqual(t, n1Record.Content, n1.Content, "n1 Content mismatch for test case") + testutils.AssertEqual(t, n1Record.Body, n1.Body, "n1 Body mismatch for test case") testutils.AssertEqual(t, n1Record.Public, n1.Public, "n1 Public mismatch for test case") testutils.AssertEqual(t, n1Record.Deleted, n1.Deleted, "n1 Deleted mismatch for test case") testutils.AssertEqual(t, n1Record.Dirty, n1.Dirty, "n1 Dirty mismatch for test case") @@ -406,9 +406,9 @@ func TestSyncDeleteBook(t *testing.T) { db := ctx.DB testutils.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label") - testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 content", 1541108743, false, false) + testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, false) testutils.MustExec(t, "inserting b2 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b2UUID, "b2-label") - testutils.MustExec(t, "inserting n2 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b2UUID, 11, "n2 content", 1541108743, false, false) + testutils.MustExec(t, "inserting n2 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b2UUID, 11, "n2 body", 1541108743, false, false) var b2 core.Book testutils.MustScan(t, "getting b2 for test case", @@ -416,8 +416,8 @@ func TestSyncDeleteBook(t *testing.T) { &b2.UUID, &b2.Label, &b2.USN, &b2.Dirty) var n2 core.Note testutils.MustScan(t, "getting n2 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", "n2-uuid"), - &n2.UUID, &n2.BookUUID, &n2.USN, &n2.AddedOn, &n2.EditedOn, &n2.Content, &n2.Public, &n2.Deleted, &n2.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", "n2-uuid"), + &n2.UUID, &n2.BookUUID, &n2.USN, &n2.AddedOn, &n2.EditedOn, &n2.Body, &n2.Public, &n2.Deleted, &n2.Dirty) // execute tx, err := db.Begin() @@ -446,8 +446,8 @@ func TestSyncDeleteBook(t *testing.T) { &b2Record.UUID, &b2Record.Label, &b2Record.USN, &b2Record.Dirty) var n2Record core.Note testutils.MustScan(t, "getting n2 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), - &n2Record.UUID, &n2Record.BookUUID, &n2Record.USN, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.Content, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), + &n2Record.UUID, &n2Record.BookUUID, &n2Record.USN, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.Body, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) testutils.AssertEqual(t, b2Record.UUID, b2.UUID, "b2 UUID mismatch for test case") testutils.AssertEqual(t, b2Record.Label, b2.Label, "b2 Label mismatch for test case") @@ -459,7 +459,7 @@ func TestSyncDeleteBook(t *testing.T) { testutils.AssertEqual(t, n2Record.USN, n2.USN, "n2 USN mismatch for test case") testutils.AssertEqual(t, n2Record.AddedOn, n2.AddedOn, "n2 AddedOn mismatch for test case") testutils.AssertEqual(t, n2Record.EditedOn, n2.EditedOn, "n2 EditedOn mismatch for test case") - testutils.AssertEqual(t, n2Record.Content, n2.Content, "n2 Content mismatch for test case") + testutils.AssertEqual(t, n2Record.Body, n2.Body, "n2 Body mismatch for test case") testutils.AssertEqual(t, n2Record.Public, n2.Public, "n2 Public mismatch for test case") testutils.AssertEqual(t, n2Record.Deleted, n2.Deleted, "n2 Deleted mismatch for test case") testutils.AssertEqual(t, n2Record.Dirty, n2.Dirty, "n2 Dirty mismatch for test case") @@ -475,7 +475,7 @@ func TestSyncDeleteBook(t *testing.T) { db := ctx.DB testutils.MustExec(t, "inserting b1 for test case %d", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label") - testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 content", 1541108743, false, true) + testutils.MustExec(t, "inserting n1 for test case %d", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, true) // execute tx, err := db.Begin() @@ -503,8 +503,8 @@ func TestSyncDeleteBook(t *testing.T) { &b1Record.UUID, &b1Record.Label, &b1Record.USN, &b1Record.Dirty) var n1Record core.Note testutils.MustScan(t, "getting n1 for test case", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, content,deleted, dirty FROM notes WHERE uuid = ?", "n1-uuid"), - &n1Record.UUID, &n1Record.BookUUID, &n1Record.USN, &n1Record.AddedOn, &n1Record.Content, &n1Record.Deleted, &n1Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, body,deleted, dirty FROM notes WHERE uuid = ?", "n1-uuid"), + &n1Record.UUID, &n1Record.BookUUID, &n1Record.USN, &n1Record.AddedOn, &n1Record.Body, &n1Record.Deleted, &n1Record.Dirty) testutils.AssertEqual(t, b1Record.UUID, b1UUID, "b1 UUID mismatch for test case") testutils.AssertEqual(t, b1Record.Label, "b1-label", "b1 Label mismatch for test case") @@ -514,7 +514,7 @@ func TestSyncDeleteBook(t *testing.T) { testutils.AssertEqual(t, n1Record.BookUUID, b1UUID, "n1 BookUUID mismatch for test case") testutils.AssertEqual(t, n1Record.USN, 10, "n1 USN mismatch for test case") testutils.AssertEqual(t, n1Record.AddedOn, int64(1541108743), "n1 AddedOn mismatch for test case") - testutils.AssertEqual(t, n1Record.Content, "n1 content", "n1 Content mismatch for test case") + testutils.AssertEqual(t, n1Record.Body, "n1 body", "n1 Body mismatch for test case") testutils.AssertEqual(t, n1Record.Deleted, false, "n1 Deleted mismatch for test case") testutils.AssertEqual(t, n1Record.Dirty, true, "n1 Dirty mismatch for test case") }) @@ -543,7 +543,7 @@ func TestFullSyncNote(t *testing.T) { USN: 128, AddedOn: 1541232118, EditedOn: 1541219321, - Content: "n1-content", + Body: "n1-body", Public: true, Deleted: false, } @@ -565,15 +565,15 @@ func TestFullSyncNote(t *testing.T) { var n1 core.Note testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n.UUID), - &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Content, &n1.Public, &n1.Deleted, &n1.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n.UUID), + &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Body, &n1.Public, &n1.Deleted, &n1.Dirty) testutils.AssertEqual(t, n1.UUID, n.UUID, "n1 UUID mismatch") testutils.AssertEqual(t, n1.BookUUID, n.BookUUID, "n1 BookUUID mismatch") testutils.AssertEqual(t, n1.USN, n.USN, "n1 USN mismatch") testutils.AssertEqual(t, n1.AddedOn, n.AddedOn, "n1 AddedOn mismatch") testutils.AssertEqual(t, n1.EditedOn, n.EditedOn, "n1 EditedOn mismatch") - testutils.AssertEqual(t, n1.Content, n.Content, "n1 Content mismatch") + testutils.AssertEqual(t, n1.Body, n.Body, "n1 Body mismatch") testutils.AssertEqual(t, n1.Public, n.Public, "n1 Public mismatch") testutils.AssertEqual(t, n1.Deleted, n.Deleted, "n1 Deleted mismatch") testutils.AssertEqual(t, n1.Dirty, false, "n1 Dirty mismatch") @@ -587,21 +587,21 @@ func TestFullSyncNote(t *testing.T) { addedOn int64 clientUSN int clientEditedOn int64 - clientContent string + clientBody string clientPublic bool clientDeleted bool clientBookUUID string clientDirty bool serverUSN int serverEditedOn int64 - serverContent string + serverBody string serverPublic bool serverDeleted bool serverBookUUID string expectedUSN int expectedAddedOn int64 expectedEditedOn int64 - expectedContent string + expectedBody string expectedPublic bool expectedDeleted bool expectedBookUUID string @@ -612,21 +612,21 @@ func TestFullSyncNote(t *testing.T) { clientDirty: true, clientUSN: 1, clientEditedOn: 0, - clientContent: "n1 content", + clientBody: "n1 body", clientPublic: false, clientDeleted: false, clientBookUUID: b1UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content edited", + serverBody: "n1 body edited", serverPublic: true, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content edited", + expectedBody: "n1 body edited", expectedPublic: true, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -637,21 +637,21 @@ func TestFullSyncNote(t *testing.T) { clientDirty: true, clientUSN: 1, clientEditedOn: 0, - clientContent: "", + clientBody: "", clientPublic: false, clientDeleted: true, clientBookUUID: b1UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content server", + serverBody: "n1 body server", serverPublic: false, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content server", + expectedBody: "n1 body server", expectedPublic: false, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -662,21 +662,21 @@ func TestFullSyncNote(t *testing.T) { clientDirty: false, clientUSN: 1, clientEditedOn: 0, - clientContent: "n1 content", + clientBody: "n1 body", clientPublic: false, clientDeleted: false, clientBookUUID: b1UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content edited", + serverBody: "n1 body edited", serverPublic: true, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content edited", + expectedBody: "n1 body edited", expectedPublic: true, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -687,21 +687,21 @@ func TestFullSyncNote(t *testing.T) { clientDirty: true, clientUSN: 21, clientEditedOn: 1541219321, - clientContent: "n1 content", + clientBody: "n1 body", clientPublic: false, clientDeleted: false, clientBookUUID: b2UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content", + serverBody: "n1 body", serverPublic: false, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content", + expectedBody: "n1 body", expectedPublic: false, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -714,21 +714,21 @@ func TestFullSyncNote(t *testing.T) { clientDirty: true, clientUSN: 21, clientEditedOn: 1541219320, - clientContent: "n1 content client", + clientBody: "n1 body client", clientPublic: false, clientDeleted: false, clientBookUUID: b2UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content server", + serverBody: "n1 body server", serverPublic: true, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219320, - expectedContent: "n1 content client", + expectedBody: "n1 body client", expectedPublic: false, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -747,7 +747,7 @@ func TestFullSyncNote(t *testing.T) { testutils.MustExec(t, fmt.Sprintf("inserting b1 for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label") testutils.MustExec(t, fmt.Sprintf("inserting b2 for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b2UUID, "b2-label") n1UUID := utils.GenerateUUID() - testutils.MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, tc.clientBookUUID, tc.clientUSN, tc.addedOn, tc.clientEditedOn, tc.clientContent, tc.clientPublic, tc.clientDeleted, tc.clientDirty) + testutils.MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, tc.clientBookUUID, tc.clientUSN, tc.addedOn, tc.clientEditedOn, tc.clientBody, tc.clientPublic, tc.clientDeleted, tc.clientDirty) // execute tx, err := db.Begin() @@ -762,7 +762,7 @@ func TestFullSyncNote(t *testing.T) { USN: tc.serverUSN, AddedOn: tc.addedOn, EditedOn: tc.serverEditedOn, - Content: tc.serverContent, + Body: tc.serverBody, Public: tc.serverPublic, Deleted: tc.serverDeleted, } @@ -784,15 +784,15 @@ func TestFullSyncNote(t *testing.T) { var n1 core.Note testutils.MustScan(t, fmt.Sprintf("getting n1 for test case %d", idx), - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n.UUID), - &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Content, &n1.Public, &n1.Deleted, &n1.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n.UUID), + &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Body, &n1.Public, &n1.Deleted, &n1.Dirty) testutils.AssertEqual(t, n1.UUID, n.UUID, fmt.Sprintf("n1 UUID mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.BookUUID, tc.expectedBookUUID, fmt.Sprintf("n1 BookUUID mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.USN, tc.expectedUSN, fmt.Sprintf("n1 USN mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.AddedOn, tc.expectedAddedOn, fmt.Sprintf("n1 AddedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.EditedOn, tc.expectedEditedOn, fmt.Sprintf("n1 EditedOn mismatch for test case %d", idx)) - testutils.AssertEqual(t, n1.Content, tc.expectedContent, fmt.Sprintf("n1 Content mismatch for test case %d", idx)) + testutils.AssertEqual(t, n1.Body, tc.expectedBody, fmt.Sprintf("n1 Body mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.Public, tc.expectedPublic, fmt.Sprintf("n1 Public mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.Deleted, tc.expectedDeleted, fmt.Sprintf("n1 Deleted mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.Dirty, tc.expectedDirty, fmt.Sprintf("n1 Dirty mismatch for test case %d", idx)) @@ -1020,7 +1020,7 @@ func TestStepSyncNote(t *testing.T) { USN: 128, AddedOn: 1541232118, EditedOn: 1541219321, - Content: "n1-content", + Body: "n1-body", Public: true, Deleted: false, } @@ -1042,15 +1042,15 @@ func TestStepSyncNote(t *testing.T) { var n1 core.Note testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n.UUID), - &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Content, &n1.Public, &n1.Deleted, &n1.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n.UUID), + &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Body, &n1.Public, &n1.Deleted, &n1.Dirty) testutils.AssertEqual(t, n1.UUID, n.UUID, "n1 UUID mismatch") testutils.AssertEqual(t, n1.BookUUID, n.BookUUID, "n1 BookUUID mismatch") testutils.AssertEqual(t, n1.USN, n.USN, "n1 USN mismatch") testutils.AssertEqual(t, n1.AddedOn, n.AddedOn, "n1 AddedOn mismatch") testutils.AssertEqual(t, n1.EditedOn, n.EditedOn, "n1 EditedOn mismatch") - testutils.AssertEqual(t, n1.Content, n.Content, "n1 Content mismatch") + testutils.AssertEqual(t, n1.Body, n.Body, "n1 Body mismatch") testutils.AssertEqual(t, n1.Public, n.Public, "n1 Public mismatch") testutils.AssertEqual(t, n1.Deleted, n.Deleted, "n1 Deleted mismatch") testutils.AssertEqual(t, n1.Dirty, false, "n1 Dirty mismatch") @@ -1064,21 +1064,21 @@ func TestStepSyncNote(t *testing.T) { addedOn int64 clientUSN int clientEditedOn int64 - clientContent string + clientBody string clientPublic bool clientDeleted bool clientBookUUID string clientDirty bool serverUSN int serverEditedOn int64 - serverContent string + serverBody string serverPublic bool serverDeleted bool serverBookUUID string expectedUSN int expectedAddedOn int64 expectedEditedOn int64 - expectedContent string + expectedBody string expectedPublic bool expectedDeleted bool expectedBookUUID string @@ -1088,21 +1088,21 @@ func TestStepSyncNote(t *testing.T) { clientDirty: true, clientUSN: 1, clientEditedOn: 0, - clientContent: "n1 content", + clientBody: "n1 body", clientPublic: false, clientDeleted: false, clientBookUUID: b1UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content edited", + serverBody: "n1 body edited", serverPublic: true, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content edited", + expectedBody: "n1 body edited", expectedPublic: true, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -1113,21 +1113,21 @@ func TestStepSyncNote(t *testing.T) { clientDirty: true, clientUSN: 1, clientEditedOn: 1541219321, - clientContent: "", + clientBody: "", clientPublic: false, clientDeleted: true, clientBookUUID: b1UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content edited", + serverBody: "n1 body edited", serverPublic: false, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content edited", + expectedBody: "n1 body edited", expectedPublic: false, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -1137,21 +1137,21 @@ func TestStepSyncNote(t *testing.T) { clientDirty: false, clientUSN: 1, clientEditedOn: 0, - clientContent: "n1 content", + clientBody: "n1 body", clientPublic: false, clientDeleted: false, clientBookUUID: b1UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content edited", + serverBody: "n1 body edited", serverPublic: true, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content edited", + expectedBody: "n1 body edited", expectedPublic: true, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -1170,7 +1170,7 @@ func TestStepSyncNote(t *testing.T) { testutils.MustExec(t, fmt.Sprintf("inserting b1 for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1-label") testutils.MustExec(t, fmt.Sprintf("inserting b2 for test case %d", idx), db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b2UUID, "b2-label") n1UUID := utils.GenerateUUID() - testutils.MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, tc.clientBookUUID, tc.clientUSN, tc.addedOn, tc.clientEditedOn, tc.clientContent, tc.clientPublic, tc.clientDeleted, tc.clientDirty) + testutils.MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, tc.clientBookUUID, tc.clientUSN, tc.addedOn, tc.clientEditedOn, tc.clientBody, tc.clientPublic, tc.clientDeleted, tc.clientDirty) // execute tx, err := db.Begin() @@ -1185,7 +1185,7 @@ func TestStepSyncNote(t *testing.T) { USN: tc.serverUSN, AddedOn: tc.addedOn, EditedOn: tc.serverEditedOn, - Content: tc.serverContent, + Body: tc.serverBody, Public: tc.serverPublic, Deleted: tc.serverDeleted, } @@ -1207,15 +1207,15 @@ func TestStepSyncNote(t *testing.T) { var n1 core.Note testutils.MustScan(t, fmt.Sprintf("getting n1 for test case %d", idx), - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n.UUID), - &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Content, &n1.Public, &n1.Deleted, &n1.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n.UUID), + &n1.UUID, &n1.BookUUID, &n1.USN, &n1.AddedOn, &n1.EditedOn, &n1.Body, &n1.Public, &n1.Deleted, &n1.Dirty) testutils.AssertEqual(t, n1.UUID, n.UUID, fmt.Sprintf("n1 UUID mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.BookUUID, tc.expectedBookUUID, fmt.Sprintf("n1 BookUUID mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.USN, tc.expectedUSN, fmt.Sprintf("n1 USN mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.AddedOn, tc.expectedAddedOn, fmt.Sprintf("n1 AddedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.EditedOn, tc.expectedEditedOn, fmt.Sprintf("n1 EditedOn mismatch for test case %d", idx)) - testutils.AssertEqual(t, n1.Content, tc.expectedContent, fmt.Sprintf("n1 Content mismatch for test case %d", idx)) + testutils.AssertEqual(t, n1.Body, tc.expectedBody, fmt.Sprintf("n1 Body mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.Public, tc.expectedPublic, fmt.Sprintf("n1 Public mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.Deleted, tc.expectedDeleted, fmt.Sprintf("n1 Deleted mismatch for test case %d", idx)) testutils.AssertEqual(t, n1.Dirty, tc.expectedDirty, fmt.Sprintf("n1 Dirty mismatch for test case %d", idx)) @@ -1833,14 +1833,14 @@ func TestSendBooks(t *testing.T) { testutils.MustExec(t, "inserting b8", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", "b8-uuid", "b8-label", 18, false, true) // some random notes - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 10, "n1 content", 1541108743, false, false) - testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", "b5-uuid", 10, "n2 content", 1541108743, false, false) - testutils.MustExec(t, "inserting n3", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n3-uuid", "b6-uuid", 10, "n3 content", 1541108743, false, false) - testutils.MustExec(t, "inserting n4", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n4-uuid", "b7-uuid", 10, "n4 content", 1541108743, false, false) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 10, "n1 body", 1541108743, false, false) + testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", "b5-uuid", 10, "n2 body", 1541108743, false, false) + testutils.MustExec(t, "inserting n3", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n3-uuid", "b6-uuid", 10, "n3 body", 1541108743, false, false) + testutils.MustExec(t, "inserting n4", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n4-uuid", "b7-uuid", 10, "n4 body", 1541108743, false, false) // notes that belong to the created book. Their book_uuid should be updated. - testutils.MustExec(t, "inserting n5", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n5-uuid", "b3-uuid", 10, "n5 content", 1541108743, false, false) - testutils.MustExec(t, "inserting n6", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n6-uuid", "b3-uuid", 10, "n6 content", 1541108743, false, false) - testutils.MustExec(t, "inserting n7", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n7-uuid", "b4-uuid", 10, "n7 content", 1541108743, false, false) + testutils.MustExec(t, "inserting n5", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n5-uuid", "b3-uuid", 10, "n5 body", 1541108743, false, false) + testutils.MustExec(t, "inserting n6", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n6-uuid", "b3-uuid", 10, "n6 body", 1541108743, false, false) + testutils.MustExec(t, "inserting n7", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n7-uuid", "b4-uuid", 10, "n7 body", 1541108743, false, false) var createdLabels []string var updatesUUIDs []string @@ -1865,7 +1865,7 @@ func TestSendBooks(t *testing.T) { }, } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -1879,14 +1879,14 @@ func TestSendBooks(t *testing.T) { uuid := p[3] updatesUUIDs = append(updatesUUIDs, uuid) - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") w.Write([]byte("{}")) return } else if r.Method == "DELETE" { uuid := p[3] deletedUUIDs = append(deletedUUIDs, uuid) - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") w.Write([]byte("{}")) return } @@ -1946,13 +1946,13 @@ func TestSendBooks(t *testing.T) { testutils.AssertEqual(t, b8.UUID, "b8-uuid", "b8 UUID mismatch") var n1, n2, n3, n4, n5, n6, n7 core.Note - testutils.MustScan(t, "getting n1", db.QueryRow("SELECT book_uuid FROM notes WHERE content = ?", "n1 content"), &n1.BookUUID) - testutils.MustScan(t, "getting n2", db.QueryRow("SELECT book_uuid FROM notes WHERE content = ?", "n2 content"), &n2.BookUUID) - testutils.MustScan(t, "getting n3", db.QueryRow("SELECT book_uuid FROM notes WHERE content = ?", "n3 content"), &n3.BookUUID) - testutils.MustScan(t, "getting n4", db.QueryRow("SELECT book_uuid FROM notes WHERE content = ?", "n4 content"), &n4.BookUUID) - testutils.MustScan(t, "getting n5", db.QueryRow("SELECT book_uuid FROM notes WHERE content = ?", "n5 content"), &n5.BookUUID) - testutils.MustScan(t, "getting n6", db.QueryRow("SELECT book_uuid FROM notes WHERE content = ?", "n6 content"), &n6.BookUUID) - testutils.MustScan(t, "getting n7", db.QueryRow("SELECT book_uuid FROM notes WHERE content = ?", "n7 content"), &n7.BookUUID) + testutils.MustScan(t, "getting n1", db.QueryRow("SELECT book_uuid FROM notes WHERE body = ?", "n1 body"), &n1.BookUUID) + testutils.MustScan(t, "getting n2", db.QueryRow("SELECT book_uuid FROM notes WHERE body = ?", "n2 body"), &n2.BookUUID) + testutils.MustScan(t, "getting n3", db.QueryRow("SELECT book_uuid FROM notes WHERE body = ?", "n3 body"), &n3.BookUUID) + testutils.MustScan(t, "getting n4", db.QueryRow("SELECT book_uuid FROM notes WHERE body = ?", "n4 body"), &n4.BookUUID) + testutils.MustScan(t, "getting n5", db.QueryRow("SELECT book_uuid FROM notes WHERE body = ?", "n5 body"), &n5.BookUUID) + testutils.MustScan(t, "getting n6", db.QueryRow("SELECT book_uuid FROM notes WHERE body = ?", "n6 body"), &n6.BookUUID) + testutils.MustScan(t, "getting n7", db.QueryRow("SELECT book_uuid FROM notes WHERE body = ?", "n7 body"), &n7.BookUUID) testutils.AssertEqual(t, n1.BookUUID, "b1-uuid", "n1 bookUUID mismatch") testutils.AssertEqual(t, n2.BookUUID, "b5-uuid", "n2 bookUUID mismatch") testutils.AssertEqual(t, n3.BookUUID, "b6-uuid", "n3 bookUUID mismatch") @@ -1979,7 +1979,7 @@ func TestSendBooks_isBehind(t *testing.T) { }, } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -1996,7 +1996,7 @@ func TestSendBooks_isBehind(t *testing.T) { }, } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -2009,7 +2009,7 @@ func TestSendBooks_isBehind(t *testing.T) { }, } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -2179,27 +2179,27 @@ func TestSendNotes(t *testing.T) { testutils.MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", b1UUID, "b1-label", 1, false, false) // should be ignored - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1-content", 1541108743, false, false) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1-body", 1541108743, false, false) // should be created - testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b1UUID, 0, "n2-content", 1541108743, false, true) + testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b1UUID, 0, "n2-body", 1541108743, false, true) // should be updated - testutils.MustExec(t, "inserting n3", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n3-uuid", b1UUID, 11, "n3-content", 1541108743, false, true) + testutils.MustExec(t, "inserting n3", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n3-uuid", b1UUID, 11, "n3-body", 1541108743, false, true) // should be only expunged locally without syncing to server - testutils.MustExec(t, "inserting n4", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n4-uuid", b1UUID, 0, "n4-content", 1541108743, true, true) + testutils.MustExec(t, "inserting n4", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n4-uuid", b1UUID, 0, "n4-body", 1541108743, true, true) // should be deleted - testutils.MustExec(t, "inserting n5", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n5-uuid", b1UUID, 17, "n5-content", 1541108743, true, true) + testutils.MustExec(t, "inserting n5", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n5-uuid", b1UUID, 17, "n5-body", 1541108743, true, true) // should be created - testutils.MustExec(t, "inserting n6", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n6-uuid", b1UUID, 0, "n6-content", 1541108743, false, true) + testutils.MustExec(t, "inserting n6", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n6-uuid", b1UUID, 0, "n6-body", 1541108743, false, true) // should be ignored - testutils.MustExec(t, "inserting n7", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n7-uuid", b1UUID, 12, "n7-content", 1541108743, false, false) + testutils.MustExec(t, "inserting n7", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n7-uuid", b1UUID, 12, "n7-body", 1541108743, false, false) // should be updated - testutils.MustExec(t, "inserting n8", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n8-uuid", b1UUID, 17, "n8-content", 1541108743, false, true) + testutils.MustExec(t, "inserting n8", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n8-uuid", b1UUID, 17, "n8-body", 1541108743, false, true) // should be deleted - testutils.MustExec(t, "inserting n9", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n9-uuid", b1UUID, 17, "n9-content", 1541108743, true, true) + testutils.MustExec(t, "inserting n9", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n9-uuid", b1UUID, 17, "n9-body", 1541108743, true, true) // should be created - testutils.MustExec(t, "inserting n10", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n10-uuid", b1UUID, 0, "n10-content", 1541108743, false, true) + testutils.MustExec(t, "inserting n10", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n10-uuid", b1UUID, 0, "n10-body", 1541108743, false, true) - var createdContents []string + var createdBodys []string var updatedUUIDs []string var deletedUUIDs []string @@ -2214,15 +2214,15 @@ func TestSendNotes(t *testing.T) { return } - createdContents = append(createdContents, payload.Content) + createdBodys = append(createdBodys, payload.Body) resp := client.CreateNoteResp{ Result: client.RespNote{ - UUID: fmt.Sprintf("server-%s-uuid", payload.Content), + UUID: fmt.Sprintf("server-%s-uuid", payload.Body), }, } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -2236,14 +2236,14 @@ func TestSendNotes(t *testing.T) { uuid := p[3] updatedUUIDs = append(updatedUUIDs, uuid) - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") w.Write([]byte("{}")) return } else if r.Method == "DELETE" { uuid := p[3] deletedUUIDs = append(deletedUUIDs, uuid) - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") w.Write([]byte("{}")) return } @@ -2269,11 +2269,11 @@ func TestSendNotes(t *testing.T) { tx.Commit() // test - sort.SliceStable(createdContents, func(i, j int) bool { - return strings.Compare(createdContents[i], createdContents[j]) < 0 + sort.SliceStable(createdBodys, func(i, j int) bool { + return strings.Compare(createdBodys[i], createdBodys[j]) < 0 }) - testutils.AssertDeepEqual(t, createdContents, []string{"n10-content", "n2-content", "n6-content"}, "createdContents mismatch") + testutils.AssertDeepEqual(t, createdBodys, []string{"n10-body", "n2-body", "n6-body"}, "createdBodys mismatch") testutils.AssertDeepEqual(t, updatedUUIDs, []string{"n3-uuid", "n8-uuid"}, "updatedUUIDs mismatch") testutils.AssertDeepEqual(t, deletedUUIDs, []string{"n5-uuid", "n9-uuid"}, "deletedUUIDs mismatch") @@ -2282,13 +2282,13 @@ func TestSendNotes(t *testing.T) { testutils.AssertEqualf(t, noteCount, 7, "note count mismatch") var n1, n2, n3, n6, n7, n8, n10 core.Note - testutils.MustScan(t, "getting n1", db.QueryRow("SELECT uuid, dirty FROM notes WHERE content = ?", "n1-content"), &n1.UUID, &n1.Dirty) - testutils.MustScan(t, "getting n2", db.QueryRow("SELECT uuid, dirty FROM notes WHERE content = ?", "n2-content"), &n2.UUID, &n2.Dirty) - testutils.MustScan(t, "getting n3", db.QueryRow("SELECT uuid, dirty FROM notes WHERE content = ?", "n3-content"), &n3.UUID, &n3.Dirty) - testutils.MustScan(t, "getting n6", db.QueryRow("SELECT uuid, dirty FROM notes WHERE content = ?", "n6-content"), &n6.UUID, &n6.Dirty) - testutils.MustScan(t, "getting n7", db.QueryRow("SELECT uuid, dirty FROM notes WHERE content = ?", "n7-content"), &n7.UUID, &n7.Dirty) - testutils.MustScan(t, "getting n8", db.QueryRow("SELECT uuid, dirty FROM notes WHERE content = ?", "n8-content"), &n8.UUID, &n8.Dirty) - testutils.MustScan(t, "getting n10", db.QueryRow("SELECT uuid, dirty FROM notes WHERE content = ?", "n10-content"), &n10.UUID, &n10.Dirty) + testutils.MustScan(t, "getting n1", db.QueryRow("SELECT uuid, dirty FROM notes WHERE body = ?", "n1-body"), &n1.UUID, &n1.Dirty) + testutils.MustScan(t, "getting n2", db.QueryRow("SELECT uuid, dirty FROM notes WHERE body = ?", "n2-body"), &n2.UUID, &n2.Dirty) + testutils.MustScan(t, "getting n3", db.QueryRow("SELECT uuid, dirty FROM notes WHERE body = ?", "n3-body"), &n3.UUID, &n3.Dirty) + testutils.MustScan(t, "getting n6", db.QueryRow("SELECT uuid, dirty FROM notes WHERE body = ?", "n6-body"), &n6.UUID, &n6.Dirty) + testutils.MustScan(t, "getting n7", db.QueryRow("SELECT uuid, dirty FROM notes WHERE body = ?", "n7-body"), &n7.UUID, &n7.Dirty) + testutils.MustScan(t, "getting n8", db.QueryRow("SELECT uuid, dirty FROM notes WHERE body = ?", "n8-body"), &n8.UUID, &n8.Dirty) + testutils.MustScan(t, "getting n10", db.QueryRow("SELECT uuid, dirty FROM notes WHERE body = ?", "n10-body"), &n10.UUID, &n10.Dirty) testutils.AssertEqualf(t, noteCount, 7, "note count mismatch") @@ -2302,12 +2302,12 @@ func TestSendNotes(t *testing.T) { // UUIDs of created notes should have been updated with those from the server response testutils.AssertEqual(t, n1.UUID, "n1-uuid", "n1 UUID mismatch") - testutils.AssertEqual(t, n2.UUID, "server-n2-content-uuid", "n2 UUID mismatch") + testutils.AssertEqual(t, n2.UUID, "server-n2-body-uuid", "n2 UUID mismatch") testutils.AssertEqual(t, n3.UUID, "n3-uuid", "n3 UUID mismatch") - testutils.AssertEqual(t, n6.UUID, "server-n6-content-uuid", "n6 UUID mismatch") + testutils.AssertEqual(t, n6.UUID, "server-n6-body-uuid", "n6 UUID mismatch") testutils.AssertEqual(t, n7.UUID, "n7-uuid", "n7 UUID mismatch") testutils.AssertEqual(t, n8.UUID, "n8-uuid", "n8 UUID mismatch") - testutils.AssertEqual(t, n10.UUID, "server-n10-content-uuid", "n10 UUID mismatch") + testutils.AssertEqual(t, n10.UUID, "server-n10-body-uuid", "n10 UUID mismatch") } func TestSendNotes_isBehind(t *testing.T) { @@ -2327,7 +2327,7 @@ func TestSendNotes_isBehind(t *testing.T) { }, } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -2344,7 +2344,7 @@ func TestSendNotes_isBehind(t *testing.T) { }, } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -2357,7 +2357,7 @@ func TestSendNotes_isBehind(t *testing.T) { }, } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Body-Type", "application/json") if err := json.NewEncoder(w).Encode(resp); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -2396,7 +2396,7 @@ func TestSendNotes_isBehind(t *testing.T) { testutils.MustExec(t, fmt.Sprintf("inserting last max usn for test case %d", idx), db, "INSERT INTO system (key, value) VALUES (?, ?)", infra.SystemLastMaxUSN, tc.systemLastMaxUSN) testutils.MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", "b1-uuid", "b1-label", 1, false, false) - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 1, "n1 content", 1541108743, false, true) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 1, "n1 body", 1541108743, false, true) // execute tx, err := db.Begin() @@ -2444,7 +2444,7 @@ func TestSendNotes_isBehind(t *testing.T) { testutils.MustExec(t, fmt.Sprintf("inserting last max usn for test case %d", idx), db, "INSERT INTO system (key, value) VALUES (?, ?)", infra.SystemLastMaxUSN, tc.systemLastMaxUSN) testutils.MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", "b1-uuid", "b1-label", 1, false, false) - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 2, "n1 content", 1541108743, true, true) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 2, "n1 body", 1541108743, true, true) // execute tx, err := db.Begin() @@ -2492,7 +2492,7 @@ func TestSendNotes_isBehind(t *testing.T) { testutils.MustExec(t, fmt.Sprintf("inserting last max usn for test case %d", idx), db, "INSERT INTO system (key, value) VALUES (?, ?)", infra.SystemLastMaxUSN, tc.systemLastMaxUSN) testutils.MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", "b1-uuid", "b1-label", 1, false, false) - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 8, "n1 content", 1541108743, false, true) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 8, "n1 body", 1541108743, false, true) // execute tx, err := db.Begin() @@ -2523,21 +2523,21 @@ func TestMergeNote(t *testing.T) { addedOn int64 clientUSN int clientEditedOn int64 - clientContent string + clientBody string clientPublic bool clientDeleted bool clientBookUUID string clientDirty bool serverUSN int serverEditedOn int64 - serverContent string + serverBody string serverPublic bool serverDeleted bool serverBookUUID string expectedUSN int expectedAddedOn int64 expectedEditedOn int64 - expectedContent string + expectedBody string expectedPublic bool expectedDeleted bool expectedBookUUID string @@ -2547,21 +2547,21 @@ func TestMergeNote(t *testing.T) { clientDirty: false, clientUSN: 1, clientEditedOn: 0, - clientContent: "n1 content", + clientBody: "n1 body", clientPublic: false, clientDeleted: false, clientBookUUID: b1UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content edited", + serverBody: "n1 body edited", serverPublic: true, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content edited", + expectedBody: "n1 body edited", expectedPublic: true, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -2572,21 +2572,21 @@ func TestMergeNote(t *testing.T) { clientDirty: true, clientUSN: 1, clientEditedOn: 1541219321, - clientContent: "", + clientBody: "", clientPublic: false, clientDeleted: true, clientBookUUID: b1UUID, addedOn: 1541232118, serverUSN: 21, serverEditedOn: 1541219321, - serverContent: "n1 content edited", + serverBody: "n1 body edited", serverPublic: false, serverDeleted: false, serverBookUUID: b2UUID, expectedUSN: 21, expectedAddedOn: 1541232118, expectedEditedOn: 1541219321, - expectedContent: "n1 content edited", + expectedBody: "n1 body edited", expectedPublic: false, expectedDeleted: false, expectedBookUUID: b2UUID, @@ -2605,7 +2605,7 @@ func TestMergeNote(t *testing.T) { testutils.MustExec(t, fmt.Sprintf("inserting b1 for test case %d", idx), db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", b1UUID, "b1-label", 5, false) testutils.MustExec(t, fmt.Sprintf("inserting b2 for test case %d", idx), db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", b2UUID, "b2-label", 6, false) n1UUID := utils.GenerateUUID() - testutils.MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, b1UUID, tc.clientUSN, tc.addedOn, tc.clientEditedOn, tc.clientContent, tc.clientPublic, tc.clientDeleted, tc.clientDirty) + testutils.MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, b1UUID, tc.clientUSN, tc.addedOn, tc.clientEditedOn, tc.clientBody, tc.clientPublic, tc.clientDeleted, tc.clientDirty) // execute tx, err := db.Begin() @@ -2620,14 +2620,14 @@ func TestMergeNote(t *testing.T) { USN: tc.serverUSN, AddedOn: tc.addedOn, EditedOn: tc.serverEditedOn, - Content: tc.serverContent, + Body: tc.serverBody, Public: tc.serverPublic, Deleted: tc.serverDeleted, } var localNote core.Note testutils.MustScan(t, fmt.Sprintf("getting localNote for test case %d", idx), - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n1UUID), - &localNote.UUID, &localNote.BookUUID, &localNote.USN, &localNote.AddedOn, &localNote.EditedOn, &localNote.Content, &localNote.Public, &localNote.Deleted, &localNote.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n1UUID), + &localNote.UUID, &localNote.BookUUID, &localNote.USN, &localNote.AddedOn, &localNote.EditedOn, &localNote.Body, &localNote.Public, &localNote.Deleted, &localNote.Dirty) if err := mergeNote(tx, fragNote, localNote); err != nil { tx.Rollback() @@ -2646,8 +2646,8 @@ func TestMergeNote(t *testing.T) { var n1Record core.Note testutils.MustScan(t, fmt.Sprintf("getting n1Record for test case %d", idx), - db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty FROM notes WHERE uuid = ?", n1UUID), - &n1Record.UUID, &n1Record.BookUUID, &n1Record.USN, &n1Record.AddedOn, &n1Record.EditedOn, &n1Record.Content, &n1Record.Public, &n1Record.Deleted, &n1Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty FROM notes WHERE uuid = ?", n1UUID), + &n1Record.UUID, &n1Record.BookUUID, &n1Record.USN, &n1Record.AddedOn, &n1Record.EditedOn, &n1Record.Body, &n1Record.Public, &n1Record.Deleted, &n1Record.Dirty) var b1Record core.Book testutils.MustScan(t, "getting b1Record for test case", db.QueryRow("SELECT uuid, label, usn, dirty FROM books WHERE uuid = ?", b1UUID), @@ -2672,7 +2672,7 @@ func TestMergeNote(t *testing.T) { testutils.AssertEqual(t, n1Record.USN, tc.expectedUSN, fmt.Sprintf("n1Record USN mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.AddedOn, tc.expectedAddedOn, fmt.Sprintf("n1Record AddedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.EditedOn, tc.expectedEditedOn, fmt.Sprintf("n1Record EditedOn mismatch for test case %d", idx)) - testutils.AssertEqual(t, n1Record.Content, tc.expectedContent, fmt.Sprintf("n1Record Content mismatch for test case %d", idx)) + testutils.AssertEqual(t, n1Record.Body, tc.expectedBody, fmt.Sprintf("n1Record Body mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.Public, tc.expectedPublic, fmt.Sprintf("n1Record Public mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.Deleted, tc.expectedDeleted, fmt.Sprintf("n1Record Deleted mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.Dirty, tc.expectedDirty, fmt.Sprintf("n1Record Dirty mismatch for test case %d", idx)) @@ -2689,11 +2689,11 @@ func TestCheckBookPristine(t *testing.T) { testutils.MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", "b1-uuid", "b1-label", 5, false) testutils.MustExec(t, "inserting b2", db, "INSERT INTO books (uuid, label, usn, dirty) VALUES (?, ?, ?, ?)", "b2-uuid", "b2-label", 6, false) - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, added_on, content, dirty) VALUES (?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 1541108743, "n1 content", false) - testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, added_on, content, dirty) VALUES (?, ?, ?, ?, ?)", "n2-uuid", "b1-uuid", 1541108743, "n2 content", false) - testutils.MustExec(t, "inserting n3", db, "INSERT INTO notes (uuid, book_uuid, added_on, content, dirty) VALUES (?, ?, ?, ?, ?)", "n3-uuid", "b1-uuid", 1541108743, "n3 content", true) - testutils.MustExec(t, "inserting n4", db, "INSERT INTO notes (uuid, book_uuid, added_on, content, dirty) VALUES (?, ?, ?, ?, ?)", "n4-uuid", "b2-uuid", 1541108743, "n4 content", false) - testutils.MustExec(t, "inserting n5", db, "INSERT INTO notes (uuid, book_uuid, added_on, content, dirty) VALUES (?, ?, ?, ?, ?)", "n5-uuid", "b2-uuid", 1541108743, "n5 content", false) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, added_on, body, dirty) VALUES (?, ?, ?, ?, ?)", "n1-uuid", "b1-uuid", 1541108743, "n1 body", false) + testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, added_on, body, dirty) VALUES (?, ?, ?, ?, ?)", "n2-uuid", "b1-uuid", 1541108743, "n2 body", false) + testutils.MustExec(t, "inserting n3", db, "INSERT INTO notes (uuid, book_uuid, added_on, body, dirty) VALUES (?, ?, ?, ?, ?)", "n3-uuid", "b1-uuid", 1541108743, "n3 body", true) + testutils.MustExec(t, "inserting n4", db, "INSERT INTO notes (uuid, book_uuid, added_on, body, dirty) VALUES (?, ?, ?, ?, ?)", "n4-uuid", "b2-uuid", 1541108743, "n4 body", false) + testutils.MustExec(t, "inserting n5", db, "INSERT INTO notes (uuid, book_uuid, added_on, body, dirty) VALUES (?, ?, ?, ?, ?)", "n5-uuid", "b2-uuid", 1541108743, "n5 body", false) t.Run("b1", func(t *testing.T) { // execute @@ -2896,15 +2896,15 @@ func TestCleanLocalNotes(t *testing.T) { testutils.MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", b1UUID, "b1-label", 1, false, false) // exists in the list - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 content", 1541108743, false, false) - testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b1UUID, 0, "n2 content", 1541108743, false, true) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n1-uuid", b1UUID, 10, "n1 body", 1541108743, false, false) + testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n2-uuid", b1UUID, 0, "n2 body", 1541108743, false, true) // non-existent in the list but in valid state // (created in the cli and hasn't been uploaded) - testutils.MustExec(t, "inserting n6", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n6-uuid", b1UUID, 0, "n6 content", 1541108743, false, true) + testutils.MustExec(t, "inserting n6", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n6-uuid", b1UUID, 0, "n6 body", 1541108743, false, true) // non-existent in the list and in an invalid state - testutils.MustExec(t, "inserting n5", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n5-uuid", b1UUID, 7, "n5 content", 1541108743, true, true) - testutils.MustExec(t, "inserting n9", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n9-uuid", b1UUID, 17, "n9 content", 1541108743, true, false) - testutils.MustExec(t, "inserting n10", db, "INSERT INTO notes (uuid, book_uuid, usn, content, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n10-uuid", b1UUID, 0, "n10 content", 1541108743, false, false) + testutils.MustExec(t, "inserting n5", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n5-uuid", b1UUID, 7, "n5 body", 1541108743, true, true) + testutils.MustExec(t, "inserting n9", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n9-uuid", b1UUID, 17, "n9 body", 1541108743, true, false) + testutils.MustExec(t, "inserting n10", db, "INSERT INTO notes (uuid, book_uuid, usn, body, added_on, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", "n10-uuid", b1UUID, 0, "n10 body", 1541108743, false, false) // execute tx, err := db.Begin() diff --git a/core/models.go b/core/models.go index f9c49815..38e91036 100644 --- a/core/models.go +++ b/core/models.go @@ -20,7 +20,7 @@ type Book struct { type Note struct { UUID string `json:"uuid"` BookUUID string `json:"book_uuid"` - Content string `json:"content"` + Body string `json:"content"` AddedOn int64 `json:"added_on"` EditedOn int64 `json:"edited_on"` USN int `json:"usn"` @@ -30,11 +30,11 @@ type Note struct { } // NewNote constructs a note with the given data -func NewNote(uuid, bookUUID, content string, addedOn, editedOn int64, usn int, public, deleted, dirty bool) Note { +func NewNote(uuid, bookUUID, body string, addedOn, editedOn int64, usn int, public, deleted, dirty bool) Note { return Note{ UUID: uuid, BookUUID: bookUUID, - Content: content, + Body: body, AddedOn: addedOn, EditedOn: editedOn, USN: usn, @@ -46,8 +46,8 @@ func NewNote(uuid, bookUUID, content string, addedOn, editedOn int64, usn int, p // Insert inserts a new note func (n Note) Insert(tx *sql.Tx) error { - _, err := tx.Exec("INSERT INTO notes (uuid, book_uuid, content, added_on, edited_on, usn, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", - n.UUID, n.BookUUID, n.Content, n.AddedOn, n.EditedOn, n.USN, n.Public, n.Deleted, n.Dirty) + _, err := tx.Exec("INSERT INTO notes (uuid, book_uuid, body, added_on, edited_on, usn, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + n.UUID, n.BookUUID, n.Body, n.AddedOn, n.EditedOn, n.USN, n.Public, n.Deleted, n.Dirty) if err != nil { return errors.Wrapf(err, "inserting note with uuid %s", n.UUID) @@ -58,8 +58,8 @@ func (n Note) Insert(tx *sql.Tx) error { // Update updates the note with the given data func (n Note) Update(tx *sql.Tx) error { - _, err := tx.Exec("UPDATE notes SET book_uuid = ?, content = ?, added_on = ?, edited_on = ?, usn = ?, public = ?, deleted = ?, dirty = ? WHERE uuid = ?", - n.BookUUID, n.Content, n.AddedOn, n.EditedOn, n.USN, n.Public, n.Deleted, n.Dirty, n.UUID) + _, err := tx.Exec("UPDATE notes SET book_uuid = ?, body = ?, added_on = ?, edited_on = ?, usn = ?, public = ?, deleted = ?, dirty = ? WHERE uuid = ?", + n.BookUUID, n.Body, n.AddedOn, n.EditedOn, n.USN, n.Public, n.Deleted, n.Dirty, n.UUID) if err != nil { return errors.Wrapf(err, "updating the note with uuid %s", n.UUID) diff --git a/core/models_test.go b/core/models_test.go index 2cbdbac1..7cc646c8 100644 --- a/core/models_test.go +++ b/core/models_test.go @@ -12,7 +12,7 @@ func TestNewNote(t *testing.T) { testCases := []struct { uuid string bookUUID string - content string + body string addedOn int64 editedOn int64 usn int @@ -23,7 +23,7 @@ func TestNewNote(t *testing.T) { { uuid: "n1-uuid", bookUUID: "b1-uuid", - content: "n1-content", + body: "n1-body", addedOn: 1542058875, editedOn: 0, usn: 0, @@ -34,7 +34,7 @@ func TestNewNote(t *testing.T) { { uuid: "n2-uuid", bookUUID: "b2-uuid", - content: "n2-content", + body: "n2-body", addedOn: 1542058875, editedOn: 1542058876, usn: 1008, @@ -45,11 +45,11 @@ func TestNewNote(t *testing.T) { } for idx, tc := range testCases { - got := NewNote(tc.uuid, tc.bookUUID, tc.content, tc.addedOn, tc.editedOn, tc.usn, tc.public, tc.deleted, tc.dirty) + got := NewNote(tc.uuid, tc.bookUUID, tc.body, tc.addedOn, tc.editedOn, tc.usn, tc.public, tc.deleted, tc.dirty) testutils.AssertEqual(t, got.UUID, tc.uuid, fmt.Sprintf("UUID mismatch for test case %d", idx)) testutils.AssertEqual(t, got.BookUUID, tc.bookUUID, fmt.Sprintf("BookUUID mismatch for test case %d", idx)) - testutils.AssertEqual(t, got.Content, tc.content, fmt.Sprintf("Content mismatch for test case %d", idx)) + testutils.AssertEqual(t, got.Body, tc.body, fmt.Sprintf("Body mismatch for test case %d", idx)) testutils.AssertEqual(t, got.AddedOn, tc.addedOn, fmt.Sprintf("AddedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, got.EditedOn, tc.editedOn, fmt.Sprintf("EditedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, got.USN, tc.usn, fmt.Sprintf("USN mismatch for test case %d", idx)) @@ -63,7 +63,7 @@ func TestNoteInsert(t *testing.T) { testCases := []struct { uuid string bookUUID string - content string + body string addedOn int64 editedOn int64 usn int @@ -74,7 +74,7 @@ func TestNoteInsert(t *testing.T) { { uuid: "n1-uuid", bookUUID: "b1-uuid", - content: "n1-content", + body: "n1-body", addedOn: 1542058875, editedOn: 0, usn: 0, @@ -85,7 +85,7 @@ func TestNoteInsert(t *testing.T) { { uuid: "n2-uuid", bookUUID: "b2-uuid", - content: "n2-content", + body: "n2-body", addedOn: 1542058875, editedOn: 1542058876, usn: 1008, @@ -104,7 +104,7 @@ func TestNoteInsert(t *testing.T) { n := Note{ UUID: tc.uuid, BookUUID: tc.bookUUID, - Content: tc.content, + Body: tc.body, AddedOn: tc.addedOn, EditedOn: tc.editedOn, USN: tc.usn, @@ -129,17 +129,17 @@ func TestNoteInsert(t *testing.T) { tx.Commit() // test - var uuid, bookUUID, content string + var uuid, bookUUID, body string var addedOn, editedOn int64 var usn int var public, deleted, dirty bool testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, book_uuid, content, added_on, edited_on, usn, public, deleted, dirty FROM notes WHERE uuid = ?", tc.uuid), - &uuid, &bookUUID, &content, &addedOn, &editedOn, &usn, &public, &deleted, &dirty) + db.QueryRow("SELECT uuid, book_uuid, body, added_on, edited_on, usn, public, deleted, dirty FROM notes WHERE uuid = ?", tc.uuid), + &uuid, &bookUUID, &body, &addedOn, &editedOn, &usn, &public, &deleted, &dirty) testutils.AssertEqual(t, uuid, tc.uuid, fmt.Sprintf("uuid mismatch for test case %d", idx)) testutils.AssertEqual(t, bookUUID, tc.bookUUID, fmt.Sprintf("bookUUID mismatch for test case %d", idx)) - testutils.AssertEqual(t, content, tc.content, fmt.Sprintf("content mismatch for test case %d", idx)) + testutils.AssertEqual(t, body, tc.body, fmt.Sprintf("body mismatch for test case %d", idx)) testutils.AssertEqual(t, addedOn, tc.addedOn, fmt.Sprintf("addedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, editedOn, tc.editedOn, fmt.Sprintf("editedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, usn, tc.usn, fmt.Sprintf("usn mismatch for test case %d", idx)) @@ -154,7 +154,7 @@ func TestNoteUpdate(t *testing.T) { testCases := []struct { uuid string bookUUID string - content string + body string addedOn int64 editedOn int64 usn int @@ -162,7 +162,7 @@ func TestNoteUpdate(t *testing.T) { deleted bool dirty bool newBookUUID string - newContent string + newBody string newEditedOn int64 newUSN int newPublic bool @@ -172,7 +172,7 @@ func TestNoteUpdate(t *testing.T) { { uuid: "n1-uuid", bookUUID: "b1-uuid", - content: "n1-content", + body: "n1-body", addedOn: 1542058875, editedOn: 0, usn: 0, @@ -180,7 +180,7 @@ func TestNoteUpdate(t *testing.T) { deleted: false, dirty: false, newBookUUID: "b1-uuid", - newContent: "n1-content edited", + newBody: "n1-body edited", newEditedOn: 1542058879, newUSN: 0, newPublic: false, @@ -190,7 +190,7 @@ func TestNoteUpdate(t *testing.T) { { uuid: "n1-uuid", bookUUID: "b1-uuid", - content: "n1-content", + body: "n1-body", addedOn: 1542058875, editedOn: 0, usn: 0, @@ -198,7 +198,7 @@ func TestNoteUpdate(t *testing.T) { deleted: false, dirty: true, newBookUUID: "b2-uuid", - newContent: "n1-content", + newBody: "n1-body", newEditedOn: 1542058879, newUSN: 0, newPublic: true, @@ -208,7 +208,7 @@ func TestNoteUpdate(t *testing.T) { { uuid: "n1-uuid", bookUUID: "b1-uuid", - content: "n1-content", + body: "n1-body", addedOn: 1542058875, editedOn: 0, usn: 10, @@ -216,7 +216,7 @@ func TestNoteUpdate(t *testing.T) { deleted: false, dirty: false, newBookUUID: "", - newContent: "", + newBody: "", newEditedOn: 1542058879, newUSN: 151, newPublic: false, @@ -226,7 +226,7 @@ func TestNoteUpdate(t *testing.T) { { uuid: "n1-uuid", bookUUID: "b1-uuid", - content: "n1-content", + body: "n1-body", addedOn: 1542058875, editedOn: 0, usn: 0, @@ -234,7 +234,7 @@ func TestNoteUpdate(t *testing.T) { deleted: false, dirty: false, newBookUUID: "", - newContent: "", + newBody: "", newEditedOn: 1542058879, newUSN: 15, newPublic: false, @@ -252,7 +252,7 @@ func TestNoteUpdate(t *testing.T) { n1 := Note{ UUID: tc.uuid, BookUUID: tc.bookUUID, - Content: tc.content, + Body: tc.body, AddedOn: tc.addedOn, EditedOn: tc.editedOn, USN: tc.usn, @@ -263,7 +263,7 @@ func TestNoteUpdate(t *testing.T) { n2 := Note{ UUID: "n2-uuid", BookUUID: "b10-uuid", - Content: "n2 content", + Body: "n2 body", AddedOn: 1542058875, EditedOn: 0, USN: 39, @@ -273,8 +273,8 @@ func TestNoteUpdate(t *testing.T) { } db := ctx.DB - testutils.MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.USN, n1.AddedOn, n1.EditedOn, n1.Content, n1.Public, n1.Deleted, n1.Dirty) - testutils.MustExec(t, fmt.Sprintf("inserting n2 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.USN, n2.AddedOn, n2.EditedOn, n2.Content, n2.Public, n2.Deleted, n2.Dirty) + testutils.MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.USN, n1.AddedOn, n1.EditedOn, n1.Body, n1.Public, n1.Deleted, n1.Dirty) + testutils.MustExec(t, fmt.Sprintf("inserting n2 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.USN, n2.AddedOn, n2.EditedOn, n2.Body, n2.Public, n2.Deleted, n2.Dirty) // execute tx, err := db.Begin() @@ -283,7 +283,7 @@ func TestNoteUpdate(t *testing.T) { } n1.BookUUID = tc.newBookUUID - n1.Content = tc.newContent + n1.Body = tc.newBody n1.EditedOn = tc.newEditedOn n1.USN = tc.newUSN n1.Public = tc.newPublic @@ -300,15 +300,15 @@ func TestNoteUpdate(t *testing.T) { // test var n1Record, n2Record Note testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, book_uuid, content, added_on, edited_on, usn, public, deleted, dirty FROM notes WHERE uuid = ?", tc.uuid), - &n1Record.UUID, &n1Record.BookUUID, &n1Record.Content, &n1Record.AddedOn, &n1Record.EditedOn, &n1Record.USN, &n1Record.Public, &n1Record.Deleted, &n1Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, body, added_on, edited_on, usn, public, deleted, dirty FROM notes WHERE uuid = ?", tc.uuid), + &n1Record.UUID, &n1Record.BookUUID, &n1Record.Body, &n1Record.AddedOn, &n1Record.EditedOn, &n1Record.USN, &n1Record.Public, &n1Record.Deleted, &n1Record.Dirty) testutils.MustScan(t, "getting n2", - db.QueryRow("SELECT uuid, book_uuid, content, added_on, edited_on, usn, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), - &n2Record.UUID, &n2Record.BookUUID, &n2Record.Content, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.USN, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, body, added_on, edited_on, usn, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), + &n2Record.UUID, &n2Record.BookUUID, &n2Record.Body, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.USN, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) testutils.AssertEqual(t, n1Record.UUID, n1.UUID, fmt.Sprintf("n1 uuid mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.BookUUID, tc.newBookUUID, fmt.Sprintf("n1 bookUUID mismatch for test case %d", idx)) - testutils.AssertEqual(t, n1Record.Content, tc.newContent, fmt.Sprintf("n1 content mismatch for test case %d", idx)) + testutils.AssertEqual(t, n1Record.Body, tc.newBody, fmt.Sprintf("n1 body mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.AddedOn, n1.AddedOn, fmt.Sprintf("n1 addedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.EditedOn, tc.newEditedOn, fmt.Sprintf("n1 editedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, n1Record.USN, tc.newUSN, fmt.Sprintf("n1 usn mismatch for test case %d", idx)) @@ -318,7 +318,7 @@ func TestNoteUpdate(t *testing.T) { testutils.AssertEqual(t, n2Record.UUID, n2.UUID, fmt.Sprintf("n2 uuid mismatch for test case %d", idx)) testutils.AssertEqual(t, n2Record.BookUUID, n2.BookUUID, fmt.Sprintf("n2 bookUUID mismatch for test case %d", idx)) - testutils.AssertEqual(t, n2Record.Content, n2.Content, fmt.Sprintf("n2 content mismatch for test case %d", idx)) + testutils.AssertEqual(t, n2Record.Body, n2.Body, fmt.Sprintf("n2 body mismatch for test case %d", idx)) testutils.AssertEqual(t, n2Record.AddedOn, n2.AddedOn, fmt.Sprintf("n2 addedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, n2Record.EditedOn, n2.EditedOn, fmt.Sprintf("n2 editedOn mismatch for test case %d", idx)) testutils.AssertEqual(t, n2Record.USN, n2.USN, fmt.Sprintf("n2 usn mismatch for test case %d", idx)) @@ -351,7 +351,7 @@ func TestNoteUpdateUUID(t *testing.T) { UUID: "n1-uuid", BookUUID: "b1-uuid", AddedOn: 1542058874, - Content: "n1-content", + Body: "n1-body", USN: 1, Deleted: true, Dirty: false, @@ -360,15 +360,15 @@ func TestNoteUpdateUUID(t *testing.T) { UUID: "n2-uuid", BookUUID: "b1-uuid", AddedOn: 1542058874, - Content: "n2-content", + Body: "n2-body", USN: 1, Deleted: true, Dirty: false, } db := ctx.DB - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, content, added_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.Content, n1.AddedOn, n1.USN, n1.Deleted, n1.Dirty) - testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, content, added_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.Content, n2.AddedOn, n2.USN, n2.Deleted, n2.Dirty) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.Body, n1.AddedOn, n1.USN, n1.Deleted, n1.Dirty) + testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.Body, n2.AddedOn, n2.USN, n2.Deleted, n2.Dirty) // execute tx, err := db.Begin() @@ -385,11 +385,11 @@ func TestNoteUpdateUUID(t *testing.T) { // test var n1Record, n2Record Note testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, content, usn, deleted, dirty FROM notes WHERE content = ?", "n1-content"), - &n1Record.UUID, &n1Record.Content, &n1Record.USN, &n1Record.Deleted, &n1Record.Dirty) + db.QueryRow("SELECT uuid, body, usn, deleted, dirty FROM notes WHERE body = ?", "n1-body"), + &n1Record.UUID, &n1Record.Body, &n1Record.USN, &n1Record.Deleted, &n1Record.Dirty) testutils.MustScan(t, "getting n2", - db.QueryRow("SELECT uuid, content, usn, deleted, dirty FROM notes WHERE content = ?", "n2-content"), - &n2Record.UUID, &n2Record.Content, &n2Record.USN, &n2Record.Deleted, &n2Record.Dirty) + db.QueryRow("SELECT uuid, body, usn, deleted, dirty FROM notes WHERE body = ?", "n2-body"), + &n2Record.UUID, &n2Record.Body, &n2Record.USN, &n2Record.Deleted, &n2Record.Dirty) testutils.AssertEqual(t, n1.UUID, tc.newUUID, "n1 original reference uuid mismatch") testutils.AssertEqual(t, n1Record.UUID, tc.newUUID, "n1 uuid mismatch") @@ -406,7 +406,7 @@ func TestNoteExpunge(t *testing.T) { n1 := Note{ UUID: "n1-uuid", BookUUID: "b9-uuid", - Content: "n1 content", + Body: "n1 body", AddedOn: 1542058874, EditedOn: 0, USN: 22, @@ -417,7 +417,7 @@ func TestNoteExpunge(t *testing.T) { n2 := Note{ UUID: "n2-uuid", BookUUID: "b10-uuid", - Content: "n2 content", + Body: "n2 body", AddedOn: 1542058875, EditedOn: 0, USN: 39, @@ -427,8 +427,8 @@ func TestNoteExpunge(t *testing.T) { } db := ctx.DB - testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.USN, n1.AddedOn, n1.EditedOn, n1.Content, n1.Public, n1.Deleted, n1.Dirty) - testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, content, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.USN, n2.AddedOn, n2.EditedOn, n2.Content, n2.Public, n2.Deleted, n2.Dirty) + testutils.MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.USN, n1.AddedOn, n1.EditedOn, n1.Body, n1.Public, n1.Deleted, n1.Dirty) + testutils.MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, public, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.USN, n2.AddedOn, n2.EditedOn, n2.Body, n2.Public, n2.Deleted, n2.Dirty) // execute tx, err := db.Begin() @@ -451,12 +451,12 @@ func TestNoteExpunge(t *testing.T) { var n2Record Note testutils.MustScan(t, "getting n2", - db.QueryRow("SELECT uuid, book_uuid, content, added_on, edited_on, usn, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), - &n2Record.UUID, &n2Record.BookUUID, &n2Record.Content, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.USN, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) + db.QueryRow("SELECT uuid, book_uuid, body, added_on, edited_on, usn, public, deleted, dirty FROM notes WHERE uuid = ?", n2.UUID), + &n2Record.UUID, &n2Record.BookUUID, &n2Record.Body, &n2Record.AddedOn, &n2Record.EditedOn, &n2Record.USN, &n2Record.Public, &n2Record.Deleted, &n2Record.Dirty) testutils.AssertEqual(t, n2Record.UUID, n2.UUID, "n2 uuid mismatch") testutils.AssertEqual(t, n2Record.BookUUID, n2.BookUUID, "n2 bookUUID mismatch") - testutils.AssertEqual(t, n2Record.Content, n2.Content, "n2 content mismatch") + testutils.AssertEqual(t, n2Record.Body, n2.Body, "n2 body mismatch") testutils.AssertEqual(t, n2Record.AddedOn, n2.AddedOn, "n2 addedOn mismatch") testutils.AssertEqual(t, n2Record.EditedOn, n2.EditedOn, "n2 editedOn mismatch") testutils.AssertEqual(t, n2Record.USN, n2.USN, "n2 usn mismatch") @@ -793,3 +793,91 @@ func TestBookExpunge(t *testing.T) { testutils.AssertEqual(t, b2Record.Deleted, b2.Deleted, "b2 deleted mismatch") testutils.AssertEqual(t, b2Record.Dirty, b2.Dirty, "b2 dirty mismatch") } + +// TestNoteFTS tests that note full text search indices stay in sync with the notes after insert, update and delete +func TestNoteFTS(t *testing.T) { + // set up + ctx := testutils.InitEnv(t, "../tmp", "../testutils/fixtures/schema.sql", true) + defer testutils.TeardownEnv(ctx) + + // execute - insert + n := Note{ + UUID: "n1-uuid", + BookUUID: "b1-uuid", + Body: "foo bar", + AddedOn: 1542058875, + EditedOn: 0, + USN: 0, + Public: false, + Deleted: false, + Dirty: false, + } + db := ctx.DB + + tx, err := db.Begin() + if err != nil { + t.Fatalf(errors.Wrap(err, "beginning a transaction").Error()) + } + + if err := n.Insert(tx); err != nil { + tx.Rollback() + t.Fatalf(errors.Wrap(err, "inserting").Error()) + } + + tx.Commit() + + // test + var noteCount, noteFtsCount, noteSearchCount int + testutils.MustScan(t, "counting notes", db.QueryRow("SELECT count(*) FROM notes"), ¬eCount) + testutils.MustScan(t, "counting note_fts", db.QueryRow("SELECT count(*) FROM note_fts"), ¬eFtsCount) + testutils.MustScan(t, "counting search results", db.QueryRow("SELECT count(*) FROM note_fts WHERE note_fts MATCH ?", "foo"), ¬eSearchCount) + + testutils.AssertEqual(t, noteCount, 1, "noteCount mismatch") + testutils.AssertEqual(t, noteFtsCount, 1, "noteFtsCount mismatch") + testutils.AssertEqual(t, noteSearchCount, 1, "noteSearchCount mismatch") + + // execute - update + tx, err = db.Begin() + if err != nil { + t.Fatalf(errors.Wrap(err, "beginning a transaction").Error()) + } + + n.Body = "baz quz" + if err := n.Update(tx); err != nil { + tx.Rollback() + t.Fatalf(errors.Wrap(err, "updating").Error()) + } + + tx.Commit() + + // test + testutils.MustScan(t, "counting notes", db.QueryRow("SELECT count(*) FROM notes"), ¬eCount) + testutils.MustScan(t, "counting note_fts", db.QueryRow("SELECT count(*) FROM note_fts"), ¬eFtsCount) + testutils.AssertEqual(t, noteCount, 1, "noteCount mismatch") + testutils.AssertEqual(t, noteFtsCount, 1, "noteFtsCount mismatch") + + testutils.MustScan(t, "counting search results", db.QueryRow("SELECT count(*) FROM note_fts WHERE note_fts MATCH ?", "foo"), ¬eSearchCount) + testutils.AssertEqual(t, noteSearchCount, 0, "noteSearchCount for foo mismatch") + testutils.MustScan(t, "counting search results", db.QueryRow("SELECT count(*) FROM note_fts WHERE note_fts MATCH ?", "baz"), ¬eSearchCount) + testutils.AssertEqual(t, noteSearchCount, 1, "noteSearchCount for baz mismatch") + + // execute - delete + tx, err = db.Begin() + if err != nil { + t.Fatalf(errors.Wrap(err, "beginning a transaction").Error()) + } + + if err := n.Expunge(tx); err != nil { + tx.Rollback() + t.Fatalf(errors.Wrap(err, "expunging").Error()) + } + + tx.Commit() + + // test + testutils.MustScan(t, "counting notes", db.QueryRow("SELECT count(*) FROM notes"), ¬eCount) + testutils.MustScan(t, "counting note_fts", db.QueryRow("SELECT count(*) FROM note_fts"), ¬eFtsCount) + + testutils.AssertEqual(t, noteCount, 0, "noteCount mismatch") + testutils.AssertEqual(t, noteFtsCount, 0, "noteFtsCount mismatch") +} diff --git a/infra/main.go b/infra/main.go index 74d329ba..28bf87e7 100644 --- a/infra/main.go +++ b/infra/main.go @@ -150,7 +150,6 @@ func InitDB(ctx DnoteCtx) error { CREATE UNIQUE INDEX IF NOT EXISTS idx_books_label ON books(label); CREATE UNIQUE INDEX IF NOT EXISTS idx_notes_uuid ON notes(uuid); CREATE UNIQUE INDEX IF NOT EXISTS idx_books_uuid ON books(uuid); - CREATE UNIQUE INDEX IF NOT EXISTS idx_notes_id ON notes(id); CREATE INDEX IF NOT EXISTS idx_notes_book_uuid ON notes(book_uuid);`) if err != nil { return errors.Wrap(err, "creating indices") diff --git a/main.go b/main.go index c8f25b1b..50484f81 100644 --- a/main.go +++ b/main.go @@ -13,9 +13,9 @@ import ( "github.com/dnote/cli/cmd/add" "github.com/dnote/cli/cmd/cat" "github.com/dnote/cli/cmd/edit" + "github.com/dnote/cli/cmd/find" "github.com/dnote/cli/cmd/login" "github.com/dnote/cli/cmd/ls" - "github.com/dnote/cli/cmd/remove" "github.com/dnote/cli/cmd/sync" "github.com/dnote/cli/cmd/version" @@ -46,6 +46,7 @@ func main() { root.Register(version.NewCmd(ctx)) root.Register(cat.NewCmd(ctx)) root.Register(view.NewCmd(ctx)) + root.Register(find.NewCmd(ctx)) if err := root.Execute(); err != nil { log.Errorf("%s\n", err.Error()) diff --git a/main_test.go b/main_test.go index bfb30be9..a93a532b 100644 --- a/main_test.go +++ b/main_test.go @@ -18,7 +18,7 @@ import ( var binaryName = "test-dnote" func TestMain(m *testing.M) { - if err := exec.Command("go", "build", "-o", binaryName).Run(); err != nil { + if err := exec.Command("go", "build", "--tags", "fts5", "-o", binaryName).Run(); err != nil { log.Print(errors.Wrap(err, "building a binary").Error()) os.Exit(1) } @@ -70,7 +70,7 @@ func TestInit(t *testing.T) { testutils.AssertNotEqual(t, lastSyncAt, "", "last sync at should not be empty") } -func TestAddNote_NewBook_ContentFlag(t *testing.T) { +func TestAddNote_NewBook_BodyFlag(t *testing.T) { // Set up ctx := testutils.InitEnv(t, "./tmp", "./testutils/fixtures/schema.sql", true) defer testutils.TeardownEnv(ctx) @@ -92,17 +92,17 @@ func TestAddNote_NewBook_ContentFlag(t *testing.T) { testutils.MustScan(t, "getting book", db.QueryRow("SELECT uuid, dirty FROM books where label = ?", "js"), &book.UUID, &book.Dirty) var note core.Note testutils.MustScan(t, "getting note", - db.QueryRow("SELECT uuid, content, added_on, dirty FROM notes where book_uuid = ?", book.UUID), ¬e.UUID, ¬e.Content, ¬e.AddedOn, ¬e.Dirty) + db.QueryRow("SELECT uuid, body, added_on, dirty FROM notes where book_uuid = ?", book.UUID), ¬e.UUID, ¬e.Body, ¬e.AddedOn, ¬e.Dirty) testutils.AssertEqual(t, book.Dirty, true, "Book dirty mismatch") testutils.AssertNotEqual(t, note.UUID, "", "Note should have UUID") - testutils.AssertEqual(t, note.Content, "foo", "Note content mismatch") + testutils.AssertEqual(t, note.Body, "foo", "Note body mismatch") testutils.AssertEqual(t, note.Dirty, true, "Note dirty mismatch") testutils.AssertNotEqual(t, note.AddedOn, int64(0), "Note added_on mismatch") } -func TestAddNote_ExistingBook_ContentFlag(t *testing.T) { +func TestAddNote_ExistingBook_BodyFlag(t *testing.T) { // Set up ctx := testutils.InitEnv(t, "./tmp", "./testutils/fixtures/schema.sql", true) defer testutils.TeardownEnv(ctx) @@ -124,9 +124,9 @@ func TestAddNote_ExistingBook_ContentFlag(t *testing.T) { var n1, n2 core.Note testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, content, added_on, dirty FROM notes WHERE book_uuid = ? AND uuid = ?", "js-book-uuid", "43827b9a-c2b0-4c06-a290-97991c896653"), &n1.UUID, &n1.Content, &n1.AddedOn, &n1.Dirty) + db.QueryRow("SELECT uuid, body, added_on, dirty FROM notes WHERE book_uuid = ? AND uuid = ?", "js-book-uuid", "43827b9a-c2b0-4c06-a290-97991c896653"), &n1.UUID, &n1.Body, &n1.AddedOn, &n1.Dirty) testutils.MustScan(t, "getting n2", - db.QueryRow("SELECT uuid, content, added_on, dirty FROM notes WHERE book_uuid = ? AND content = ?", "js-book-uuid", "foo"), &n2.UUID, &n2.Content, &n2.AddedOn, &n2.Dirty) + db.QueryRow("SELECT uuid, body, added_on, dirty FROM notes WHERE book_uuid = ? AND body = ?", "js-book-uuid", "foo"), &n2.UUID, &n2.Body, &n2.AddedOn, &n2.Dirty) var book core.Book testutils.MustScan(t, "getting book", db.QueryRow("SELECT dirty FROM books where label = ?", "js"), &book.Dirty) @@ -134,16 +134,16 @@ func TestAddNote_ExistingBook_ContentFlag(t *testing.T) { testutils.AssertEqual(t, book.Dirty, false, "Book dirty mismatch") testutils.AssertNotEqual(t, n1.UUID, "", "n1 should have UUID") - testutils.AssertEqual(t, n1.Content, "Booleans have toString()", "n1 content mismatch") + testutils.AssertEqual(t, n1.Body, "Booleans have toString()", "n1 body mismatch") testutils.AssertEqual(t, n1.AddedOn, int64(1515199943), "n1 added_on mismatch") testutils.AssertEqual(t, n1.Dirty, false, "n1 dirty mismatch") testutils.AssertNotEqual(t, n2.UUID, "", "n2 should have UUID") - testutils.AssertEqual(t, n2.Content, "foo", "n2 content mismatch") + testutils.AssertEqual(t, n2.Body, "foo", "n2 body mismatch") testutils.AssertEqual(t, n2.Dirty, true, "n2 dirty mismatch") } -func TestEditNote_ContentFlag(t *testing.T) { +func TestEditNote_BodyFlag(t *testing.T) { // Set up ctx := testutils.InitEnv(t, "./tmp", "./testutils/fixtures/schema.sql", true) defer testutils.TeardownEnv(ctx) @@ -165,16 +165,16 @@ func TestEditNote_ContentFlag(t *testing.T) { var n1, n2 core.Note testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, content, added_on, dirty FROM notes where book_uuid = ? AND uuid = ?", "js-book-uuid", "43827b9a-c2b0-4c06-a290-97991c896653"), &n1.UUID, &n1.Content, &n1.AddedOn, &n1.Dirty) + db.QueryRow("SELECT uuid, body, added_on, dirty FROM notes where book_uuid = ? AND uuid = ?", "js-book-uuid", "43827b9a-c2b0-4c06-a290-97991c896653"), &n1.UUID, &n1.Body, &n1.AddedOn, &n1.Dirty) testutils.MustScan(t, "getting n2", - db.QueryRow("SELECT uuid, content, added_on, dirty FROM notes where book_uuid = ? AND uuid = ?", "js-book-uuid", "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f"), &n2.UUID, &n2.Content, &n2.AddedOn, &n2.Dirty) + db.QueryRow("SELECT uuid, body, added_on, dirty FROM notes where book_uuid = ? AND uuid = ?", "js-book-uuid", "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f"), &n2.UUID, &n2.Body, &n2.AddedOn, &n2.Dirty) testutils.AssertEqual(t, n1.UUID, "43827b9a-c2b0-4c06-a290-97991c896653", "n1 should have UUID") - testutils.AssertEqual(t, n1.Content, "Booleans have toString()", "n1 content mismatch") + testutils.AssertEqual(t, n1.Body, "Booleans have toString()", "n1 body mismatch") testutils.AssertEqual(t, n1.Dirty, false, "n1 dirty mismatch") testutils.AssertEqual(t, n2.UUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "Note should have UUID") - testutils.AssertEqual(t, n2.Content, "foo bar", "Note content mismatch") + testutils.AssertEqual(t, n2.Body, "foo bar", "Note body mismatch") testutils.AssertEqual(t, n2.Dirty, true, "n2 dirty mismatch") testutils.AssertNotEqual(t, n2.EditedOn, 0, "Note edited_on mismatch") } @@ -212,14 +212,14 @@ func TestRemoveNote(t *testing.T) { db.QueryRow("SELECT label, deleted, usn FROM books WHERE uuid = ?", "linux-book-uuid"), &b2.Label, &b2.Deleted, &b2.USN) testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, content, added_on, deleted, dirty, usn FROM notes WHERE book_uuid = ? AND id = ?", "js-book-uuid", 1), - &n1.UUID, &n1.Content, &n1.AddedOn, &n1.Deleted, &n1.Dirty, &n1.USN) + db.QueryRow("SELECT uuid, body, added_on, deleted, dirty, usn FROM notes WHERE book_uuid = ? AND uuid = ?", "js-book-uuid", "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f"), + &n1.UUID, &n1.Body, &n1.AddedOn, &n1.Deleted, &n1.Dirty, &n1.USN) testutils.MustScan(t, "getting n2", - db.QueryRow("SELECT uuid, content, added_on, deleted, dirty, usn FROM notes WHERE book_uuid = ? AND id = ?", "js-book-uuid", 2), - &n2.UUID, &n2.Content, &n2.AddedOn, &n2.Deleted, &n2.Dirty, &n2.USN) + db.QueryRow("SELECT uuid, body, added_on, deleted, dirty, usn FROM notes WHERE book_uuid = ? AND uuid = ?", "js-book-uuid", "43827b9a-c2b0-4c06-a290-97991c896653"), + &n2.UUID, &n2.Body, &n2.AddedOn, &n2.Deleted, &n2.Dirty, &n2.USN) testutils.MustScan(t, "getting n3", - db.QueryRow("SELECT uuid, content, added_on, deleted, dirty, usn FROM notes WHERE book_uuid = ? AND id = ?", "linux-book-uuid", 3), - &n3.UUID, &n3.Content, &n3.AddedOn, &n3.Deleted, &n3.Dirty, &n3.USN) + db.QueryRow("SELECT uuid, body, added_on, deleted, dirty, usn FROM notes WHERE book_uuid = ? AND uuid = ?", "linux-book-uuid", "3e065d55-6d47-42f2-a6bf-f5844130b2d2"), + &n3.UUID, &n3.Body, &n3.AddedOn, &n3.Deleted, &n3.Dirty, &n3.USN) testutils.AssertEqual(t, b1.Label, "js", "b1 label mismatch") testutils.AssertEqual(t, b1.Deleted, false, "b1 deleted mismatch") @@ -232,19 +232,19 @@ func TestRemoveNote(t *testing.T) { testutils.AssertEqual(t, b2.USN, 122, "b2 usn mismatch") testutils.AssertEqual(t, n1.UUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "n1 should have UUID") - testutils.AssertEqual(t, n1.Content, "", "n1 content mismatch") + testutils.AssertEqual(t, n1.Body, "", "n1 body mismatch") testutils.AssertEqual(t, n1.Deleted, true, "n1 deleted mismatch") testutils.AssertEqual(t, n1.Dirty, true, "n1 Dirty mismatch") testutils.AssertEqual(t, n1.USN, 11, "n1 usn mismatch") testutils.AssertEqual(t, n2.UUID, "43827b9a-c2b0-4c06-a290-97991c896653", "n2 should have UUID") - testutils.AssertEqual(t, n2.Content, "n2 content", "n2 content mismatch") + testutils.AssertEqual(t, n2.Body, "n2 body", "n2 body mismatch") testutils.AssertEqual(t, n2.Deleted, false, "n2 deleted mismatch") testutils.AssertEqual(t, n2.Dirty, false, "n2 Dirty mismatch") testutils.AssertEqual(t, n2.USN, 12, "n2 usn mismatch") testutils.AssertEqual(t, n3.UUID, "3e065d55-6d47-42f2-a6bf-f5844130b2d2", "n3 should have UUID") - testutils.AssertEqual(t, n3.Content, "n3 content", "n3 content mismatch") + testutils.AssertEqual(t, n3.Body, "n3 body", "n3 body mismatch") testutils.AssertEqual(t, n3.Deleted, false, "n3 deleted mismatch") testutils.AssertEqual(t, n3.Dirty, false, "n3 Dirty mismatch") testutils.AssertEqual(t, n3.USN, 13, "n3 usn mismatch") @@ -283,14 +283,14 @@ func TestRemoveBook(t *testing.T) { db.QueryRow("SELECT label, dirty, deleted, usn FROM books WHERE uuid = ?", "linux-book-uuid"), &b2.Label, &b2.Dirty, &b2.Deleted, &b2.USN) testutils.MustScan(t, "getting n1", - db.QueryRow("SELECT uuid, content, added_on, dirty, deleted, usn FROM notes WHERE book_uuid = ? AND id = ?", "js-book-uuid", 1), - &n1.UUID, &n1.Content, &n1.AddedOn, &n1.Deleted, &n1.Dirty, &n1.USN) + db.QueryRow("SELECT uuid, body, added_on, dirty, deleted, usn FROM notes WHERE book_uuid = ? AND uuid = ?", "js-book-uuid", "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f"), + &n1.UUID, &n1.Body, &n1.AddedOn, &n1.Deleted, &n1.Dirty, &n1.USN) testutils.MustScan(t, "getting n2", - db.QueryRow("SELECT uuid, content, added_on, dirty, deleted, usn FROM notes WHERE book_uuid = ? AND id = ?", "js-book-uuid", 2), - &n2.UUID, &n2.Content, &n2.AddedOn, &n2.Deleted, &n2.Dirty, &n2.USN) + db.QueryRow("SELECT uuid, body, added_on, dirty, deleted, usn FROM notes WHERE book_uuid = ? AND uuid = ?", "js-book-uuid", "43827b9a-c2b0-4c06-a290-97991c896653"), + &n2.UUID, &n2.Body, &n2.AddedOn, &n2.Deleted, &n2.Dirty, &n2.USN) testutils.MustScan(t, "getting n3", - db.QueryRow("SELECT uuid, content, added_on, dirty, deleted, usn FROM notes WHERE book_uuid = ? AND id = ?", "linux-book-uuid", 3), - &n3.UUID, &n3.Content, &n3.AddedOn, &n3.Deleted, &n3.Dirty, &n3.USN) + db.QueryRow("SELECT uuid, body, added_on, dirty, deleted, usn FROM notes WHERE book_uuid = ? AND uuid = ?", "linux-book-uuid", "3e065d55-6d47-42f2-a6bf-f5844130b2d2"), + &n3.UUID, &n3.Body, &n3.AddedOn, &n3.Deleted, &n3.Dirty, &n3.USN) testutils.AssertNotEqual(t, b1.Label, "js", "b1 label mismatch") testutils.AssertEqual(t, b1.Dirty, true, "b1 Dirty mismatch") @@ -303,19 +303,19 @@ func TestRemoveBook(t *testing.T) { testutils.AssertEqual(t, b2.USN, 122, "b2 usn mismatch") testutils.AssertEqual(t, n1.UUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "n1 should have UUID") - testutils.AssertEqual(t, n1.Content, "", "n1 content mismatch") + testutils.AssertEqual(t, n1.Body, "", "n1 body mismatch") testutils.AssertEqual(t, n1.Dirty, true, "n1 Dirty mismatch") testutils.AssertEqual(t, n1.Deleted, true, "n1 deleted mismatch") testutils.AssertEqual(t, n1.USN, 11, "n1 usn mismatch") testutils.AssertEqual(t, n2.UUID, "43827b9a-c2b0-4c06-a290-97991c896653", "n2 should have UUID") - testutils.AssertEqual(t, n2.Content, "", "n2 content mismatch") + testutils.AssertEqual(t, n2.Body, "", "n2 body mismatch") testutils.AssertEqual(t, n2.Dirty, true, "n2 Dirty mismatch") testutils.AssertEqual(t, n2.Deleted, true, "n2 deleted mismatch") testutils.AssertEqual(t, n2.USN, 12, "n2 usn mismatch") testutils.AssertEqual(t, n3.UUID, "3e065d55-6d47-42f2-a6bf-f5844130b2d2", "n3 should have UUID") - testutils.AssertEqual(t, n3.Content, "n3 content", "n3 content mismatch") + testutils.AssertEqual(t, n3.Body, "n3 body", "n3 body mismatch") testutils.AssertEqual(t, n3.Dirty, false, "n3 Dirty mismatch") testutils.AssertEqual(t, n3.Deleted, false, "n3 deleted mismatch") testutils.AssertEqual(t, n3.USN, 13, "n3 usn mismatch") diff --git a/migrate/fixtures/local-8-pre-schema.sql b/migrate/fixtures/local-8-pre-schema.sql new file mode 100644 index 00000000..c0e908b6 --- /dev/null +++ b/migrate/fixtures/local-8-pre-schema.sql @@ -0,0 +1,25 @@ +CREATE TABLE notes + ( + id integer PRIMARY KEY AUTOINCREMENT, + uuid text NOT NULL, + book_uuid text NOT NULL, + content text NOT NULL, + added_on integer NOT NULL, + edited_on integer DEFAULT 0, + public bool DEFAULT false + , dirty bool DEFAULT false, usn int DEFAULT 0 NOT NULL, deleted bool DEFAULT false); +CREATE TABLE books + ( + uuid text PRIMARY KEY, + label text NOT NULL + , dirty bool DEFAULT false, usn int DEFAULT 0 NOT NULL, deleted bool DEFAULT false); +CREATE TABLE system + ( + key string NOT NULL, + value text NOT NULL + ); +CREATE UNIQUE INDEX idx_books_label ON books(label); +CREATE UNIQUE INDEX idx_notes_uuid ON notes(uuid); +CREATE UNIQUE INDEX idx_books_uuid ON books(uuid); +CREATE UNIQUE INDEX idx_notes_id ON notes(id); +CREATE INDEX idx_notes_book_uuid ON notes(book_uuid); diff --git a/migrate/fixtures/local-9-pre-schema.sql b/migrate/fixtures/local-9-pre-schema.sql new file mode 100644 index 00000000..1e266e9f --- /dev/null +++ b/migrate/fixtures/local-9-pre-schema.sql @@ -0,0 +1,23 @@ +CREATE TABLE notes + ( + uuid text NOT NULL, + book_uuid text NOT NULL, + body text NOT NULL, + added_on integer NOT NULL, + edited_on integer DEFAULT 0, + public bool DEFAULT false + , dirty bool DEFAULT false, usn int DEFAULT 0 NOT NULL, deleted bool DEFAULT false); +CREATE TABLE books + ( + uuid text PRIMARY KEY, + label text NOT NULL + , dirty bool DEFAULT false, usn int DEFAULT 0 NOT NULL, deleted bool DEFAULT false); +CREATE TABLE system + ( + key string NOT NULL, + value text NOT NULL + ); +CREATE UNIQUE INDEX idx_books_label ON books(label); +CREATE UNIQUE INDEX idx_notes_uuid ON notes(uuid); +CREATE UNIQUE INDEX idx_books_uuid ON books(uuid); +CREATE INDEX idx_notes_book_uuid ON notes(book_uuid); diff --git a/migrate/migrate.go b/migrate/migrate.go index 0b5856b1..1b53c940 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -23,6 +23,9 @@ var LocalSequence = []migration{ lm4, lm5, lm6, + lm7, + lm8, + lm9, } // RemoteSequence is a list of remote migrations to be run diff --git a/migrate/migrate_test.go b/migrate/migrate_test.go index 279e45af..9c937163 100644 --- a/migrate/migrate_test.go +++ b/migrate/migrate_test.go @@ -763,6 +763,116 @@ func TestLocalMigration7_conflicts_dup(t *testing.T) { testutils.AssertEqual(t, b2Dirty, false, "b2 should not have been marked dirty") } +func TestLocalMigration8(t *testing.T) { + // set up + ctx := testutils.InitEnv(t, "../tmp", "./fixtures/local-8-pre-schema.sql", false) + defer testutils.TeardownEnv(ctx) + + db := ctx.DB + + b1UUID := utils.GenerateUUID() + testutils.MustExec(t, "inserting book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1") + + n1UUID := utils.GenerateUUID() + testutils.MustExec(t, "inserting n1", db, `INSERT INTO notes + (id, uuid, book_uuid, content, added_on, edited_on, public, dirty, usn, deleted) VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, 1, n1UUID, b1UUID, "n1 Body", 1, 2, true, true, 20, false) + n2UUID := utils.GenerateUUID() + testutils.MustExec(t, "inserting n2", db, `INSERT INTO notes + (id, uuid, book_uuid, content, added_on, edited_on, public, dirty, usn, deleted) VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, 2, n2UUID, b1UUID, "", 3, 4, false, true, 21, true) + + // Execute + tx, err := db.Begin() + if err != nil { + t.Fatal(errors.Wrap(err, "beginning a transaction")) + } + + err = lm8.run(ctx, tx) + if err != nil { + tx.Rollback() + t.Fatal(errors.Wrap(err, "failed to run")) + } + + tx.Commit() + + // Test + var n1BookUUID, n1Body string + var n1AddedOn, n1EditedOn int64 + var n1USN int + var n1Public, n1Dirty, n1Deleted bool + testutils.MustScan(t, "scanning n1", db.QueryRow("SELECT book_uuid, body, added_on, edited_on, usn, public, dirty, deleted FROM notes WHERE uuid = ?", n1UUID), &n1BookUUID, &n1Body, &n1AddedOn, &n1EditedOn, &n1USN, &n1Public, &n1Dirty, &n1Deleted) + + var n2BookUUID, n2Body string + var n2AddedOn, n2EditedOn int64 + var n2USN int + var n2Public, n2Dirty, n2Deleted bool + testutils.MustScan(t, "scanning n2", db.QueryRow("SELECT book_uuid, body, added_on, edited_on, usn, public, dirty, deleted FROM notes WHERE uuid = ?", n2UUID), &n2BookUUID, &n2Body, &n2AddedOn, &n2EditedOn, &n2USN, &n2Public, &n2Dirty, &n2Deleted) + + testutils.AssertEqual(t, n1BookUUID, b1UUID, "n1 BookUUID mismatch") + testutils.AssertEqual(t, n1Body, "n1 Body", "n1 Body mismatch") + testutils.AssertEqual(t, n1AddedOn, int64(1), "n1 AddedOn mismatch") + testutils.AssertEqual(t, n1EditedOn, int64(2), "n1 EditedOn mismatch") + testutils.AssertEqual(t, n1USN, 20, "n1 USN mismatch") + testutils.AssertEqual(t, n1Public, true, "n1 Public mismatch") + testutils.AssertEqual(t, n1Dirty, true, "n1 Dirty mismatch") + testutils.AssertEqual(t, n1Deleted, false, "n1 Deleted mismatch") + + testutils.AssertEqual(t, n2BookUUID, b1UUID, "n2 BookUUID mismatch") + testutils.AssertEqual(t, n2Body, "", "n2 Body mismatch") + testutils.AssertEqual(t, n2AddedOn, int64(3), "n2 AddedOn mismatch") + testutils.AssertEqual(t, n2EditedOn, int64(4), "n2 EditedOn mismatch") + testutils.AssertEqual(t, n2USN, 21, "n2 USN mismatch") + testutils.AssertEqual(t, n2Public, false, "n2 Public mismatch") + testutils.AssertEqual(t, n2Dirty, true, "n2 Dirty mismatch") + testutils.AssertEqual(t, n2Deleted, true, "n2 Deleted mismatch") +} + +func TestLocalMigration9(t *testing.T) { + // set up + ctx := testutils.InitEnv(t, "../tmp", "./fixtures/local-9-pre-schema.sql", false) + defer testutils.TeardownEnv(ctx) + + db := ctx.DB + + b1UUID := utils.GenerateUUID() + testutils.MustExec(t, "inserting book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "b1") + + n1UUID := utils.GenerateUUID() + testutils.MustExec(t, "inserting n1", db, `INSERT INTO notes + (uuid, book_uuid, body, added_on, edited_on, public, dirty, usn, deleted) VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?)`, n1UUID, b1UUID, "n1 Body", 1, 2, true, true, 20, false) + n2UUID := utils.GenerateUUID() + testutils.MustExec(t, "inserting n2", db, `INSERT INTO notes + (uuid, book_uuid, body, added_on, edited_on, public, dirty, usn, deleted) VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?)`, n2UUID, b1UUID, "n2 Body", 3, 4, false, true, 21, false) + + // Execute + tx, err := db.Begin() + if err != nil { + t.Fatal(errors.Wrap(err, "beginning a transaction")) + } + + err = lm9.run(ctx, tx) + if err != nil { + tx.Rollback() + t.Fatal(errors.Wrap(err, "failed to run")) + } + + tx.Commit() + + // Test + + // assert that note_fts was populated with correct values + var noteFtsCount int + testutils.MustScan(t, "counting note_fts", db.QueryRow("SELECT count(*) FROM note_fts;"), ¬eFtsCount) + testutils.AssertEqual(t, noteFtsCount, 2, "noteFtsCount mismatch") + + var resCount int + testutils.MustScan(t, "counting result", db.QueryRow("SELECT count(*) FROM note_fts WHERE note_fts MATCH ?", "n1"), &resCount) + testutils.AssertEqual(t, resCount, 1, "noteFtsCount mismatch") +} + func TestRemoteMigration1(t *testing.T) { // set up ctx := testutils.InitEnv(t, "../tmp", "./fixtures/remote-1-pre-schema.sql", false) diff --git a/migrate/migrations.go b/migrate/migrations.go index abf6dc09..100350b2 100644 --- a/migrate/migrations.go +++ b/migrate/migrations.go @@ -311,6 +311,81 @@ var lm7 = migration{ }, } +var lm8 = migration{ + name: "drop-note-id-and-rename-content-to-body", + run: func(ctx infra.DnoteCtx, tx *sql.Tx) error { + _, err := tx.Exec(`CREATE TABLE notes_tmp + ( + uuid text NOT NULL, + book_uuid text NOT NULL, + body text NOT NULL, + added_on integer NOT NULL, + edited_on integer DEFAULT 0, + public bool DEFAULT false, + dirty bool DEFAULT false, + usn int DEFAULT 0 NOT NULL, + deleted bool DEFAULT false + );`) + if err != nil { + return errors.Wrap(err, "creating temporary notes table for migration") + } + + _, err = tx.Exec(`INSERT INTO notes_tmp + SELECT uuid, book_uuid, content, added_on, edited_on, public, dirty, usn, deleted FROM notes;`) + if err != nil { + return errors.Wrap(err, "copying data to new table") + } + + _, err = tx.Exec(`DROP TABLE notes;`) + if err != nil { + return errors.Wrap(err, "dropping the notes table") + } + + _, err = tx.Exec(`ALTER TABLE notes_tmp RENAME to notes;`) + if err != nil { + return errors.Wrap(err, "renaming the temporary notes table") + } + + return nil + }, +} + +var lm9 = migration{ + name: "create-fts-index", + run: func(ctx infra.DnoteCtx, tx *sql.Tx) error { + _, err := tx.Exec(`CREATE VIRTUAL TABLE IF NOT EXISTS note_fts USING fts5(content=notes, body, tokenize="porter unicode61 categories 'L* N* Co Ps Pe'");`) + if err != nil { + return errors.Wrap(err, "creating note_fts") + } + + // Create triggers to keep the indices in note_fts in sync with notes + _, err = tx.Exec(` + CREATE TRIGGER notes_after_insert AFTER INSERT ON notes BEGIN + INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body); + END; + CREATE TRIGGER notes_after_delete AFTER DELETE ON notes BEGIN + INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body); + END; + CREATE TRIGGER notes_after_update AFTER UPDATE ON notes BEGIN + INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body); + INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body); + END; + `) + if err != nil { + return errors.Wrap(err, "creating triggers for note_fts") + } + + // populate fts indices + _, err = tx.Exec(`INSERT INTO note_fts (rowid, body) + SELECT rowid, body FROM notes;`) + if err != nil { + return errors.Wrap(err, "populating note_fts") + } + + return nil + }, +} + var rm1 = migration{ name: "sync-book-uuids-from-server", run: func(ctx infra.DnoteCtx, tx *sql.Tx) error { diff --git a/scripts/build.sh b/scripts/build.sh index 80cb6ed4..62b28415 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -38,6 +38,8 @@ build() { pushd "$basedir" + # TODO: do i need to pass fts5 tag? + # build linux xgo --targets="linux/amd64"\ -ldflags "-X main.apiEndpoint=https://api.dnote.io -X main.versionTag=$version" . diff --git a/scripts/dev.sh b/scripts/dev.sh index b47d610c..cf7d794f 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -5,6 +5,6 @@ sudo rm "$(which dnote)" $GOPATH/bin/cli # change tags to darwin if on macos -go install -ldflags "-X main.apiEndpoint=http://127.0.0.1:5000" --tags "linux" . +go install -ldflags "-X main.apiEndpoint=http://127.0.0.1:5000" --tags "linux fts5" . sudo ln -s $GOPATH/bin/cli /usr/local/bin/dnote diff --git a/scripts/release.sh b/scripts/release.sh index 0a9adb41..0b3c1994 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -6,6 +6,8 @@ set -eu +homebrewRepoDir="$GOPATH"/src/github.com/dnote/homebrew-dnote + command_exists () { command -v "$1" >/dev/null 2>&1; } @@ -24,6 +26,13 @@ if ! command_exists hub; then exit 1 fi +if [ ! -d $homebrewRepoDir ]; then + echo "homebrew-dnote not found locally. did you clone it?" + exit 1 +fi + +if [ -d ] + # 1. push tag version=$1 version_tag="v$version" @@ -48,4 +57,4 @@ hub release create \ # 3. Release on Homebrew homebrew_sha256=$(shasum -a 256 "./build/dnote_${version}_darwin_amd64.tar.gz" | cut -d ' ' -f 1) -(cd "$GOPATH"/src/github.com/dnote/homebrew-dnote && ./release.sh "$version" "$homebrew_sha256") +(cd $homebrewRepoDir && ./release.sh "$version" "$homebrew_sha256") diff --git a/scripts/test.sh b/scripts/test.sh index 66df3309..6e322de9 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -7,5 +7,6 @@ rm -rf ./tmp # run test -go test ./... -p 1 - +go test ./... \ + -p 1\ + --tags "fts5" diff --git a/testutils/fixtures/schema.sql b/testutils/fixtures/schema.sql index c0e908b6..6723608b 100644 --- a/testutils/fixtures/schema.sql +++ b/testutils/fixtures/schema.sql @@ -1,13 +1,3 @@ -CREATE TABLE notes - ( - id integer PRIMARY KEY AUTOINCREMENT, - uuid text NOT NULL, - book_uuid text NOT NULL, - content text NOT NULL, - added_on integer NOT NULL, - edited_on integer DEFAULT 0, - public bool DEFAULT false - , dirty bool DEFAULT false, usn int DEFAULT 0 NOT NULL, deleted bool DEFAULT false); CREATE TABLE books ( uuid text PRIMARY KEY, @@ -19,7 +9,43 @@ CREATE TABLE system value text NOT NULL ); CREATE UNIQUE INDEX idx_books_label ON books(label); -CREATE UNIQUE INDEX idx_notes_uuid ON notes(uuid); CREATE UNIQUE INDEX idx_books_uuid ON books(uuid); -CREATE UNIQUE INDEX idx_notes_id ON notes(id); +CREATE TABLE actions + ( + uuid text PRIMARY KEY, + schema integer NOT NULL, + type text NOT NULL, + data text NOT NULL, + timestamp integer NOT NULL + ); +CREATE TABLE IF NOT EXISTS "notes" + ( + uuid text NOT NULL, + book_uuid text NOT NULL, + body text NOT NULL, + added_on integer NOT NULL, + edited_on integer DEFAULT 0, + public bool DEFAULT false, + dirty bool DEFAULT false, + usn int DEFAULT 0 NOT NULL, + deleted bool DEFAULT false + ); +CREATE VIRTUAL TABLE note_fts + USING fts5(content=notes, body, tokenize = "unicode61") +/* note_fts(body) */; +CREATE TABLE IF NOT EXISTS 'note_fts_data'(id INTEGER PRIMARY KEY, block BLOB); +CREATE TABLE IF NOT EXISTS 'note_fts_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID; +CREATE TABLE IF NOT EXISTS 'note_fts_docsize'(id INTEGER PRIMARY KEY, sz BLOB); +CREATE TABLE IF NOT EXISTS 'note_fts_config'(k PRIMARY KEY, v) WITHOUT ROWID; +CREATE TRIGGER notes_after_insert AFTER INSERT ON notes BEGIN + INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body); + END; +CREATE TRIGGER notes_after_delete AFTER DELETE ON notes BEGIN + INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body); + END; +CREATE TRIGGER notes_after_update AFTER UPDATE ON notes BEGIN + INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body); + INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body); + END; +CREATE UNIQUE INDEX idx_notes_uuid ON notes(uuid); CREATE INDEX idx_notes_book_uuid ON notes(book_uuid); diff --git a/testutils/main.go b/testutils/main.go index d5b980c9..7ae009f1 100644 --- a/testutils/main.go +++ b/testutils/main.go @@ -49,7 +49,7 @@ func InitEnv(t *testing.T, relPath string, relFixturePath string, migrated bool) if migrated { // mark migrations as done. When adding new migrations, bump the numbers here. - if _, err := db.Exec("INSERT INTO system (key, value) VALUES (? , ?);", infra.SystemSchema, 6); err != nil { + if _, err := db.Exec("INSERT INTO system (key, value) VALUES (? , ?);", infra.SystemSchema, 9); err != nil { t.Fatal(errors.Wrap(err, "inserting schema")) } diff --git a/testutils/setup.go b/testutils/setup.go index 03e59b4d..3febbcc8 100644 --- a/testutils/setup.go +++ b/testutils/setup.go @@ -16,7 +16,7 @@ func Setup1(t *testing.T, ctx infra.DnoteCtx) { MustExec(t, "setting up book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "js") MustExec(t, "setting up book 2", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b2UUID, "linux") - MustExec(t, "setting up note 1", db, "INSERT INTO notes (uuid, book_uuid, content, added_on) VALUES (?, ?, ?, ?)", "43827b9a-c2b0-4c06-a290-97991c896653", b1UUID, "Booleans have toString()", 1515199943) + MustExec(t, "setting up note 1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?)", "43827b9a-c2b0-4c06-a290-97991c896653", b1UUID, "Booleans have toString()", 1515199943) } // Setup2 sets up a dnote env #2 @@ -30,9 +30,9 @@ func Setup2(t *testing.T, ctx infra.DnoteCtx) { MustExec(t, "setting up book 1", db, "INSERT INTO books (uuid, label, usn) VALUES (?, ?, ?)", b1UUID, "js", 111) MustExec(t, "setting up book 2", db, "INSERT INTO books (uuid, label, usn) VALUES (?, ?, ?)", b2UUID, "linux", 122) - MustExec(t, "setting up note 1", db, "INSERT INTO notes (id, uuid, book_uuid, content, added_on, usn) VALUES (?, ?, ?, ?, ?, ?)", 1, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", b1UUID, "n1 content", 1515199951, 11) - MustExec(t, "setting up note 2", db, "INSERT INTO notes (id, uuid, book_uuid, content, added_on, usn) VALUES (?, ?, ?, ?, ?, ?)", 2, "43827b9a-c2b0-4c06-a290-97991c896653", b1UUID, "n2 content", 1515199943, 12) - MustExec(t, "setting up note 3", db, "INSERT INTO notes (id, uuid, book_uuid, content, added_on, usn) VALUES (?, ?, ?, ?, ?, ?)", 3, "3e065d55-6d47-42f2-a6bf-f5844130b2d2", b2UUID, "n3 content", 1515199961, 13) + MustExec(t, "setting up note 1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, usn) VALUES (?, ?, ?, ?, ?)", "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", b1UUID, "n1 body", 1515199951, 11) + MustExec(t, "setting up note 2", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, usn) VALUES (?, ?, ?, ?, ?)", "43827b9a-c2b0-4c06-a290-97991c896653", b1UUID, "n2 body", 1515199943, 12) + MustExec(t, "setting up note 3", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, usn) VALUES (?, ?, ?, ?, ?)", "3e065d55-6d47-42f2-a6bf-f5844130b2d2", b2UUID, "n3 body", 1515199961, 13) } // Setup3 sets up a dnote env #1 @@ -44,7 +44,7 @@ func Setup3(t *testing.T, ctx infra.DnoteCtx) { MustExec(t, "setting up book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "js") - MustExec(t, "setting up note 1", db, "INSERT INTO notes (uuid, book_uuid, content, added_on) VALUES (?, ?, ?, ?)", "43827b9a-c2b0-4c06-a290-97991c896653", b1UUID, "Booleans have toString()", 1515199943) + MustExec(t, "setting up note 1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?)", "43827b9a-c2b0-4c06-a290-97991c896653", b1UUID, "Booleans have toString()", 1515199943) } // Setup4 sets up a dnote env #1 @@ -56,6 +56,6 @@ func Setup4(t *testing.T, ctx infra.DnoteCtx) { MustExec(t, "setting up book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "js") - MustExec(t, "setting up note 1", db, "INSERT INTO notes (id, uuid, book_uuid, content, added_on) VALUES (?, ?, ?, ?, ?)", 1, "43827b9a-c2b0-4c06-a290-97991c896653", b1UUID, "Booleans have toString()", 1515199943) - MustExec(t, "setting up note 2", db, "INSERT INTO notes (id, uuid, book_uuid, content, added_on) VALUES (?, ?, ?, ?, ?)", 2, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", b1UUID, "Date object implements mathematical comparisons", 1515199951) + MustExec(t, "setting up note 1", db, "INSERT INTO notes (rowid, uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?, ?)", 1, "43827b9a-c2b0-4c06-a290-97991c896653", b1UUID, "Booleans have toString()", 1515199943) + MustExec(t, "setting up note 2", db, "INSERT INTO notes (rowid, uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?, ?)", 2, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", b1UUID, "Date object implements mathematical comparisons", 1515199951) }