-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
183 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
feeds.db: src/main.go src/feed.go src/file.go feeds.json | ||
SRCS := src/main.go src/feeds.go src/db.go src/entries.go src/file.go | ||
|
||
feeds.db: $(SRCS) feeds.json | ||
go run -tags "sqlite_fts5 sqlite_foreign_keys" ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package main | ||
|
||
import ( | ||
"database/sql" | ||
"os" | ||
|
||
_ "github.com/mattn/go-sqlite3" | ||
) | ||
|
||
func initDb() (*sql.DB, error) { | ||
os.Remove(DB_NAME) | ||
|
||
db, err := sql.Open("sqlite3", DB_NAME) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
initStmt := ` | ||
pragma journal_mode = delete; | ||
pragma page_size = 1024; | ||
create table feeds ( | ||
id integer not null primary key, | ||
title text, | ||
url text, | ||
description text | ||
); | ||
create table entries ( | ||
id integer not null primary key, | ||
feedid integer not null, | ||
datemillis integer not null, | ||
title text, | ||
content text, | ||
url text, | ||
foreign key(feedid) references feeds(id) | ||
); | ||
create index entriesindex on entries(feedid); | ||
create table entries_content ( | ||
entriesid integer not null, | ||
content text, | ||
foreign key(entriesid) references entries(id) | ||
); | ||
create index entriescindex on entries_content(entriesid); | ||
create virtual table search using fts5( | ||
entriesid unindexed, | ||
content | ||
); | ||
` | ||
_, err = db.Exec(initStmt) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return db, nil | ||
} | ||
|
||
func insertFeedsAndEntries(db *sql.DB, feeds Feeds) error { | ||
tx, err := db.Begin() | ||
if err != nil { | ||
return err | ||
} | ||
stmt_feeds, err := tx.Prepare("insert into feeds(id,title,url,description) values(?,?,?,?)") | ||
if err != nil { | ||
return err | ||
} | ||
defer stmt_feeds.Close() | ||
stmt_entry, err := tx.Prepare( | ||
"insert into entries(feedid,datemillis,title,url) values(?,?,?,?)", | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
defer stmt_entry.Close() | ||
stmt_entry_content, err := tx.Prepare( | ||
"insert into entries_content(entriesid,content) values(?,?)", | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
defer stmt_entry_content.Close() | ||
for feedid, feed := range feeds { | ||
_, err = stmt_feeds.Exec(feedid, feed.Title, feed.Url, feed.Description) | ||
if err != nil { | ||
return err | ||
} | ||
for _, entry := range feed.Entries { | ||
// entries | ||
res, err := stmt_entry.Exec( | ||
feedid, | ||
entry.Date.UnixMilli(), | ||
entry.Title, | ||
entry.Url, | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
// entries_content | ||
entryid, err := res.LastInsertId() | ||
if err != nil { | ||
return err | ||
} | ||
_, err = stmt_entry_content.Exec( | ||
entryid, | ||
entry.Content, | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
err = tx.Commit() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = insertSearch(db) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// insertSearch populates `search` table. | ||
// Assumes there are already `entries_content` on the db. | ||
func insertSearch(db *sql.DB) error { | ||
sqlStmt := ` | ||
insert into search | ||
select entriesid,content | ||
from entries_content; | ||
insert into search(search) values('optimize'); | ||
vacuum; | ||
` | ||
_, err := db.Exec(sqlStmt) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package main | ||
|
||
import "time" | ||
|
||
type Entry struct { | ||
Date time.Time | ||
HumanDate string | ||
MachineDate string | ||
Title string | ||
Url string | ||
Description string | ||
Content string | ||
} | ||
|
||
type Entries []Entry | ||
|
||
func (a Entries) Len() int { | ||
return len(a) | ||
} | ||
|
||
func (a Entries) Less(i, j int) bool { | ||
iDate := a[i].Date | ||
jDate := a[j].Date | ||
return iDate.After(jDate) | ||
} | ||
|
||
func (a Entries) Swap(i, j int) { | ||
a[i], a[j] = a[j], a[i] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.