Merge dir and filename to simplify paths handling

pull/6/head
Mickaël Menu 3 years ago
parent 5988b020af
commit ea3b6923c0
No known key found for this signature in database
GPG Key ID: 53D73664CD359895

@ -2,7 +2,6 @@ package sqlite
import (
"database/sql"
"path/filepath"
"time"
"github.com/mickael-menu/zk/core/file"
@ -15,7 +14,6 @@ import (
// It implements the core ports note.Indexer and note.Finder.
type NoteDAO struct {
tx Transaction
root string
logger util.Logger
// Prepared SQL statements
@ -26,30 +24,29 @@ type NoteDAO struct {
existsStmt *LazyStmt
}
func NewNoteDAO(tx Transaction, root string, logger util.Logger) *NoteDAO {
func NewNoteDAO(tx Transaction, logger util.Logger) *NoteDAO {
return &NoteDAO{
tx: tx,
root: root,
logger: logger,
indexedStmt: tx.PrepareLazy(`
SELECT dir, filename, modified from notes
ORDER BY dir, filename ASC
SELECT path, modified from notes
ORDER BY path ASC
`),
addStmt: tx.PrepareLazy(`
INSERT INTO notes (dir, filename, title, body, word_count, checksum, created, modified)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
INSERT INTO notes (path, title, body, word_count, checksum, created, modified)
VALUES (?, ?, ?, ?, ?, ?, ?)
`),
updateStmt: tx.PrepareLazy(`
UPDATE notes
SET title = ?, body = ?, word_count = ?, checksum = ?, modified = ?
WHERE dir = ? AND filename = ?
WHERE path = ?
`),
removeStmt: tx.PrepareLazy(`
DELETE FROM notes
WHERE dir = ? AND filename = ?
WHERE path = ?
`),
existsStmt: tx.PrepareLazy(`
SELECT EXISTS (SELECT 1 FROM notes WHERE dir = ? AND filename = ?)
SELECT EXISTS (SELECT 1 FROM notes WHERE path = ?)
`),
}
}
@ -67,18 +64,18 @@ func (d *NoteDAO) Indexed() (<-chan file.Metadata, error) {
defer close(c)
defer rows.Close()
var (
dir, filename string
modified time.Time
path string
modified time.Time
)
for rows.Next() {
err := rows.Scan(&dir, &filename, &modified)
err := rows.Scan(&path, &modified)
if err != nil {
d.logger.Err(wrap(err))
}
c <- file.Metadata{
Path: file.Path{Dir: dir, Filename: filename, Abs: filepath.Join(d.root, dir, filename)},
Path: path,
Modified: modified,
}
}
@ -94,8 +91,7 @@ func (d *NoteDAO) Indexed() (<-chan file.Metadata, error) {
func (d *NoteDAO) Add(note note.Metadata) error {
_, err := d.addStmt.Exec(
note.Path.Dir, note.Path.Filename, note.Title,
note.Body, note.WordCount, note.Checksum,
note.Path, note.Title, note.Body, note.WordCount, note.Checksum,
note.Created, note.Modified,
)
return errors.Wrapf(err, "%v: can't add note to the index", note.Path)
@ -113,14 +109,13 @@ func (d *NoteDAO) Update(note note.Metadata) error {
}
_, err = d.updateStmt.Exec(
note.Title, note.Body, note.WordCount,
note.Checksum, note.Modified,
note.Path.Dir, note.Path.Filename,
note.Title, note.Body, note.WordCount, note.Checksum, note.Modified,
note.Path,
)
return errors.Wrapf(err, "%v: failed to update note index", note.Path)
}
func (d *NoteDAO) Remove(path file.Path) error {
func (d *NoteDAO) Remove(path string) error {
wrap := errors.Wrapperf("%v: failed to remove note index", path)
exists, err := d.exists(path)
@ -131,12 +126,12 @@ func (d *NoteDAO) Remove(path file.Path) error {
return wrap(errors.New("note not found in the index"))
}
_, err = d.removeStmt.Exec(path.Dir, path.Filename)
_, err = d.removeStmt.Exec(path)
return wrap(err)
}
func (d *NoteDAO) exists(path file.Path) (bool, error) {
row, err := d.existsStmt.QueryRow(path.Dir, path.Filename)
func (d *NoteDAO) exists(path string) (bool, error) {
row, err := d.existsStmt.QueryRow(path)
if err != nil {
return false, err
}
@ -152,14 +147,14 @@ func (d *NoteDAO) Find(callback func(note.Match) error, filters ...note.Filter)
rows, err := func() (*sql.Rows, error) {
if len(filters) == 0 {
return d.tx.Query(`
SELECT id, dir, filename, title, body, word_count, created, modified,
SELECT id, path, title, body, word_count, created, modified,
checksum, "" as snippet from notes
ORDER BY title ASC
`)
} else {
filter := filters[0].(note.QueryFilter)
return d.tx.Query(`
SELECT n.id, n.dir, n.filename, n.title, n.body, n.word_count,
SELECT n.id, n.path, n.title, n.body, n.word_count,
n.created, n.modified, n.checksum,
snippet(notes_fts, -1, '<zk:match>', '</zk:match>', '…', 20) as snippet
FROM notes n
@ -179,13 +174,13 @@ func (d *NoteDAO) Find(callback func(note.Match) error, filters ...note.Filter)
for rows.Next() {
var (
id, wordCount int
title, body, snippet string
dir, filename, checksum string
created, modified time.Time
id, wordCount int
title, body, snippet string
path, checksum string
created, modified time.Time
)
err := rows.Scan(&id, &dir, &filename, &title, &body, &wordCount, &created, &modified, &checksum, &snippet)
err := rows.Scan(&id, &path, &title, &body, &wordCount, &created, &modified, &checksum, &snippet)
if err != nil {
d.logger.Err(err)
continue
@ -195,11 +190,7 @@ func (d *NoteDAO) Find(callback func(note.Match) error, filters ...note.Filter)
ID: id,
Snippet: snippet,
Metadata: note.Metadata{
Path: file.Path{
Dir: dir,
Filename: filename,
Abs: filepath.Join(d.root, dir, filename),
},
Path: path,
Title: title,
Body: body,
WordCount: wordCount,

@ -13,31 +13,31 @@ import (
func TestNoteDAOIndexed(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
dao := NewNoteDAO(tx, &util.NullLogger)
expected := []file.Metadata{
{
Path: file.Path{Dir: "", Filename: "f39c8.md", Abs: "/test/f39c8.md"},
Path: "f39c8.md",
Modified: date("2020-01-20T08:52:42.321024+01:00"),
},
{
Path: file.Path{Dir: "", Filename: "index.md", Abs: "/test/index.md"},
Path: "index.md",
Modified: date("2019-12-04T12:17:21.720747+01:00"),
},
{
Path: file.Path{Dir: "log", Filename: "2021-01-03.md", Abs: "/test/log/2021-01-03.md"},
Path: "log/2021-01-03.md",
Modified: date("2020-11-22T16:27:45.734454655+01:00"),
},
{
Path: file.Path{Dir: "log", Filename: "2021-01-04.md", Abs: "/test/log/2021-01-04.md"},
Path: "log/2021-01-04.md",
Modified: date("2020-11-29T08:20:18.138907236+01:00"),
},
{
Path: file.Path{Dir: "ref/test", Filename: "a.md", Abs: "/test/ref/test/a.md"},
Path: "ref/test/a.md",
Modified: date("2019-11-20T20:34:06.120375+01:00"),
},
{
Path: file.Path{Dir: "ref/test", Filename: "b.md", Abs: "/test/ref/test/b.md"},
Path: "ref/test/b.md",
Modified: date("2019-11-20T20:34:06.120375+01:00"),
},
}
@ -55,14 +55,10 @@ func TestNoteDAOIndexed(t *testing.T) {
func TestNoteDAOAdd(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
dao := NewNoteDAO(tx, &util.NullLogger)
err := dao.Add(note.Metadata{
Path: file.Path{
Dir: "log",
Filename: "added.md",
Abs: "/test/log/added.md",
},
Path: "log/added.md",
Title: "Added note",
Body: "Note body",
WordCount: 2,
@ -72,11 +68,10 @@ func TestNoteDAOAdd(t *testing.T) {
})
assert.Nil(t, err)
row, err := queryNoteRow(tx, `filename = "added.md"`)
row, err := queryNoteRow(tx, `path = "log/added.md"`)
assert.Nil(t, err)
assert.Equal(t, row, noteRow{
Dir: "log",
Filename: "added.md",
Path: "log/added.md",
Title: "Added note",
Body: "Note body",
WordCount: 2,
@ -90,28 +85,19 @@ func TestNoteDAOAdd(t *testing.T) {
// Check that we can't add a duplicate note with an existing path.
func TestNoteDAOAddExistingNote(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
dao := NewNoteDAO(tx, &util.NullLogger)
err := dao.Add(note.Metadata{
Path: file.Path{
Dir: "ref/test",
Filename: "a.md",
},
})
assert.Err(t, err, "ref/test/a.md: can't add note to the index: UNIQUE constraint failed: notes.filename, notes.dir")
err := dao.Add(note.Metadata{Path: "ref/test/a.md"})
assert.Err(t, err, "ref/test/a.md: can't add note to the index: UNIQUE constraint failed: notes.path")
})
}
func TestNoteDAOUpdate(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
dao := NewNoteDAO(tx, &util.NullLogger)
err := dao.Update(note.Metadata{
Path: file.Path{
Dir: "ref/test",
Filename: "a.md",
Abs: "/test/log/added.md",
},
Path: "ref/test/a.md",
Title: "Updated note",
Body: "Updated body",
WordCount: 42,
@ -121,11 +107,10 @@ func TestNoteDAOUpdate(t *testing.T) {
})
assert.Nil(t, err)
row, err := queryNoteRow(tx, `dir = "ref/test" AND filename = "a.md"`)
row, err := queryNoteRow(tx, `path = "ref/test/a.md"`)
assert.Nil(t, err)
assert.Equal(t, row, noteRow{
Dir: "ref/test",
Filename: "a.md",
Path: "ref/test/a.md",
Title: "Updated note",
Body: "Updated body",
WordCount: 42,
@ -138,14 +123,10 @@ func TestNoteDAOUpdate(t *testing.T) {
func TestNoteDAOUpdateUnknown(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
dao := NewNoteDAO(tx, &util.NullLogger)
err := dao.Update(note.Metadata{
Path: file.Path{
Dir: "unknown",
Filename: "unknown.md",
Abs: "/test/unknown/unknown.md",
},
Path: "unknown/unknown.md",
})
assert.Err(t, err, "unknown/unknown.md: failed to update note index: note not found in the index")
})
@ -153,43 +134,35 @@ func TestNoteDAOUpdateUnknown(t *testing.T) {
func TestNoteDAORemove(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
dao := NewNoteDAO(tx, &util.NullLogger)
err := dao.Remove(file.Path{
Dir: "ref/test",
Filename: "a.md",
Abs: "/test/ref/test/a.md",
})
err := dao.Remove("ref/test/a.md")
assert.Nil(t, err)
})
}
func TestNoteDAORemoveUnknown(t *testing.T) {
testTransaction(t, func(tx Transaction) {
dao := NewNoteDAO(tx, "/test", &util.NullLogger)
dao := NewNoteDAO(tx, &util.NullLogger)
err := dao.Remove(file.Path{
Dir: "unknown",
Filename: "unknown.md",
Abs: "/test/unknown/unknown.md",
})
err := dao.Remove("unknown/unknown.md")
assert.Err(t, err, "unknown/unknown.md: failed to remove note index: note not found in the index")
})
}
type noteRow struct {
Dir, Filename, Title, Body, Checksum string
WordCount int
Created, Modified time.Time
Path, Title, Body, Checksum string
WordCount int
Created, Modified time.Time
}
func queryNoteRow(tx Transaction, where string) (noteRow, error) {
var row noteRow
err := tx.QueryRow(fmt.Sprintf(`
SELECT dir, filename, title, body, word_count, checksum, created, modified
SELECT path, title, body, word_count, checksum, created, modified
FROM notes
WHERE %v
`, where)).Scan(&row.Dir, &row.Filename, &row.Title, &row.Body, &row.WordCount, &row.Checksum, &row.Created, &row.Modified)
`, where)).Scan(&row.Path, &row.Title, &row.Body, &row.WordCount, &row.Checksum, &row.Created, &row.Modified)
return row, err
}

@ -47,47 +47,36 @@ func (db *DB) Migrate() error {
if version == 0 {
err = tx.ExecStmts([]string{
`
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
dir TEXT NOT NULL,
filename TEXT NOT NULL,
title TEXT DEFAULT('') NOT NULL,
body TEXT DEFAULT('') NOT NULL,
word_count INTEGER DEFAULT(0) NOT NULL,
checksum TEXT NOT NULL,
created DATETIME DEFAULT(CURRENT_TIMESTAMP) NOT NULL,
modified DATETIME DEFAULT(CURRENT_TIMESTAMP) NOT NULL,
UNIQUE(filename, dir)
)
`,
`CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
path TEXT NOT NULL,
title TEXT DEFAULT('') NOT NULL,
body TEXT DEFAULT('') NOT NULL,
word_count INTEGER DEFAULT(0) NOT NULL,
checksum TEXT NOT NULL,
created DATETIME DEFAULT(CURRENT_TIMESTAMP) NOT NULL,
modified DATETIME DEFAULT(CURRENT_TIMESTAMP) NOT NULL,
UNIQUE(path)
)`,
`CREATE INDEX IF NOT EXISTS index_notes_checksum ON notes (checksum)`,
`CREATE INDEX IF NOT EXISTS index_notes_dir_filename ON notes (dir, filename)`,
`
CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(
filename, title, body,
content = notes,
content_rowid = id,
tokenize = 'porter unicode61 remove_diacritics 1'
)
`,
`CREATE INDEX IF NOT EXISTS index_notes_path ON notes (path)`,
`CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(
path, title, body,
content = notes,
content_rowid = id,
tokenize = 'porter unicode61 remove_diacritics 1'
)`,
// Triggers to keep the FTS index up to date.
`
CREATE TRIGGER IF NOT EXISTS notes_ai AFTER INSERT ON notes BEGIN
INSERT INTO notes_fts(rowid, filename, title, body) VALUES (new.id, new.filename, new.title, new.body);
END
`,
`
CREATE TRIGGER IF NOT EXISTS notes_ad AFTER DELETE ON notes BEGIN
INSERT INTO notes_fts(notes_fts, rowid, filename, title, body) VALUES('delete', old.id, old.filename, old.title, old.body);
END
`,
`
CREATE TRIGGER IF NOT EXISTS notes_au AFTER UPDATE ON notes BEGIN
INSERT INTO notes_fts(notes_fts, rowid, filename, title, body) VALUES('delete', old.id, old.filename, old.title, old.body);
INSERT INTO notes_fts(rowid, filename, title, body) VALUES (new.id, new.filename, new.title, new.body);
END
`,
`CREATE TRIGGER IF NOT EXISTS trigger_notes_ai AFTER INSERT ON notes BEGIN
INSERT INTO notes_fts(rowid, path, title, body) VALUES (new.id, new.path, new.title, new.body);
END`,
`CREATE TRIGGER IF NOT EXISTS trigger_notes_ad AFTER DELETE ON notes BEGIN
INSERT INTO notes_fts(notes_fts, rowid, path, title, body) VALUES('delete', old.id, old.path, old.title, old.body);
END`,
`CREATE TRIGGER IF NOT EXISTS trigger_notes_au AFTER UPDATE ON notes BEGIN
INSERT INTO notes_fts(notes_fts, rowid, path, title, body) VALUES('delete', old.id, old.path, old.title, old.body);
INSERT INTO notes_fts(rowid, path, title, body) VALUES (new.id, new.path, new.title, new.body);
END`,
`PRAGMA user_version = 1`,
})

@ -36,8 +36,8 @@ func TestMigrateFrom0(t *testing.T) {
assert.Equal(t, version, 1)
_, err = tx.Exec(`
INSERT INTO notes (dir, filename, title, body, word_count, checksum)
VALUES ("ref", "tx1.md", "A reference", "Content", 1, "qwfpg")
INSERT INTO notes (path, title, body, word_count, checksum)
VALUES ("ref/tx1.md", "A reference", "Content", 1, "qwfpg")
`)
assert.Nil(t, err)

@ -1,6 +1,5 @@
- id: 1
dir: "log"
filename: "2021-01-03.md"
path: "log/2021-01-03.md"
title: "January 3, 2021"
body: "A daily note"
word_count: 3
@ -9,8 +8,7 @@
modified: "2020-11-22T16:27:45.734454655+01:00"
- id: 2
dir: "log"
filename: "2021-01-04.md"
path: "log/2021-01-04.md"
title: "January 4, 2021"
body: "A second daily note"
word_count: 4
@ -19,8 +17,7 @@
modified: "2020-11-29T08:20:18.138907236+01:00"
- id: 3
dir: ""
filename: "index.md"
path: "index.md"
title: "Index"
body: "Index of the Zettelkasten"
word_count: 4
@ -29,8 +26,7 @@
modified: "2019-12-04T12:17:21.720747+01:00"
- id: 4
dir: ""
filename: "f39c8.md"
path: "f39c8.md"
title: "An interesting note"
body: "Its content will surprise you"
word_count: 5
@ -39,8 +35,7 @@
modified: "2020-01-20T08:52:42.321024+01:00"
- id: 5
dir: "ref/test"
filename: "b.md"
path: "ref/test/b.md"
title: "A nested note"
body: "This one is in a sub sub directory"
word_count: 8
@ -49,8 +44,7 @@
modified: "2019-11-20T20:34:06.120375+01:00"
- id: 6
dir: "ref/test"
filename: "a.md"
path: "ref/test/a.md"
title: "Another nested note"
body: "It shall appear before b.md"
word_count: 5

@ -28,7 +28,7 @@ func (cmd *Index) Run(container *Container) error {
}
return db.WithTransaction(func(tx sqlite.Transaction) error {
notes := sqlite.NewNoteDAO(tx, zk.Path, container.Logger)
notes := sqlite.NewNoteDAO(tx, container.Logger)
return note.Index(*dir, notes, container.Logger)
})
}

@ -1,12 +1,12 @@
package file
// DiffChange represents a file change made in a slip box directory.
// DiffChange represents a file change made in a directory.
type DiffChange struct {
Path Path
Path string
Kind DiffKind
}
// DiffKind represents a type of file change made in a slip box directory.
// DiffKind represents a type of file change made in a directory.
type DiffKind int
const (
@ -82,7 +82,7 @@ func (p *diffPair) diff() *DiffChange {
p.target = nil
default: // Different files, one has been added or removed.
if p.source.Path.Less(p.target.Path) {
if p.source.Path < p.target.Path {
change = &DiffChange{p.source.Path, DiffAdded}
p.source = nil
} else {

@ -22,15 +22,15 @@ func TestDiffEmpty(t *testing.T) {
func TestNoDiff(t *testing.T) {
files := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Modified: date2,
},
{
Path: Path{Dir: "b", Filename: "1"},
Path: "b/1",
Modified: date3,
},
}
@ -41,15 +41,15 @@ func TestNoDiff(t *testing.T) {
func TestDiff(t *testing.T) {
source := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Modified: date2,
},
{
Path: Path{Dir: "b", Filename: "1"},
Path: "b/1",
Modified: date3,
},
}
@ -57,33 +57,33 @@ func TestDiff(t *testing.T) {
target := []Metadata{
{
// Date changed
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1.Add(time.Hour),
},
// 2 is added
{
// 3 is removed
Path: Path{Dir: "a", Filename: "3"},
Path: "a/3",
Modified: date3,
},
{
// No change
Path: Path{Dir: "b", Filename: "1"},
Path: "b/1",
Modified: date3,
},
}
test(t, source, target, []DiffChange{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Kind: DiffModified,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Kind: DiffAdded,
},
{
Path: Path{Dir: "a", Filename: "3"},
Path: "a/3",
Kind: DiffRemoved,
},
})
@ -92,25 +92,25 @@ func TestDiff(t *testing.T) {
func TestDiffWithMoreInSource(t *testing.T) {
source := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Modified: date2,
},
}
target := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
}
test(t, source, target, []DiffChange{
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Kind: DiffAdded,
},
})
@ -119,25 +119,25 @@ func TestDiffWithMoreInSource(t *testing.T) {
func TestDiffWithMoreInTarget(t *testing.T) {
source := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
}
target := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Modified: date2,
},
}
test(t, source, target, []DiffChange{
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Kind: DiffRemoved,
},
})
@ -148,22 +148,22 @@ func TestDiffEmptySource(t *testing.T) {
target := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Modified: date2,
},
}
test(t, source, target, []DiffChange{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Kind: DiffRemoved,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Kind: DiffRemoved,
},
})
@ -172,11 +172,11 @@ func TestDiffEmptySource(t *testing.T) {
func TestDiffEmptyTarget(t *testing.T) {
source := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Modified: date2,
},
}
@ -185,11 +185,11 @@ func TestDiffEmptyTarget(t *testing.T) {
test(t, source, target, []DiffChange{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Kind: DiffAdded,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Kind: DiffAdded,
},
})
@ -198,11 +198,11 @@ func TestDiffEmptyTarget(t *testing.T) {
func TestDiffCancellation(t *testing.T) {
source := []Metadata{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Modified: date1,
},
{
Path: Path{Dir: "a", Filename: "2"},
Path: "a/2",
Modified: date2,
},
}
@ -222,7 +222,7 @@ func TestDiffCancellation(t *testing.T) {
assert.Equal(t, received, []DiffChange{
{
Path: Path{Dir: "a", Filename: "1"},
Path: "a/1",
Kind: DiffAdded,
},
})

@ -1,36 +1,11 @@
package file
import (
"path/filepath"
"time"
)
// Metadata holds information about a slip box file.
type Metadata struct {
Path Path
Path string
Modified time.Time
}
// Path holds a file path relative to a slip box.
type Path struct {
Dir string
Filename string
Abs string
}
// Less returns whether ther receiver path is located before the given one,
// lexicographically.
func (p Path) Less(other Path) bool {
switch {
case p.Dir < other.Dir:
return true
case p.Dir > other.Dir:
return false
default:
return p.Filename < other.Filename
}
}
func (p Path) String() string {
return filepath.Join(p.Dir, p.Filename)
}

@ -47,11 +47,7 @@ func Walk(dir zk.Dir, extension string, logger util.Logger) <-chan Metadata {
}
c <- Metadata{
Path: Path{
Dir: filepath.Join(dir.Name, curDir),
Filename: filename,
Abs: abs,
},
Path: filepath.Join(dir.Name, curDir, filename),
Modified: info.ModTime(),
}
}

@ -15,29 +15,29 @@ var root = fixtures.Path("walk")
func TestWalkRootDir(t *testing.T) {
dir := zk.Dir{Name: "", Path: root}
testEqual(t, Walk(dir, "md", &util.NullLogger), []Path{
{Dir: "", Filename: "a.md", Abs: filepath.Join(root, "a.md")},
{Dir: "", Filename: "b.md", Abs: filepath.Join(root, "b.md")},
{Dir: "dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/a.md")},
{Dir: "dir1", Filename: "b.md", Abs: filepath.Join(root, "dir1/b.md")},
{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
{Dir: "dir2", Filename: "a.md", Abs: filepath.Join(root, "dir2/a.md")},
testEqual(t, Walk(dir, "md", &util.NullLogger), []string{
"a.md",
"b.md",
"dir1/a.md",
"dir1/b.md",
"dir1/dir1/a.md",
"dir2/a.md",
})
}
func TestWalkSubDir(t *testing.T) {
dir := zk.Dir{Name: "dir1", Path: filepath.Join(root, "dir1")}
testEqual(t, Walk(dir, "md", &util.NullLogger), []Path{
{Dir: "dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/a.md")},
{Dir: "dir1", Filename: "b.md", Abs: filepath.Join(root, "dir1/b.md")},
{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
testEqual(t, Walk(dir, "md", &util.NullLogger), []string{
"dir1/a.md",
"dir1/b.md",
"dir1/dir1/a.md",
})
}
func TestWalkSubSubDir(t *testing.T) {
dir := zk.Dir{Name: "dir1/dir1", Path: filepath.Join(root, "dir1/dir1")}
testEqual(t, Walk(dir, "md", &util.NullLogger), []Path{
{Dir: "dir1/dir1", Filename: "a.md", Abs: filepath.Join(root, "dir1/dir1/a.md")},
testEqual(t, Walk(dir, "md", &util.NullLogger), []string{
"dir1/dir1/a.md",
})
}
@ -46,10 +46,10 @@ func date(s string) time.Time {
return date
}
func testEqual(t *testing.T, actual <-chan Metadata, expected []Path) {
popExpected := func() (Path, bool) {
func testEqual(t *testing.T, actual <-chan Metadata, expected []string) {
popExpected := func() (string, bool) {
if len(expected) == 0 {
return Path{}, false
return "", false
}
item := expected[0]
expected = expected[1:]

@ -4,6 +4,7 @@ import (
"crypto/sha256"
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"time"
@ -16,7 +17,7 @@ import (
// Metadata holds information about a particular note.
type Metadata struct {
Path file.Path
Path string
Title string
Body string
WordCount int
@ -34,7 +35,7 @@ type Indexer interface {
// Update updates the metadata of an already indexed note.
Update(metadata Metadata) error
// Remove deletes a note from the index.
Remove(path file.Path) error
Remove(path string) error
}
// Index indexes the content of the notes in the given directory.
@ -50,14 +51,14 @@ func Index(dir zk.Dir, indexer Indexer, logger util.Logger) error {
err = file.Diff(source, target, func(change file.DiffChange) error {
switch change.Kind {
case file.DiffAdded:
metadata, err := metadata(change.Path)
metadata, err := metadata(change.Path, dir.Path)
if err == nil {
err = indexer.Add(metadata)
}
logger.Err(err)
case file.DiffModified:
metadata, err := metadata(change.Path)
metadata, err := metadata(change.Path, dir.Path)
if err == nil {
err = indexer.Update(metadata)
}
@ -74,12 +75,13 @@ func Index(dir zk.Dir, indexer Indexer, logger util.Logger) error {
}
// metadata retrieves note metadata for the given file.
func metadata(path file.Path) (Metadata, error) {
func metadata(path string, basePath string) (Metadata, error) {
metadata := Metadata{
Path: path,
}
content, err := ioutil.ReadFile(path.Abs)
absPath := filepath.Join(basePath, path)
content, err := ioutil.ReadFile(absPath)
if err != nil {
return metadata, err
}
@ -90,7 +92,7 @@ func metadata(path file.Path) (Metadata, error) {
metadata.WordCount = len(strings.Fields(contentStr))
metadata.Checksum = fmt.Sprintf("%x", sha256.Sum256(content))
times, err := times.Stat(path.Abs)
times, err := times.Stat(absPath)
if err != nil {
return metadata, err
}

Loading…
Cancel
Save