Find command (#149)

* Implement basic full text search

* Avoid lag in log while making network calls

* Allow to restrict search by book name
This commit is contained in:
Sung Won Cho 2019-01-01 14:59:57 +11:00 committed by GitHub
commit 14b0cf623f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1181 additions and 338 deletions

View file

@ -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

6
Gopkg.lock generated
View file

@ -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"

View file

@ -47,4 +47,4 @@
[[constraint]]
name = "github.com/mattn/go-sqlite3"
version = "1.9.0"
version = "1.10.0"

View file

@ -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)

View file

@ -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 <content>",
Use: "add <book>",
Short: "Add a note",
Aliases: []string{"a", "n", "new"},
Example: example,

View file

@ -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")
}

View file

@ -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(&noteUUID, &oldContent)
err = db.QueryRow("SELECT uuid, body FROM notes WHERE rowid = ? AND book_uuid = ?", noteRowID, bookUUID).Scan(&noteUUID, &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")

180
cmd/find/find.go Normal file
View file

@ -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, '<dnotehl>', '</dnotehl>', '...', 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
}
}

82
cmd/find/lexer.go Normal file
View file

@ -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 == "<dnotehl>" {
nextIdx := getNextIdx(idx+lookahead, s)
return token{Kind: tokenKindHLBegin}, nextIdx
}
}
if len(s)-idx >= 10 {
lookahead := 10
candidate := s[idx : idx+lookahead]
if candidate == "</dnotehl>" {
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
}

213
cmd/find/lexer_test.go Normal file
View file

@ -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 <bar>",
idx: 4,
retTok: token{Value: '<', Kind: tokenKindChar},
retIdx: 5,
},
{
input: "foo <dnotehL>",
idx: 4,
retTok: token{Value: '<', Kind: tokenKindChar},
retIdx: 5,
},
{
input: "foo <dnotehl>bar</dnotehl> foo bar",
idx: 4,
retTok: token{Kind: tokenKindHLBegin},
retIdx: 13,
},
{
input: "foo <dnotehl>bar</dnotehl> <dnotehl>foo</dnotehl> bar",
idx: 4,
retTok: token{Kind: tokenKindHLBegin},
retIdx: 13,
},
{
input: "foo <dnotehl>bar</dnotehl> <dnotehl>foo</dnotehl> bar",
idx: 27,
retTok: token{Kind: tokenKindHLBegin},
retIdx: 36,
},
{
input: "foo <dnotehl>bar</dnotehl> foo bar",
idx: 13,
retTok: token{Value: 'b', Kind: tokenKindChar},
retIdx: 14,
},
{
input: "foo <dnotehl>bar</dnotehl> foo bar",
idx: 16,
retTok: token{Kind: tokenKindHLEnd},
retIdx: 26,
},
{
input: "<dno<dnotehl>tehl>",
idx: 0,
retTok: token{Value: '<', Kind: tokenKindChar},
retIdx: 1,
},
{
input: "<dno<dnotehl>tehl>",
idx: 4,
retTok: token{Kind: tokenKindHLBegin},
retIdx: 13,
},
{
input: "foo <dnotehl>bar</dnotehl>",
idx: 16,
retTok: token{Kind: tokenKindHLEnd},
retIdx: -1,
},
// user writes reserved token
{
input: "foo <dnotehl>",
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: "ab<dnotehl>c</dnotehl>",
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: "ab<dnotehl>c</dnotehl>d",
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: "<dnotehl><dnotehl></dnotehl>",
tokens: []token{
token{
Kind: tokenKindHLBegin,
},
token{
Kind: tokenKindHLBegin,
},
token{
Kind: tokenKindHLEnd,
},
token{
Kind: tokenKindEOL,
},
},
},
{
input: "<dnotehl></dnotehl></dnotehl>",
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")
})
}
}

View file

@ -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

View file

@ -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(&noteUUID, &noteContent)
err = db.QueryRow("SELECT uuid, body FROM notes WHERE rowid = ? AND book_uuid = ?", noteRowID, bookUUID).Scan(&noteUUID, &noteContent)
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")
}

View file

@ -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(&note.UUID, &note.BookUUID, &note.Content, &note.Public, &note.Deleted, &note.USN); err != nil {
if err = rows.Scan(&note.UUID, &note.BookUUID, &note.Body, &note.Public, &note.Deleted, &note.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 {

View file

@ -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()

View file

@ -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)

View file

@ -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"), &noteCount)
testutils.MustScan(t, "counting note_fts", db.QueryRow("SELECT count(*) FROM note_fts"), &noteFtsCount)
testutils.MustScan(t, "counting search results", db.QueryRow("SELECT count(*) FROM note_fts WHERE note_fts MATCH ?", "foo"), &noteSearchCount)
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"), &noteCount)
testutils.MustScan(t, "counting note_fts", db.QueryRow("SELECT count(*) FROM note_fts"), &noteFtsCount)
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"), &noteSearchCount)
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"), &noteSearchCount)
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"), &noteCount)
testutils.MustScan(t, "counting note_fts", db.QueryRow("SELECT count(*) FROM note_fts"), &noteFtsCount)
testutils.AssertEqual(t, noteCount, 0, "noteCount mismatch")
testutils.AssertEqual(t, noteFtsCount, 0, "noteFtsCount mismatch")
}

View file

@ -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")

View file

@ -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())

View file

@ -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), &note.UUID, &note.Content, &note.AddedOn, &note.Dirty)
db.QueryRow("SELECT uuid, body, added_on, dirty FROM notes where book_uuid = ?", book.UUID), &note.UUID, &note.Body, &note.AddedOn, &note.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")

View file

@ -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);

View file

@ -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);

View file

@ -23,6 +23,9 @@ var LocalSequence = []migration{
lm4,
lm5,
lm6,
lm7,
lm8,
lm9,
}
// RemoteSequence is a list of remote migrations to be run

View file

@ -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;"), &noteFtsCount)
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)

View file

@ -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 {

View file

@ -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" .

View file

@ -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

View file

@ -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")

View file

@ -7,5 +7,6 @@
rm -rf ./tmp
# run test
go test ./... -p 1
go test ./... \
-p 1\
--tags "fts5"

View file

@ -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);

View file

@ -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"))
}

View file

@ -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)
}