@@ -34,6 +34,8 @@ func (i Item) Read() bool {
3434
3535type Store interface {
3636 UpsertItem (item Item ) error
37+ BeginBatch () error
38+ EndBatch () error
3739 GetAllItems (ordering string ) ([]Item , error )
3840 GetItemByID (ID int ) (Item , error )
3941 GetAllFeedURLs () ([]string , error )
@@ -45,8 +47,9 @@ type Store interface {
4547}
4648
4749type SQLiteStore struct {
48- path string
49- db * sql.DB
50+ path string
51+ db * sql.DB
52+ batch * sql.Tx
5053}
5154
5255func NewSQLiteStore (basePath string , dbName string ) (* SQLiteStore , error ) {
@@ -148,8 +151,46 @@ func runMigrations(db *sql.DB) (err error) {
148151 return err
149152}
150153
151- func (sls SQLiteStore ) UpsertItem (item Item ) error {
152- stmt , err := sls .db .Prepare (`select count(id), id from items where feedurl = ? and title = ?;` )
154+ // Begin a transaction. UpsertItem will use this transaction until
155+ // client code calls EndBatch().
156+ func (sls * SQLiteStore ) BeginBatch () error {
157+ tx , err := sls .db .Begin ()
158+ if err != nil {
159+ return fmt .Errorf ("BeginBatch: %w" , err )
160+ }
161+ sls .batch = tx
162+ return nil
163+ }
164+
165+ // Commit a transaction. This commits any changes made since BeginBatch()
166+ // and reset sls.batch to nil so that subsequent calls to UpsertItem()
167+ // will not use a transaction.
168+ func (sls * SQLiteStore ) EndBatch () error {
169+ if sls .batch == nil {
170+ return nil
171+ }
172+ err := sls .batch .Commit ()
173+ sls .batch = nil
174+ if err != nil {
175+ return fmt .Errorf ("EndBatch: %w" , err )
176+ }
177+ return nil
178+ }
179+
180+ func (sls * SQLiteStore ) UpsertItem (item Item ) error {
181+ if sls .batch != nil {
182+ return sls .upsertItem (sls .batch , item )
183+ }
184+ return sls .upsertItem (sls .db , item )
185+ }
186+
187+ // This interface is implemented by both sql.DB and by sql.Tx
188+ type statementPreparer interface {
189+ Prepare (query string ) (* sql.Stmt , error )
190+ }
191+
192+ func (sls * SQLiteStore ) upsertItem (db statementPreparer , item Item ) error {
193+ stmt , err := db .Prepare (`select count(id), id from items where feedurl = ? and title = ?;` )
153194 if err != nil {
154195 return fmt .Errorf ("sqlite.go: could not prepare query: %w" , err )
155196 }
@@ -162,7 +203,7 @@ func (sls SQLiteStore) UpsertItem(item Item) error {
162203 }
163204
164205 if count == 0 {
165- stmt , err = sls . db .Prepare (`insert into items (feedurl, link, title, content, author, publishedat, createdat, updatedat) values (?, ?, ?, ?, ?, ?, ?, ?)` )
206+ stmt , err = db .Prepare (`insert into items (feedurl, link, title, content, author, publishedat, createdat, updatedat) values (?, ?, ?, ?, ?, ?, ?, ?)` )
166207 if err != nil {
167208 return fmt .Errorf ("sqlite.go: could not prepare query: %w" , err )
168209 }
@@ -172,7 +213,7 @@ func (sls SQLiteStore) UpsertItem(item Item) error {
172213 return fmt .Errorf ("sqlite.go: Upsert failed: %w" , err )
173214 }
174215 } else {
175- stmt , err = sls . db .Prepare (`update items set content = ?, updatedat = ? where id = ?` )
216+ stmt , err = db .Prepare (`update items set content = ?, updatedat = ? where id = ?` )
176217 if err != nil {
177218 return fmt .Errorf ("sqlite.go: could not prepare query: %w" , err )
178219 }
0 commit comments