Add lazy prepared statements

pull/6/head
Mickaël Menu 4 years ago
parent 2cd15aafe2
commit 6dc9a65d21
No known key found for this signature in database
GPG Key ID: 53D73664CD359895

@ -18,54 +18,35 @@ type NoteDAO struct {
logger util.Logger logger util.Logger
// Prepared SQL statements // Prepared SQL statements
indexedStmt *sql.Stmt indexedStmt *LazyStmt
addStmt *sql.Stmt addStmt *LazyStmt
updateStmt *sql.Stmt updateStmt *LazyStmt
removeStmt *sql.Stmt removeStmt *LazyStmt
} }
func NewNoteDAO(tx Transaction, root string, logger util.Logger) (*NoteDAO, error) { func NewNoteDAO(tx Transaction, root string, logger util.Logger) *NoteDAO {
indexedStmt, err := tx.Prepare(`
SELECT dir, filename, modified from notes
ORDER BY dir, filename ASC
`)
if err != nil {
return nil, err
}
addStmt, err := tx.Prepare(`
INSERT INTO notes (dir, filename, title, body, word_count, checksum, created, modified)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`)
if err != nil {
return nil, err
}
updateStmt, err := tx.Prepare(`
UPDATE notes
SET title = ?, body = ?, word_count = ?, checksum = ?, modified = ?
WHERE dir = ? AND filename = ?`)
if err != nil {
return nil, err
}
removeStmt, err := tx.Prepare(`
DELETE FROM notes
WHERE dir = ? AND filename = ?
`)
if err != nil {
return nil, err
}
return &NoteDAO{ return &NoteDAO{
tx: tx, tx: tx,
root: root, root: root,
logger: logger, logger: logger,
indexedStmt: indexedStmt, indexedStmt: tx.PrepareLazy(`
addStmt: addStmt, SELECT dir, filename, modified from notes
updateStmt: updateStmt, ORDER BY dir, filename ASC
removeStmt: removeStmt, `),
}, nil addStmt: tx.PrepareLazy(`
INSERT INTO notes (dir, filename, title, body, word_count, checksum, created, modified)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`),
updateStmt: tx.PrepareLazy(`
UPDATE notes
SET title = ?, body = ?, word_count = ?, checksum = ?, modified = ?
WHERE dir = ? AND filename = ?
`),
removeStmt: tx.PrepareLazy(`
DELETE FROM notes
WHERE dir = ? AND filename = ?
`),
}
} }
func (d *NoteDAO) Indexed() (<-chan file.Metadata, error) { func (d *NoteDAO) Indexed() (<-chan file.Metadata, error) {

@ -0,0 +1,52 @@
package sqlite
import (
"database/sql"
"sync"
)
// LazyStmt is a wrapper around a sql.Stmt which will be evaluated on first use.
type LazyStmt struct {
create func() (*sql.Stmt, error)
stmt *sql.Stmt
err error
once sync.Once
}
// NewLazyStmt creates a new lazy statement bound to the given transaction.
func NewLazyStmt(tx *sql.Tx, query string) *LazyStmt {
return &LazyStmt{
create: func() (*sql.Stmt, error) { return tx.Prepare(query) },
}
}
func (s *LazyStmt) Stmt() (*sql.Stmt, error) {
s.once.Do(func() {
s.stmt, s.err = s.create()
})
return s.stmt, s.err
}
func (s *LazyStmt) Exec(args ...interface{}) (sql.Result, error) {
stmt, err := s.Stmt()
if err != nil {
return nil, err
}
return stmt.Exec(args...)
}
func (s *LazyStmt) Query(args ...interface{}) (*sql.Rows, error) {
stmt, err := s.Stmt()
if err != nil {
return nil, err
}
return stmt.Query(args...)
}
func (s *LazyStmt) QueryRow(args ...interface{}) (*sql.Row, error) {
stmt, err := s.Stmt()
if err != nil {
return nil, err
}
return stmt.QueryRow(args...), nil
}

@ -13,6 +13,7 @@ type Transaction interface {
Exec(query string, args ...interface{}) (sql.Result, error) Exec(query string, args ...interface{}) (sql.Result, error)
ExecStmts(stmts []string) error ExecStmts(stmts []string) error
Prepare(query string) (*sql.Stmt, error) Prepare(query string) (*sql.Stmt, error)
PrepareLazy(query string) *LazyStmt
Query(query string, args ...interface{}) (*sql.Rows, error) Query(query string, args ...interface{}) (*sql.Rows, error)
QueryRow(query string, args ...interface{}) *sql.Row QueryRow(query string, args ...interface{}) *sql.Row
} }
@ -22,6 +23,10 @@ type txWrapper struct {
*sql.Tx *sql.Tx
} }
func (tx *txWrapper) PrepareLazy(query string) *LazyStmt {
return NewLazyStmt(tx.Tx, query)
}
func (tx *txWrapper) ExecStmts(stmts []string) error { func (tx *txWrapper) ExecStmts(stmts []string) error {
var err error var err error
for _, stmt := range stmts { for _, stmt := range stmts {

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

@ -23,10 +23,7 @@ func (cmd *List) Run(container *Container) error {
} }
return db.WithTransaction(func(tx sqlite.Transaction) error { return db.WithTransaction(func(tx sqlite.Transaction) error {
notes, err := sqlite.NewNoteDAO(tx, zk.Path, container.Logger) notes := sqlite.NewNoteDAO(tx, zk.Path, container.Logger)
if err != nil {
return err
}
filters := make([]note.Filter, 0) filters := make([]note.Filter, 0)
if cmd.Query != "" { if cmd.Query != "" {

Loading…
Cancel
Save