nandi/gleanpublic⑂ Fork 0
⑂ bb615b0
Commits
⬇ Clone ▾
git clone https://git.rickub.com/nandi/glean.git
git clone ssh://git@rickub.com/nandi/glean.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Renaming and cleanupUnverified

Julien Robert committed 2026-04-26T23:18:29+02:00 Browse files
bb615b0 parent: 0548274
modified internal/cluster/jaccard_test.go +78 -78
@@ -15,7 +15,7 @@ import (
1515 "gotest.tools/v3/assert"
1616 )
1717
18-func setupClusterTestDB(t *testing.T) *db.Databases {
18+func setupClusterTestDB(t *testing.T) *db.Store {
1919 t.Helper()
2020 vec.Auto()
2121 f, err := os.CreateTemp("", "glean-cluster-test-*.db")
@@ -35,19 +35,19 @@ func setupClusterTestDB(t *testing.T) *db.Databases {
3535 _ = os.Remove(path + "_recs-wal")
3636 })
3737
38- dbs, err := db.OpenAll(path)
38+ dbs, err := db.Open(path)
3939 assert.NilError(t, err)
4040 t.Cleanup(func() { _ = dbs.Close() })
4141 assert.NilError(t, dbs.InitVecTables(8))
4242 return dbs
4343 }
4444
45-func seedClusterData(t *testing.T, ctx context.Context, dbs *db.Databases) {
45+func seedClusterData(t *testing.T, ctx context.Context, dbs *db.Store) {
4646 t.Helper()
4747
4848 users := []string{"did:test:alice", "did:test:bob", "did:test:carol", "did:test:dave"}
4949 for _, did := range users {
50- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, did)
50+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, did)
5151 assert.NilError(t, err)
5252 }
5353
@@ -59,7 +59,7 @@ func seedClusterData(t *testing.T, ctx context.Context, dbs *db.Databases) {
5959 {"https://e.com/feed", "Feed E"},
6060 }
6161 for _, f := range feeds {
62- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, '', 'rss', 2)`, f.url, f.title, f.url)
62+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, '', 'rss', 2)`, f.url, f.title, f.url)
6363 assert.NilError(t, err)
6464 }
6565
@@ -75,12 +75,12 @@ func seedClusterData(t *testing.T, ctx context.Context, dbs *db.Databases) {
7575 {"did:test:carol", "https://c.com/feed"},
7676 }
7777 for _, s := range subs {
78- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, s.user, s.feed)
78+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, s.user, s.feed)
7979 assert.NilError(t, err)
8080 }
8181 }
8282
83-func seedFollowData(t *testing.T, ctx context.Context, dbs *db.Databases) {
83+func seedFollowData(t *testing.T, ctx context.Context, dbs *db.Store) {
8484 t.Helper()
8585 follows := []struct{ user, target string }{
8686 {"did:test:alice", "did:test:bob"},
@@ -88,13 +88,13 @@ func seedFollowData(t *testing.T, ctx context.Context, dbs *db.Databases) {
8888 {"did:test:carol", "did:test:dave"},
8989 }
9090 for _, f := range follows {
91- _, err := dbs.DB().ExecContext(ctx, `INSERT OR IGNORE INTO follows (user_did, target_did) VALUES (?, ?)`, f.user, f.target)
91+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT OR IGNORE INTO follows (user_did, target_did) VALUES (?, ?)`, f.user, f.target)
9292 assert.NilError(t, err)
9393 }
9494 }
9595
96-func newTestEngine(dbs *db.Databases) *Engine {
97- return NewEngine(dbs.DB(), NewMockEmbedder(8), slog.Default())
96+func newTestEngine(dbs *db.Store) *Engine {
97+ return NewEngine(dbs.SQLDB(), NewMockEmbedder(8), slog.Default())
9898 }
9999
100100 func TestComputeFeedSimilarity(t *testing.T) {
@@ -107,7 +107,7 @@ func TestComputeFeedSimilarity(t *testing.T) {
107107 assert.NilError(t, err)
108108
109109 var count int
110- err = dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.feed_similarity`).Scan(&count)
110+ err = dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.feed_similarity`).Scan(&count)
111111 assert.NilError(t, err)
112112 assert.Assert(t, count > 0, "expected feed similarity pairs")
113113 }
@@ -122,7 +122,7 @@ func TestComputeUserSimilarity(t *testing.T) {
122122 assert.NilError(t, err)
123123
124124 var count int
125- err = dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.user_similarity`).Scan(&count)
125+ err = dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.user_similarity`).Scan(&count)
126126 assert.NilError(t, err)
127127 assert.Assert(t, count > 0, "expected user similarity pairs")
128128 }
@@ -224,14 +224,14 @@ func TestRecordImpressions(t *testing.T) {
224224 assert.NilError(t, engine.RecordImpressions(ctx, "did:test:alice", impressions))
225225
226226 var count int
227- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
227+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
228228 `SELECT COUNT(*) FROM main.recommendation_impressions WHERE user_did = 'did:test:alice'`).Scan(&count))
229229 assert.Equal(t, count, 2)
230230
231231 assert.NilError(t, engine.RecordImpressions(ctx, "did:test:alice", impressions))
232232
233233 var shownCount int
234- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
234+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
235235 `SELECT shown_count FROM main.recommendation_impressions WHERE user_did = 'did:test:alice' AND target_id = 'https://a.com/feed'`).Scan(&shownCount))
236236 assert.Equal(t, shownCount, 2, "shown_count should increment on repeated impression")
237237 }
@@ -249,7 +249,7 @@ func TestMarkImpressionActed(t *testing.T) {
249249 assert.NilError(t, engine.MarkImpressionActed(ctx, "did:test:alice", "feed", "https://a.com/feed"))
250250
251251 var acted bool
252- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
252+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
253253 `SELECT acted FROM main.recommendation_impressions WHERE user_did = 'did:test:alice' AND target_id = 'https://a.com/feed'`).Scan(&acted))
254254 assert.Assert(t, acted, "impression should be marked as acted")
255255 }
@@ -264,22 +264,22 @@ func TestComputeFollowDistances(t *testing.T) {
264264 assert.NilError(t, engine.ComputeFollowDistances(ctx))
265265
266266 var d1, d2, d3 int
267- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
267+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
268268 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 1`).Scan(&d1))
269- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
269+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
270270 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 2`).Scan(&d2))
271- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
271+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
272272 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 3`).Scan(&d3))
273273 assert.Assert(t, d1 >= 3, "expected at least 3 direct follow distances")
274274 assert.Assert(t, d2 >= 1, "expected at least 1 two-hop distance (alice -> bob -> carol)")
275275 assert.Assert(t, d3 >= 1, "expected at least 1 three-hop distance (alice -> bob -> carol -> dave)")
276276
277277 var exists int
278- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
278+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
279279 `SELECT COUNT(*) FROM recs.follow_distances WHERE user_a = 'did:test:alice' AND user_b = 'did:test:carol'`).Scan(&exists))
280280 assert.Assert(t, exists == 1, "alice should reach carol")
281281
282- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
282+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
283283 `SELECT COUNT(*) FROM recs.follow_distances WHERE user_a = 'did:test:alice' AND user_b = 'did:test:dave'`).Scan(&exists))
284284 assert.Assert(t, exists == 1, "alice should reach dave via 3 hops")
285285 }
@@ -300,7 +300,7 @@ func TestComputeFollowDistancesData_SplitReadWrite(t *testing.T) {
300300 assert.NilError(t, engine.WriteFollowDistances(ctx, distances))
301301
302302 var count int
303- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.follow_distances`).Scan(&count))
303+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.follow_distances`).Scan(&count))
304304 assert.Equal(t, count, len(distances))
305305 }
306306
@@ -311,7 +311,7 @@ func TestAutoDismissStale(t *testing.T) {
311311
312312 engine := newTestEngine(dbs)
313313
314- _, err := dbs.DB().ExecContext(ctx, `
314+ _, err := dbs.SQLDB().ExecContext(ctx, `
315315 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
316316 VALUES ('did:test:alice', 'feed', 'https://stale.com/feed', datetime('now', '-6 days'), datetime('now'), 6, 0)
317317 `)
@@ -331,7 +331,7 @@ func TestAutoDismissStale_DoesNotDismissRecent(t *testing.T) {
331331
332332 engine := newTestEngine(dbs)
333333
334- _, err := dbs.DB().ExecContext(ctx, `
334+ _, err := dbs.SQLDB().ExecContext(ctx, `
335335 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
336336 VALUES ('did:test:alice', 'feed', 'https://recent.com/feed', datetime('now'), datetime('now'), 5, 0)
337337 `)
@@ -351,7 +351,7 @@ func TestAutoDismissStale_DoesNotDismissActed(t *testing.T) {
351351
352352 engine := newTestEngine(dbs)
353353
354- _, err := dbs.DB().ExecContext(ctx, `
354+ _, err := dbs.SQLDB().ExecContext(ctx, `
355355 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
356356 VALUES ('did:test:alice', 'feed', 'https://acted.com/feed', datetime('now', '-6 days'), datetime('now'), 6, 1)
357357 `)
@@ -427,13 +427,13 @@ func TestSignalWeights_RewardPenalize(t *testing.T) {
427427
428428 engine := newTestEngine(dbs)
429429
430- _, err := dbs.DB().ExecContext(ctx, `
430+ _, err := dbs.SQLDB().ExecContext(ctx, `
431431 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
432432 VALUES ('did:test:alice', 'feed', 'https://a.com/feed', datetime('now'), datetime('now'), 1, 1)
433433 `)
434434 assert.NilError(t, err)
435435 for i := range minActionsTune {
436- _, err = dbs.DB().ExecContext(ctx, `
436+ _, err = dbs.SQLDB().ExecContext(ctx, `
437437 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
438438 VALUES ('did:test:alice', 'feed', ?, datetime('now'), datetime('now'), 1, 1)
439439 `, fmt.Sprintf("https://%d.com/feed", i))
@@ -455,12 +455,12 @@ func TestColdStartRecommendations(t *testing.T) {
455455 engine := newTestEngine(dbs)
456456 assert.NilError(t, engine.ComputeFollowDistances(ctx))
457457
458- _, err := dbs.DB().ExecContext(ctx, `UPDATE articles.feeds SET subscriber_count = 2 WHERE feed_url = 'https://a.com/feed'`)
458+ _, err := dbs.SQLDB().ExecContext(ctx, `UPDATE articles.feeds SET subscriber_count = 2 WHERE feed_url = 'https://a.com/feed'`)
459459 assert.NilError(t, err)
460- _, err = dbs.DB().ExecContext(ctx, `UPDATE articles.feeds SET subscriber_count = 2 WHERE feed_url = 'https://b.com/feed'`)
460+ _, err = dbs.SQLDB().ExecContext(ctx, `UPDATE articles.feeds SET subscriber_count = 2 WHERE feed_url = 'https://b.com/feed'`)
461461 assert.NilError(t, err)
462462
463- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:newuser")
463+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:newuser")
464464 assert.NilError(t, err)
465465
466466 recs, err := engine.ColdStartRecommendations(ctx, "did:test:newuser", 10)
@@ -505,7 +505,7 @@ func TestDismissArticle(t *testing.T) {
505505 assert.NilError(t, engine.DismissArticle(ctx, "did:test:alice", "https://a.com/article1", "not_interested"))
506506
507507 var count int
508- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
508+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
509509 `SELECT COUNT(*) FROM main.dismissed_recommendations WHERE user_did = 'did:test:alice' AND target_type = 'article'`).Scan(&count))
510510 assert.Equal(t, count, 1)
511511 }
@@ -519,7 +519,7 @@ func TestComputeSignalProfiles(t *testing.T) {
519519 assert.NilError(t, engine.ComputeSignalProfiles(ctx))
520520
521521 var count int
522- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.user_signal_profiles`).Scan(&count))
522+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.user_signal_profiles`).Scan(&count))
523523 assert.Assert(t, count >= 3, "expected signal profiles for all users")
524524 }
525525
@@ -534,7 +534,7 @@ func TestDismissFeed_Idempotent(t *testing.T) {
534534 assert.NilError(t, engine.DismissFeed(ctx, "did:test:alice", "https://a.com/feed", "reason2"))
535535
536536 var count int
537- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
537+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
538538 `SELECT COUNT(*) FROM main.dismissed_recommendations WHERE user_did = 'did:test:alice' AND target_type = 'feed'`).Scan(&count))
539539 assert.Equal(t, count, 1, "duplicate dismiss should not create extra rows")
540540 }
@@ -543,25 +543,25 @@ func TestEmbeddingBasedFeedSimilarity(t *testing.T) {
543543 ctx := context.Background()
544544 dbs := setupClusterTestDB(t)
545545
546- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
546+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
547547 assert.NilError(t, err)
548- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
548+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
549549 assert.NilError(t, err)
550550
551- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
551+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
552552 "https://go.com/feed", "Go Blog", "https://go.com", "programming language golang software development")
553553 assert.NilError(t, err)
554- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
554+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
555555 "https://rust.com/feed", "Rust Blog", "https://rust.com", "programming language rust software development")
556556 assert.NilError(t, err)
557557
558- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:alice", "https://go.com/feed")
558+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:alice", "https://go.com/feed")
559559 assert.NilError(t, err)
560- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:alice", "https://rust.com/feed")
560+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:alice", "https://rust.com/feed")
561561 assert.NilError(t, err)
562- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:bob", "https://go.com/feed")
562+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:bob", "https://go.com/feed")
563563 assert.NilError(t, err)
564- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:bob", "https://rust.com/feed")
564+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:bob", "https://rust.com/feed")
565565 assert.NilError(t, err)
566566
567567 engine := newTestEngine(dbs)
@@ -570,7 +570,7 @@ func TestEmbeddingBasedFeedSimilarity(t *testing.T) {
570570 assert.NilError(t, engine.ComputeFeedSimilarity(ctx))
571571
572572 var jaccard float64
573- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
573+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
574574 `SELECT jaccard FROM recs.feed_similarity WHERE feed_a = ? AND feed_b = ?`,
575575 "https://go.com/feed", "https://rust.com/feed").Scan(&jaccard))
576576 assert.Assert(t, jaccard > 1.0, "embedding cosine similarity should boost feed similarity above pure Jaccard")
@@ -610,17 +610,17 @@ func TestComputeArticleEmbeddings(t *testing.T) {
610610 ctx := context.Background()
611611 dbs := setupClusterTestDB(t)
612612
613- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 1)`,
613+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 1)`,
614614 "https://tech.com/feed", "Tech Feed", "https://tech.com")
615615 assert.NilError(t, err)
616616
617- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
617+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
618618 "https://tech.com/feed", "1", "golang programming language tutorial", "learn the go programming language for backend development", "https://tech.com/go")
619619 assert.NilError(t, err)
620- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
620+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
621621 "https://tech.com/feed", "2", "rust programming language guide", "learn the rust programming language for systems development", "https://tech.com/rust")
622622 assert.NilError(t, err)
623- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
623+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
624624 "https://tech.com/feed", "3", "cooking recipes for dinner", "easy dinner recipes for the whole family", "https://tech.com/cook")
625625 assert.NilError(t, err)
626626
@@ -629,7 +629,7 @@ func TestComputeArticleEmbeddings(t *testing.T) {
629629 assert.NilError(t, engine.ComputeArticleEmbeddings(ctx))
630630
631631 var count int
632- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.article_embeddings`).Scan(&count))
632+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.article_embeddings`).Scan(&count))
633633 assert.Equal(t, count, 3, "expected 3 article embeddings")
634634 }
635635
@@ -637,44 +637,44 @@ func TestArticleRecommendationsWithContentBoost(t *testing.T) {
637637 ctx := context.Background()
638638 dbs := setupClusterTestDB(t)
639639
640- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
640+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
641641 assert.NilError(t, err)
642- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
642+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
643643 assert.NilError(t, err)
644644
645- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
645+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
646646 "https://tech.com/feed", "Tech Feed", "https://tech.com")
647647 assert.NilError(t, err)
648- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
648+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
649649 "https://dev.com/feed", "Dev Feed", "https://dev.com")
650650 assert.NilError(t, err)
651- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
651+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
652652 "https://shared.com/feed", "Shared Feed", "https://shared.com")
653653 assert.NilError(t, err)
654654
655- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:alice", "https://tech.com/feed")
655+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:alice", "https://tech.com/feed")
656656 assert.NilError(t, err)
657- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:alice", "https://shared.com/feed")
657+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:alice", "https://shared.com/feed")
658658 assert.NilError(t, err)
659- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:bob", "https://dev.com/feed")
659+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:bob", "https://dev.com/feed")
660660 assert.NilError(t, err)
661- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:bob", "https://shared.com/feed")
661+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:bob", "https://shared.com/feed")
662662 assert.NilError(t, err)
663663
664- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
664+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
665665 "https://tech.com/feed", "1", "golang programming tutorial", "learn go programming", "https://tech.com/go")
666666 assert.NilError(t, err)
667- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
667+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
668668 "https://dev.com/feed", "2", "rust programming tutorial", "learn rust programming", "https://dev.com/rust")
669669 assert.NilError(t, err)
670- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
670+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
671671 "https://dev.com/feed", "3", "cooking dinner recipes", "easy dinner recipes", "https://dev.com/cook")
672672 assert.NilError(t, err)
673673
674- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.likes (uri, author_did, feed_url, article_url, created_at) VALUES (?, ?, ?, ?, datetime('now'))`,
674+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.likes (uri, author_did, feed_url, article_url, created_at) VALUES (?, ?, ?, ?, datetime('now'))`,
675675 "at://alice/like/1", "did:test:alice", "https://tech.com/feed", "https://tech.com/go")
676676 assert.NilError(t, err)
677- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.likes (uri, author_did, feed_url, article_url, created_at) VALUES (?, ?, ?, ?, datetime('now'))`,
677+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.likes (uri, author_did, feed_url, article_url, created_at) VALUES (?, ?, ?, ?, datetime('now'))`,
678678 "at://bob/like/1", "did:test:bob", "https://dev.com/feed", "https://dev.com/rust")
679679 assert.NilError(t, err)
680680
@@ -693,7 +693,7 @@ func TestFeedEmbeddingRecomputedOnDescriptionChange(t *testing.T) {
693693 ctx := context.Background()
694694 dbs := setupClusterTestDB(t)
695695
696- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type) VALUES (?, ?, ?, ?, 'rss')`,
696+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type) VALUES (?, ?, ?, ?, 'rss')`,
697697 "https://go.com/feed", "Go Blog", "https://go.com", "old description")
698698 assert.NilError(t, err)
699699
@@ -702,16 +702,16 @@ func TestFeedEmbeddingRecomputedOnDescriptionChange(t *testing.T) {
702702 assert.NilError(t, engine.ComputeFeedEmbeddings(ctx))
703703
704704 var count int
705- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.feed_embeddings`).Scan(&count))
705+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.feed_embeddings`).Scan(&count))
706706 assert.Equal(t, count, 1)
707707
708- _, err = dbs.DB().ExecContext(ctx, `UPDATE articles.feeds SET description = 'new description' WHERE feed_url = 'https://go.com/feed'`)
708+ _, err = dbs.SQLDB().ExecContext(ctx, `UPDATE articles.feeds SET description = 'new description' WHERE feed_url = 'https://go.com/feed'`)
709709 assert.NilError(t, err)
710710
711711 assert.NilError(t, engine.ComputeFeedEmbeddings(ctx))
712712
713713 var sourceText string
714- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT source_text FROM recs.feed_embedding_meta WHERE feed_url = 'https://go.com/feed'`).Scan(&sourceText))
714+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT source_text FROM recs.feed_embedding_meta WHERE feed_url = 'https://go.com/feed'`).Scan(&sourceText))
715715 assert.Assert(t, sourceText == "Go Blog new description", "embedding should be recomputed when description changes, got: %s", sourceText)
716716 }
717717
@@ -719,28 +719,28 @@ func TestTimeDecayedFeedSimilarity(t *testing.T) {
719719 ctx := context.Background()
720720 dbs := setupClusterTestDB(t)
721721
722- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
722+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
723723 assert.NilError(t, err)
724- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
724+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
725725 assert.NilError(t, err)
726726
727- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
727+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
728728 "https://a.com/feed", "Feed A", "https://a.com")
729729 assert.NilError(t, err)
730- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
730+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
731731 "https://b.com/feed", "Feed B", "https://b.com")
732732 assert.NilError(t, err)
733733
734- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now', '-60 days'))`,
734+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now', '-60 days'))`,
735735 "did:test:alice", "https://a.com/feed")
736736 assert.NilError(t, err)
737- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
737+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
738738 "did:test:bob", "https://a.com/feed")
739739 assert.NilError(t, err)
740- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
740+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
741741 "did:test:alice", "https://b.com/feed")
742742 assert.NilError(t, err)
743- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
743+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
744744 "did:test:bob", "https://b.com/feed")
745745 assert.NilError(t, err)
746746
@@ -748,7 +748,7 @@ func TestTimeDecayedFeedSimilarity(t *testing.T) {
748748 assert.NilError(t, engine.ComputeFeedSimilarity(ctx))
749749
750750 var jaccard float64
751- assert.NilError(t, dbs.DB().QueryRowContext(ctx,
751+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
752752 `SELECT jaccard FROM recs.feed_similarity WHERE feed_a = 'https://a.com/feed' AND feed_b = 'https://b.com/feed'`).Scan(&jaccard))
753753 assert.Assert(t, jaccard > 0, "time-decayed feed similarity should be positive")
754754 assert.Assert(t, jaccard < 1.0, "time decay should reduce similarity below raw Jaccard")
@@ -758,20 +758,20 @@ func TestColdStartFromEmbeddings(t *testing.T) {
758758 ctx := context.Background()
759759 dbs := setupClusterTestDB(t)
760760
761- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:newuser")
761+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:newuser")
762762 assert.NilError(t, err)
763763
764- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
764+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
765765 "https://go.com/feed", "Go Blog", "https://go.com", "golang programming language")
766766 assert.NilError(t, err)
767- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
767+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
768768 "https://godev.com/feed", "Go Dev", "https://godev.com", "golang development tutorials")
769769 assert.NilError(t, err)
770- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
770+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
771771 "https://cooking.com/feed", "Cooking", "https://cooking.com", "recipes for dinner")
772772 assert.NilError(t, err)
773773
774- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`,
774+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`,
775775 "did:test:newuser", "https://go.com/feed")
776776 assert.NilError(t, err)
777777
@@ -15,7 +15,7 @@ import (
15 "gotest.tools/v3/assert"15 "gotest.tools/v3/assert"
16 )16 )
17 17
18-func setupClusterTestDB(t *testing.T) *db.Databases {18+func setupClusterTestDB(t *testing.T) *db.Store {
19 t.Helper()19 t.Helper()
20 vec.Auto()20 vec.Auto()
21 f, err := os.CreateTemp("", "glean-cluster-test-*.db")21 f, err := os.CreateTemp("", "glean-cluster-test-*.db")
@@ -35,19 +35,19 @@ func setupClusterTestDB(t *testing.T) *db.Databases {
35 _ = os.Remove(path + "_recs-wal")35 _ = os.Remove(path + "_recs-wal")
36 })36 })
37 37
38- dbs, err := db.OpenAll(path)38+ dbs, err := db.Open(path)
39 assert.NilError(t, err)39 assert.NilError(t, err)
40 t.Cleanup(func() { _ = dbs.Close() })40 t.Cleanup(func() { _ = dbs.Close() })
41 assert.NilError(t, dbs.InitVecTables(8))41 assert.NilError(t, dbs.InitVecTables(8))
42 return dbs42 return dbs
43 }43 }
44 44
45-func seedClusterData(t *testing.T, ctx context.Context, dbs *db.Databases) {45+func seedClusterData(t *testing.T, ctx context.Context, dbs *db.Store) {
46 t.Helper()46 t.Helper()
47 47
48 users := []string{"did:test:alice", "did:test:bob", "did:test:carol", "did:test:dave"}48 users := []string{"did:test:alice", "did:test:bob", "did:test:carol", "did:test:dave"}
49 for _, did := range users {49 for _, did := range users {
50- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, did)50+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, did)
51 assert.NilError(t, err)51 assert.NilError(t, err)
52 }52 }
53 53
@@ -59,7 +59,7 @@ func seedClusterData(t *testing.T, ctx context.Context, dbs *db.Databases) {
59 {"https://e.com/feed", "Feed E"},59 {"https://e.com/feed", "Feed E"},
60 }60 }
61 for _, f := range feeds {61 for _, f := range feeds {
62- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, '', 'rss', 2)`, f.url, f.title, f.url)62+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, '', 'rss', 2)`, f.url, f.title, f.url)
63 assert.NilError(t, err)63 assert.NilError(t, err)
64 }64 }
65 65
@@ -75,12 +75,12 @@ func seedClusterData(t *testing.T, ctx context.Context, dbs *db.Databases) {
75 {"did:test:carol", "https://c.com/feed"},75 {"did:test:carol", "https://c.com/feed"},
76 }76 }
77 for _, s := range subs {77 for _, s := range subs {
78- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, s.user, s.feed)78+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, s.user, s.feed)
79 assert.NilError(t, err)79 assert.NilError(t, err)
80 }80 }
81 }81 }
82 82
83-func seedFollowData(t *testing.T, ctx context.Context, dbs *db.Databases) {83+func seedFollowData(t *testing.T, ctx context.Context, dbs *db.Store) {
84 t.Helper()84 t.Helper()
85 follows := []struct{ user, target string }{85 follows := []struct{ user, target string }{
86 {"did:test:alice", "did:test:bob"},86 {"did:test:alice", "did:test:bob"},
@@ -88,13 +88,13 @@ func seedFollowData(t *testing.T, ctx context.Context, dbs *db.Databases) {
88 {"did:test:carol", "did:test:dave"},88 {"did:test:carol", "did:test:dave"},
89 }89 }
90 for _, f := range follows {90 for _, f := range follows {
91- _, err := dbs.DB().ExecContext(ctx, `INSERT OR IGNORE INTO follows (user_did, target_did) VALUES (?, ?)`, f.user, f.target)91+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT OR IGNORE INTO follows (user_did, target_did) VALUES (?, ?)`, f.user, f.target)
92 assert.NilError(t, err)92 assert.NilError(t, err)
93 }93 }
94 }94 }
95 95
96-func newTestEngine(dbs *db.Databases) *Engine {96+func newTestEngine(dbs *db.Store) *Engine {
97- return NewEngine(dbs.DB(), NewMockEmbedder(8), slog.Default())97+ return NewEngine(dbs.SQLDB(), NewMockEmbedder(8), slog.Default())
98 }98 }
99 99
100 func TestComputeFeedSimilarity(t *testing.T) {100 func TestComputeFeedSimilarity(t *testing.T) {
@@ -107,7 +107,7 @@ func TestComputeFeedSimilarity(t *testing.T) {
107 assert.NilError(t, err)107 assert.NilError(t, err)
108 108
109 var count int109 var count int
110- err = dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.feed_similarity`).Scan(&count)110+ err = dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.feed_similarity`).Scan(&count)
111 assert.NilError(t, err)111 assert.NilError(t, err)
112 assert.Assert(t, count > 0, "expected feed similarity pairs")112 assert.Assert(t, count > 0, "expected feed similarity pairs")
113 }113 }
@@ -122,7 +122,7 @@ func TestComputeUserSimilarity(t *testing.T) {
122 assert.NilError(t, err)122 assert.NilError(t, err)
123 123
124 var count int124 var count int
125- err = dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.user_similarity`).Scan(&count)125+ err = dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.user_similarity`).Scan(&count)
126 assert.NilError(t, err)126 assert.NilError(t, err)
127 assert.Assert(t, count > 0, "expected user similarity pairs")127 assert.Assert(t, count > 0, "expected user similarity pairs")
128 }128 }
@@ -224,14 +224,14 @@ func TestRecordImpressions(t *testing.T) {
224 assert.NilError(t, engine.RecordImpressions(ctx, "did:test:alice", impressions))224 assert.NilError(t, engine.RecordImpressions(ctx, "did:test:alice", impressions))
225 225
226 var count int226 var count int
227- assert.NilError(t, dbs.DB().QueryRowContext(ctx,227+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
228 `SELECT COUNT(*) FROM main.recommendation_impressions WHERE user_did = 'did:test:alice'`).Scan(&count))228 `SELECT COUNT(*) FROM main.recommendation_impressions WHERE user_did = 'did:test:alice'`).Scan(&count))
229 assert.Equal(t, count, 2)229 assert.Equal(t, count, 2)
230 230
231 assert.NilError(t, engine.RecordImpressions(ctx, "did:test:alice", impressions))231 assert.NilError(t, engine.RecordImpressions(ctx, "did:test:alice", impressions))
232 232
233 var shownCount int233 var shownCount int
234- assert.NilError(t, dbs.DB().QueryRowContext(ctx,234+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
235 `SELECT shown_count FROM main.recommendation_impressions WHERE user_did = 'did:test:alice' AND target_id = 'https://a.com/feed'`).Scan(&shownCount))235 `SELECT shown_count FROM main.recommendation_impressions WHERE user_did = 'did:test:alice' AND target_id = 'https://a.com/feed'`).Scan(&shownCount))
236 assert.Equal(t, shownCount, 2, "shown_count should increment on repeated impression")236 assert.Equal(t, shownCount, 2, "shown_count should increment on repeated impression")
237 }237 }
@@ -249,7 +249,7 @@ func TestMarkImpressionActed(t *testing.T) {
249 assert.NilError(t, engine.MarkImpressionActed(ctx, "did:test:alice", "feed", "https://a.com/feed"))249 assert.NilError(t, engine.MarkImpressionActed(ctx, "did:test:alice", "feed", "https://a.com/feed"))
250 250
251 var acted bool251 var acted bool
252- assert.NilError(t, dbs.DB().QueryRowContext(ctx,252+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
253 `SELECT acted FROM main.recommendation_impressions WHERE user_did = 'did:test:alice' AND target_id = 'https://a.com/feed'`).Scan(&acted))253 `SELECT acted FROM main.recommendation_impressions WHERE user_did = 'did:test:alice' AND target_id = 'https://a.com/feed'`).Scan(&acted))
254 assert.Assert(t, acted, "impression should be marked as acted")254 assert.Assert(t, acted, "impression should be marked as acted")
255 }255 }
@@ -264,22 +264,22 @@ func TestComputeFollowDistances(t *testing.T) {
264 assert.NilError(t, engine.ComputeFollowDistances(ctx))264 assert.NilError(t, engine.ComputeFollowDistances(ctx))
265 265
266 var d1, d2, d3 int266 var d1, d2, d3 int
267- assert.NilError(t, dbs.DB().QueryRowContext(ctx,267+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
268 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 1`).Scan(&d1))268 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 1`).Scan(&d1))
269- assert.NilError(t, dbs.DB().QueryRowContext(ctx,269+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
270 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 2`).Scan(&d2))270 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 2`).Scan(&d2))
271- assert.NilError(t, dbs.DB().QueryRowContext(ctx,271+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
272 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 3`).Scan(&d3))272 `SELECT COUNT(*) FROM recs.follow_distances WHERE distance = 3`).Scan(&d3))
273 assert.Assert(t, d1 >= 3, "expected at least 3 direct follow distances")273 assert.Assert(t, d1 >= 3, "expected at least 3 direct follow distances")
274 assert.Assert(t, d2 >= 1, "expected at least 1 two-hop distance (alice -> bob -> carol)")274 assert.Assert(t, d2 >= 1, "expected at least 1 two-hop distance (alice -> bob -> carol)")
275 assert.Assert(t, d3 >= 1, "expected at least 1 three-hop distance (alice -> bob -> carol -> dave)")275 assert.Assert(t, d3 >= 1, "expected at least 1 three-hop distance (alice -> bob -> carol -> dave)")
276 276
277 var exists int277 var exists int
278- assert.NilError(t, dbs.DB().QueryRowContext(ctx,278+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
279 `SELECT COUNT(*) FROM recs.follow_distances WHERE user_a = 'did:test:alice' AND user_b = 'did:test:carol'`).Scan(&exists))279 `SELECT COUNT(*) FROM recs.follow_distances WHERE user_a = 'did:test:alice' AND user_b = 'did:test:carol'`).Scan(&exists))
280 assert.Assert(t, exists == 1, "alice should reach carol")280 assert.Assert(t, exists == 1, "alice should reach carol")
281 281
282- assert.NilError(t, dbs.DB().QueryRowContext(ctx,282+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
283 `SELECT COUNT(*) FROM recs.follow_distances WHERE user_a = 'did:test:alice' AND user_b = 'did:test:dave'`).Scan(&exists))283 `SELECT COUNT(*) FROM recs.follow_distances WHERE user_a = 'did:test:alice' AND user_b = 'did:test:dave'`).Scan(&exists))
284 assert.Assert(t, exists == 1, "alice should reach dave via 3 hops")284 assert.Assert(t, exists == 1, "alice should reach dave via 3 hops")
285 }285 }
@@ -300,7 +300,7 @@ func TestComputeFollowDistancesData_SplitReadWrite(t *testing.T) {
300 assert.NilError(t, engine.WriteFollowDistances(ctx, distances))300 assert.NilError(t, engine.WriteFollowDistances(ctx, distances))
301 301
302 var count int302 var count int
303- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.follow_distances`).Scan(&count))303+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.follow_distances`).Scan(&count))
304 assert.Equal(t, count, len(distances))304 assert.Equal(t, count, len(distances))
305 }305 }
306 306
@@ -311,7 +311,7 @@ func TestAutoDismissStale(t *testing.T) {
311 311
312 engine := newTestEngine(dbs)312 engine := newTestEngine(dbs)
313 313
314- _, err := dbs.DB().ExecContext(ctx, `314+ _, err := dbs.SQLDB().ExecContext(ctx, `
315 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)315 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
316 VALUES ('did:test:alice', 'feed', 'https://stale.com/feed', datetime('now', '-6 days'), datetime('now'), 6, 0)316 VALUES ('did:test:alice', 'feed', 'https://stale.com/feed', datetime('now', '-6 days'), datetime('now'), 6, 0)
317 `)317 `)
@@ -331,7 +331,7 @@ func TestAutoDismissStale_DoesNotDismissRecent(t *testing.T) {
331 331
332 engine := newTestEngine(dbs)332 engine := newTestEngine(dbs)
333 333
334- _, err := dbs.DB().ExecContext(ctx, `334+ _, err := dbs.SQLDB().ExecContext(ctx, `
335 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)335 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
336 VALUES ('did:test:alice', 'feed', 'https://recent.com/feed', datetime('now'), datetime('now'), 5, 0)336 VALUES ('did:test:alice', 'feed', 'https://recent.com/feed', datetime('now'), datetime('now'), 5, 0)
337 `)337 `)
@@ -351,7 +351,7 @@ func TestAutoDismissStale_DoesNotDismissActed(t *testing.T) {
351 351
352 engine := newTestEngine(dbs)352 engine := newTestEngine(dbs)
353 353
354- _, err := dbs.DB().ExecContext(ctx, `354+ _, err := dbs.SQLDB().ExecContext(ctx, `
355 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)355 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
356 VALUES ('did:test:alice', 'feed', 'https://acted.com/feed', datetime('now', '-6 days'), datetime('now'), 6, 1)356 VALUES ('did:test:alice', 'feed', 'https://acted.com/feed', datetime('now', '-6 days'), datetime('now'), 6, 1)
357 `)357 `)
@@ -427,13 +427,13 @@ func TestSignalWeights_RewardPenalize(t *testing.T) {
427 427
428 engine := newTestEngine(dbs)428 engine := newTestEngine(dbs)
429 429
430- _, err := dbs.DB().ExecContext(ctx, `430+ _, err := dbs.SQLDB().ExecContext(ctx, `
431 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)431 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
432 VALUES ('did:test:alice', 'feed', 'https://a.com/feed', datetime('now'), datetime('now'), 1, 1)432 VALUES ('did:test:alice', 'feed', 'https://a.com/feed', datetime('now'), datetime('now'), 1, 1)
433 `)433 `)
434 assert.NilError(t, err)434 assert.NilError(t, err)
435 for i := range minActionsTune {435 for i := range minActionsTune {
436- _, err = dbs.DB().ExecContext(ctx, `436+ _, err = dbs.SQLDB().ExecContext(ctx, `
437 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)437 INSERT INTO main.recommendation_impressions (user_did, target_type, target_id, first_shown_at, last_shown_at, shown_count, acted)
438 VALUES ('did:test:alice', 'feed', ?, datetime('now'), datetime('now'), 1, 1)438 VALUES ('did:test:alice', 'feed', ?, datetime('now'), datetime('now'), 1, 1)
439 `, fmt.Sprintf("https://%d.com/feed", i))439 `, fmt.Sprintf("https://%d.com/feed", i))
@@ -455,12 +455,12 @@ func TestColdStartRecommendations(t *testing.T) {
455 engine := newTestEngine(dbs)455 engine := newTestEngine(dbs)
456 assert.NilError(t, engine.ComputeFollowDistances(ctx))456 assert.NilError(t, engine.ComputeFollowDistances(ctx))
457 457
458- _, err := dbs.DB().ExecContext(ctx, `UPDATE articles.feeds SET subscriber_count = 2 WHERE feed_url = 'https://a.com/feed'`)458+ _, err := dbs.SQLDB().ExecContext(ctx, `UPDATE articles.feeds SET subscriber_count = 2 WHERE feed_url = 'https://a.com/feed'`)
459 assert.NilError(t, err)459 assert.NilError(t, err)
460- _, err = dbs.DB().ExecContext(ctx, `UPDATE articles.feeds SET subscriber_count = 2 WHERE feed_url = 'https://b.com/feed'`)460+ _, err = dbs.SQLDB().ExecContext(ctx, `UPDATE articles.feeds SET subscriber_count = 2 WHERE feed_url = 'https://b.com/feed'`)
461 assert.NilError(t, err)461 assert.NilError(t, err)
462 462
463- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:newuser")463+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:newuser")
464 assert.NilError(t, err)464 assert.NilError(t, err)
465 465
466 recs, err := engine.ColdStartRecommendations(ctx, "did:test:newuser", 10)466 recs, err := engine.ColdStartRecommendations(ctx, "did:test:newuser", 10)
@@ -505,7 +505,7 @@ func TestDismissArticle(t *testing.T) {
505 assert.NilError(t, engine.DismissArticle(ctx, "did:test:alice", "https://a.com/article1", "not_interested"))505 assert.NilError(t, engine.DismissArticle(ctx, "did:test:alice", "https://a.com/article1", "not_interested"))
506 506
507 var count int507 var count int
508- assert.NilError(t, dbs.DB().QueryRowContext(ctx,508+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
509 `SELECT COUNT(*) FROM main.dismissed_recommendations WHERE user_did = 'did:test:alice' AND target_type = 'article'`).Scan(&count))509 `SELECT COUNT(*) FROM main.dismissed_recommendations WHERE user_did = 'did:test:alice' AND target_type = 'article'`).Scan(&count))
510 assert.Equal(t, count, 1)510 assert.Equal(t, count, 1)
511 }511 }
@@ -519,7 +519,7 @@ func TestComputeSignalProfiles(t *testing.T) {
519 assert.NilError(t, engine.ComputeSignalProfiles(ctx))519 assert.NilError(t, engine.ComputeSignalProfiles(ctx))
520 520
521 var count int521 var count int
522- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.user_signal_profiles`).Scan(&count))522+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.user_signal_profiles`).Scan(&count))
523 assert.Assert(t, count >= 3, "expected signal profiles for all users")523 assert.Assert(t, count >= 3, "expected signal profiles for all users")
524 }524 }
525 525
@@ -534,7 +534,7 @@ func TestDismissFeed_Idempotent(t *testing.T) {
534 assert.NilError(t, engine.DismissFeed(ctx, "did:test:alice", "https://a.com/feed", "reason2"))534 assert.NilError(t, engine.DismissFeed(ctx, "did:test:alice", "https://a.com/feed", "reason2"))
535 535
536 var count int536 var count int
537- assert.NilError(t, dbs.DB().QueryRowContext(ctx,537+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
538 `SELECT COUNT(*) FROM main.dismissed_recommendations WHERE user_did = 'did:test:alice' AND target_type = 'feed'`).Scan(&count))538 `SELECT COUNT(*) FROM main.dismissed_recommendations WHERE user_did = 'did:test:alice' AND target_type = 'feed'`).Scan(&count))
539 assert.Equal(t, count, 1, "duplicate dismiss should not create extra rows")539 assert.Equal(t, count, 1, "duplicate dismiss should not create extra rows")
540 }540 }
@@ -543,25 +543,25 @@ func TestEmbeddingBasedFeedSimilarity(t *testing.T) {
543 ctx := context.Background()543 ctx := context.Background()
544 dbs := setupClusterTestDB(t)544 dbs := setupClusterTestDB(t)
545 545
546- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")546+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
547 assert.NilError(t, err)547 assert.NilError(t, err)
548- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")548+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
549 assert.NilError(t, err)549 assert.NilError(t, err)
550 550
551- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,551+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
552 "https://go.com/feed", "Go Blog", "https://go.com", "programming language golang software development")552 "https://go.com/feed", "Go Blog", "https://go.com", "programming language golang software development")
553 assert.NilError(t, err)553 assert.NilError(t, err)
554- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,554+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
555 "https://rust.com/feed", "Rust Blog", "https://rust.com", "programming language rust software development")555 "https://rust.com/feed", "Rust Blog", "https://rust.com", "programming language rust software development")
556 assert.NilError(t, err)556 assert.NilError(t, err)
557 557
558- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:alice", "https://go.com/feed")558+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:alice", "https://go.com/feed")
559 assert.NilError(t, err)559 assert.NilError(t, err)
560- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:alice", "https://rust.com/feed")560+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:alice", "https://rust.com/feed")
561 assert.NilError(t, err)561 assert.NilError(t, err)
562- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:bob", "https://go.com/feed")562+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:bob", "https://go.com/feed")
563 assert.NilError(t, err)563 assert.NilError(t, err)
564- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:bob", "https://rust.com/feed")564+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, CURRENT_TIMESTAMP)`, "did:test:bob", "https://rust.com/feed")
565 assert.NilError(t, err)565 assert.NilError(t, err)
566 566
567 engine := newTestEngine(dbs)567 engine := newTestEngine(dbs)
@@ -570,7 +570,7 @@ func TestEmbeddingBasedFeedSimilarity(t *testing.T) {
570 assert.NilError(t, engine.ComputeFeedSimilarity(ctx))570 assert.NilError(t, engine.ComputeFeedSimilarity(ctx))
571 571
572 var jaccard float64572 var jaccard float64
573- assert.NilError(t, dbs.DB().QueryRowContext(ctx,573+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
574 `SELECT jaccard FROM recs.feed_similarity WHERE feed_a = ? AND feed_b = ?`,574 `SELECT jaccard FROM recs.feed_similarity WHERE feed_a = ? AND feed_b = ?`,
575 "https://go.com/feed", "https://rust.com/feed").Scan(&jaccard))575 "https://go.com/feed", "https://rust.com/feed").Scan(&jaccard))
576 assert.Assert(t, jaccard > 1.0, "embedding cosine similarity should boost feed similarity above pure Jaccard")576 assert.Assert(t, jaccard > 1.0, "embedding cosine similarity should boost feed similarity above pure Jaccard")
@@ -610,17 +610,17 @@ func TestComputeArticleEmbeddings(t *testing.T) {
610 ctx := context.Background()610 ctx := context.Background()
611 dbs := setupClusterTestDB(t)611 dbs := setupClusterTestDB(t)
612 612
613- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 1)`,613+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 1)`,
614 "https://tech.com/feed", "Tech Feed", "https://tech.com")614 "https://tech.com/feed", "Tech Feed", "https://tech.com")
615 assert.NilError(t, err)615 assert.NilError(t, err)
616 616
617- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,617+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
618 "https://tech.com/feed", "1", "golang programming language tutorial", "learn the go programming language for backend development", "https://tech.com/go")618 "https://tech.com/feed", "1", "golang programming language tutorial", "learn the go programming language for backend development", "https://tech.com/go")
619 assert.NilError(t, err)619 assert.NilError(t, err)
620- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,620+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
621 "https://tech.com/feed", "2", "rust programming language guide", "learn the rust programming language for systems development", "https://tech.com/rust")621 "https://tech.com/feed", "2", "rust programming language guide", "learn the rust programming language for systems development", "https://tech.com/rust")
622 assert.NilError(t, err)622 assert.NilError(t, err)
623- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,623+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url) VALUES (?, ?, ?, ?, ?)`,
624 "https://tech.com/feed", "3", "cooking recipes for dinner", "easy dinner recipes for the whole family", "https://tech.com/cook")624 "https://tech.com/feed", "3", "cooking recipes for dinner", "easy dinner recipes for the whole family", "https://tech.com/cook")
625 assert.NilError(t, err)625 assert.NilError(t, err)
626 626
@@ -629,7 +629,7 @@ func TestComputeArticleEmbeddings(t *testing.T) {
629 assert.NilError(t, engine.ComputeArticleEmbeddings(ctx))629 assert.NilError(t, engine.ComputeArticleEmbeddings(ctx))
630 630
631 var count int631 var count int
632- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.article_embeddings`).Scan(&count))632+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.article_embeddings`).Scan(&count))
633 assert.Equal(t, count, 3, "expected 3 article embeddings")633 assert.Equal(t, count, 3, "expected 3 article embeddings")
634 }634 }
635 635
@@ -637,44 +637,44 @@ func TestArticleRecommendationsWithContentBoost(t *testing.T) {
637 ctx := context.Background()637 ctx := context.Background()
638 dbs := setupClusterTestDB(t)638 dbs := setupClusterTestDB(t)
639 639
640- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")640+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
641 assert.NilError(t, err)641 assert.NilError(t, err)
642- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")642+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
643 assert.NilError(t, err)643 assert.NilError(t, err)
644 644
645- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,645+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
646 "https://tech.com/feed", "Tech Feed", "https://tech.com")646 "https://tech.com/feed", "Tech Feed", "https://tech.com")
647 assert.NilError(t, err)647 assert.NilError(t, err)
648- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,648+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
649 "https://dev.com/feed", "Dev Feed", "https://dev.com")649 "https://dev.com/feed", "Dev Feed", "https://dev.com")
650 assert.NilError(t, err)650 assert.NilError(t, err)
651- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,651+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
652 "https://shared.com/feed", "Shared Feed", "https://shared.com")652 "https://shared.com/feed", "Shared Feed", "https://shared.com")
653 assert.NilError(t, err)653 assert.NilError(t, err)
654 654
655- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:alice", "https://tech.com/feed")655+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:alice", "https://tech.com/feed")
656 assert.NilError(t, err)656 assert.NilError(t, err)
657- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:alice", "https://shared.com/feed")657+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:alice", "https://shared.com/feed")
658 assert.NilError(t, err)658 assert.NilError(t, err)
659- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:bob", "https://dev.com/feed")659+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:bob", "https://dev.com/feed")
660 assert.NilError(t, err)660 assert.NilError(t, err)
661- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:bob", "https://shared.com/feed")661+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, "did:test:bob", "https://shared.com/feed")
662 assert.NilError(t, err)662 assert.NilError(t, err)
663 663
664- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,664+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
665 "https://tech.com/feed", "1", "golang programming tutorial", "learn go programming", "https://tech.com/go")665 "https://tech.com/feed", "1", "golang programming tutorial", "learn go programming", "https://tech.com/go")
666 assert.NilError(t, err)666 assert.NilError(t, err)
667- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,667+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
668 "https://dev.com/feed", "2", "rust programming tutorial", "learn rust programming", "https://dev.com/rust")668 "https://dev.com/feed", "2", "rust programming tutorial", "learn rust programming", "https://dev.com/rust")
669 assert.NilError(t, err)669 assert.NilError(t, err)
670- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,670+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, summary, url, published) VALUES (?, ?, ?, ?, ?, datetime('now'))`,
671 "https://dev.com/feed", "3", "cooking dinner recipes", "easy dinner recipes", "https://dev.com/cook")671 "https://dev.com/feed", "3", "cooking dinner recipes", "easy dinner recipes", "https://dev.com/cook")
672 assert.NilError(t, err)672 assert.NilError(t, err)
673 673
674- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.likes (uri, author_did, feed_url, article_url, created_at) VALUES (?, ?, ?, ?, datetime('now'))`,674+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.likes (uri, author_did, feed_url, article_url, created_at) VALUES (?, ?, ?, ?, datetime('now'))`,
675 "at://alice/like/1", "did:test:alice", "https://tech.com/feed", "https://tech.com/go")675 "at://alice/like/1", "did:test:alice", "https://tech.com/feed", "https://tech.com/go")
676 assert.NilError(t, err)676 assert.NilError(t, err)
677- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.likes (uri, author_did, feed_url, article_url, created_at) VALUES (?, ?, ?, ?, datetime('now'))`,677+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.likes (uri, author_did, feed_url, article_url, created_at) VALUES (?, ?, ?, ?, datetime('now'))`,
678 "at://bob/like/1", "did:test:bob", "https://dev.com/feed", "https://dev.com/rust")678 "at://bob/like/1", "did:test:bob", "https://dev.com/feed", "https://dev.com/rust")
679 assert.NilError(t, err)679 assert.NilError(t, err)
680 680
@@ -693,7 +693,7 @@ func TestFeedEmbeddingRecomputedOnDescriptionChange(t *testing.T) {
693 ctx := context.Background()693 ctx := context.Background()
694 dbs := setupClusterTestDB(t)694 dbs := setupClusterTestDB(t)
695 695
696- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type) VALUES (?, ?, ?, ?, 'rss')`,696+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type) VALUES (?, ?, ?, ?, 'rss')`,
697 "https://go.com/feed", "Go Blog", "https://go.com", "old description")697 "https://go.com/feed", "Go Blog", "https://go.com", "old description")
698 assert.NilError(t, err)698 assert.NilError(t, err)
699 699
@@ -702,16 +702,16 @@ func TestFeedEmbeddingRecomputedOnDescriptionChange(t *testing.T) {
702 assert.NilError(t, engine.ComputeFeedEmbeddings(ctx))702 assert.NilError(t, engine.ComputeFeedEmbeddings(ctx))
703 703
704 var count int704 var count int
705- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.feed_embeddings`).Scan(&count))705+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT COUNT(*) FROM recs.feed_embeddings`).Scan(&count))
706 assert.Equal(t, count, 1)706 assert.Equal(t, count, 1)
707 707
708- _, err = dbs.DB().ExecContext(ctx, `UPDATE articles.feeds SET description = 'new description' WHERE feed_url = 'https://go.com/feed'`)708+ _, err = dbs.SQLDB().ExecContext(ctx, `UPDATE articles.feeds SET description = 'new description' WHERE feed_url = 'https://go.com/feed'`)
709 assert.NilError(t, err)709 assert.NilError(t, err)
710 710
711 assert.NilError(t, engine.ComputeFeedEmbeddings(ctx))711 assert.NilError(t, engine.ComputeFeedEmbeddings(ctx))
712 712
713 var sourceText string713 var sourceText string
714- assert.NilError(t, dbs.DB().QueryRowContext(ctx, `SELECT source_text FROM recs.feed_embedding_meta WHERE feed_url = 'https://go.com/feed'`).Scan(&sourceText))714+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx, `SELECT source_text FROM recs.feed_embedding_meta WHERE feed_url = 'https://go.com/feed'`).Scan(&sourceText))
715 assert.Assert(t, sourceText == "Go Blog new description", "embedding should be recomputed when description changes, got: %s", sourceText)715 assert.Assert(t, sourceText == "Go Blog new description", "embedding should be recomputed when description changes, got: %s", sourceText)
716 }716 }
717 717
@@ -719,28 +719,28 @@ func TestTimeDecayedFeedSimilarity(t *testing.T) {
719 ctx := context.Background()719 ctx := context.Background()
720 dbs := setupClusterTestDB(t)720 dbs := setupClusterTestDB(t)
721 721
722- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")722+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:alice")
723 assert.NilError(t, err)723 assert.NilError(t, err)
724- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")724+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:bob")
725 assert.NilError(t, err)725 assert.NilError(t, err)
726 726
727- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,727+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
728 "https://a.com/feed", "Feed A", "https://a.com")728 "https://a.com/feed", "Feed A", "https://a.com")
729 assert.NilError(t, err)729 assert.NilError(t, err)
730- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,730+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, feed_type, subscriber_count) VALUES (?, ?, ?, 'rss', 2)`,
731 "https://b.com/feed", "Feed B", "https://b.com")731 "https://b.com/feed", "Feed B", "https://b.com")
732 assert.NilError(t, err)732 assert.NilError(t, err)
733 733
734- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now', '-60 days'))`,734+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now', '-60 days'))`,
735 "did:test:alice", "https://a.com/feed")735 "did:test:alice", "https://a.com/feed")
736 assert.NilError(t, err)736 assert.NilError(t, err)
737- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,737+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
738 "did:test:bob", "https://a.com/feed")738 "did:test:bob", "https://a.com/feed")
739 assert.NilError(t, err)739 assert.NilError(t, err)
740- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,740+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
741 "did:test:alice", "https://b.com/feed")741 "did:test:alice", "https://b.com/feed")
742 assert.NilError(t, err)742 assert.NilError(t, err)
743- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,743+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url, added_at) VALUES (?, ?, datetime('now'))`,
744 "did:test:bob", "https://b.com/feed")744 "did:test:bob", "https://b.com/feed")
745 assert.NilError(t, err)745 assert.NilError(t, err)
746 746
@@ -748,7 +748,7 @@ func TestTimeDecayedFeedSimilarity(t *testing.T) {
748 assert.NilError(t, engine.ComputeFeedSimilarity(ctx))748 assert.NilError(t, engine.ComputeFeedSimilarity(ctx))
749 749
750 var jaccard float64750 var jaccard float64
751- assert.NilError(t, dbs.DB().QueryRowContext(ctx,751+ assert.NilError(t, dbs.SQLDB().QueryRowContext(ctx,
752 `SELECT jaccard FROM recs.feed_similarity WHERE feed_a = 'https://a.com/feed' AND feed_b = 'https://b.com/feed'`).Scan(&jaccard))752 `SELECT jaccard FROM recs.feed_similarity WHERE feed_a = 'https://a.com/feed' AND feed_b = 'https://b.com/feed'`).Scan(&jaccard))
753 assert.Assert(t, jaccard > 0, "time-decayed feed similarity should be positive")753 assert.Assert(t, jaccard > 0, "time-decayed feed similarity should be positive")
754 assert.Assert(t, jaccard < 1.0, "time decay should reduce similarity below raw Jaccard")754 assert.Assert(t, jaccard < 1.0, "time decay should reduce similarity below raw Jaccard")
@@ -758,20 +758,20 @@ func TestColdStartFromEmbeddings(t *testing.T) {
758 ctx := context.Background()758 ctx := context.Background()
759 dbs := setupClusterTestDB(t)759 dbs := setupClusterTestDB(t)
760 760
761- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:newuser")761+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, "did:test:newuser")
762 assert.NilError(t, err)762 assert.NilError(t, err)
763 763
764- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,764+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
765 "https://go.com/feed", "Go Blog", "https://go.com", "golang programming language")765 "https://go.com/feed", "Go Blog", "https://go.com", "golang programming language")
766 assert.NilError(t, err)766 assert.NilError(t, err)
767- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,767+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
768 "https://godev.com/feed", "Go Dev", "https://godev.com", "golang development tutorials")768 "https://godev.com/feed", "Go Dev", "https://godev.com", "golang development tutorials")
769 assert.NilError(t, err)769 assert.NilError(t, err)
770- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,770+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title, site_url, description, feed_type, subscriber_count) VALUES (?, ?, ?, ?, 'rss', 2)`,
771 "https://cooking.com/feed", "Cooking", "https://cooking.com", "recipes for dinner")771 "https://cooking.com/feed", "Cooking", "https://cooking.com", "recipes for dinner")
772 assert.NilError(t, err)772 assert.NilError(t, err)
773 773
774- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`,774+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`,
775 "did:test:newuser", "https://go.com/feed")775 "did:test:newuser", "https://go.com/feed")
776 assert.NilError(t, err)776 assert.NilError(t, err)
777 777
modified internal/db/article.go +1 -1
@@ -51,7 +51,7 @@ type ReadState struct {
5151 ReadAt sql.NullTime
5252 }
5353
54-func (s *ArticleStore) UpsertArticlesBatch(ctx context.Context, articles []feed.Article) error {
54+func (s *ArticleStore) BatchUpsertArticles(ctx context.Context, articles []feed.Article) error {
5555 if len(articles) == 0 {
5656 return nil
5757 }
@@ -51,7 +51,7 @@ type ReadState struct {
51 ReadAt sql.NullTime51 ReadAt sql.NullTime
52 }52 }
53 53
54-func (s *ArticleStore) UpsertArticlesBatch(ctx context.Context, articles []feed.Article) error {54+func (s *ArticleStore) BatchUpsertArticles(ctx context.Context, articles []feed.Article) error {
55 if len(articles) == 0 {55 if len(articles) == 0 {
56 return nil56 return nil
57 }57 }
modified internal/db/article_test.go +15 -15
@@ -9,7 +9,7 @@ import (
99 "gotest.tools/v3/assert"
1010 )
1111
12-func setupTestDB(t *testing.T) *Databases {
12+func setupTestDB(t *testing.T) *Store {
1313 t.Helper()
1414 f, err := os.CreateTemp("", "glean-test-*.db")
1515 assert.NilError(t, err)
@@ -21,33 +21,33 @@ func setupTestDB(t *testing.T) *Databases {
2121 }
2222 })
2323
24- dbs, err := OpenAll(path)
24+ dbs, err := Open(path)
2525 assert.NilError(t, err)
2626 t.Cleanup(func() { _ = dbs.Close() })
2727 return dbs
2828 }
2929
30-func seedArticleReadState(t *testing.T, ctx context.Context, dbs *Databases) (userDID string, feedURL string, readArticleID, unreadArticleID int64) {
30+func seedArticleReadState(t *testing.T, ctx context.Context, dbs *Store) (userDID string, feedURL string, readArticleID, unreadArticleID int64) {
3131 t.Helper()
3232
3333 userDID = "did:test:user1"
3434 feedURL = "https://example.com/feed.xml"
3535
36- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
36+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
3737 assert.NilError(t, err)
3838
39- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, feedURL, "Test Feed")
39+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, feedURL, "Test Feed")
4040 assert.NilError(t, err)
4141
42- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, userDID, feedURL)
42+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, userDID, feedURL)
4343 assert.NilError(t, err)
4444
45- res, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, url) VALUES (?, ?, ?, ?)`,
45+ res, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, url) VALUES (?, ?, ?, ?)`,
4646 feedURL, "guid-read", "Read Article", "https://example.com/read")
4747 assert.NilError(t, err)
4848 readArticleID, _ = res.LastInsertId()
4949
50- res, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, url) VALUES (?, ?, ?, ?)`,
50+ res, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, url) VALUES (?, ?, ?, ?)`,
5151 feedURL, "guid-unread", "Unread Article", "https://example.com/unread")
5252 assert.NilError(t, err)
5353 unreadArticleID, _ = res.LastInsertId()
@@ -190,19 +190,19 @@ func TestGetArticle_IncludesFullContent(t *testing.T) {
190190 assert.Assert(t, !article.FullContent.Valid)
191191 }
192192
193-func seedSearchData(t *testing.T, ctx context.Context, dbs *Databases) (userDID, feedURL string) {
193+func seedSearchData(t *testing.T, ctx context.Context, dbs *Store) (userDID, feedURL string) {
194194 t.Helper()
195195
196196 userDID = "did:test:searcher"
197197 feedURL = "https://search.example.com/feed.xml"
198198
199- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
199+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
200200 assert.NilError(t, err)
201201
202- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, feedURL, "Tech Blog")
202+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, feedURL, "Tech Blog")
203203 assert.NilError(t, err)
204204
205- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, userDID, feedURL)
205+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, userDID, feedURL)
206206 assert.NilError(t, err)
207207
208208 articles := []struct {
@@ -213,7 +213,7 @@ func seedSearchData(t *testing.T, ctx context.Context, dbs *Databases) (userDID,
213213 {"g3", "Python Data Science", "NumPy and Pandas tutorial", "Python is popular for data analysis"},
214214 }
215215 for _, a := range articles {
216- _, err := dbs.DB().ExecContext(ctx, `
216+ _, err := dbs.SQLDB().ExecContext(ctx, `
217217 INSERT INTO articles.articles (feed_url, guid, title, summary, content) VALUES (?, ?, ?, ?, ?)
218218 `, feedURL, a.guid, a.title, a.summary, a.content)
219219 assert.NilError(t, err)
@@ -289,10 +289,10 @@ func TestSearchArticles_ScopedToSubscriptions(t *testing.T) {
289289 userDID, feedURL := seedSearchData(t, ctx, dbs)
290290
291291 otherFeed := "https://other.example.com/feed.xml"
292- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, otherFeed, "Other Feed")
292+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, otherFeed, "Other Feed")
293293 assert.NilError(t, err)
294294
295- _, err = dbs.DB().ExecContext(ctx, `
295+ _, err = dbs.SQLDB().ExecContext(ctx, `
296296 INSERT INTO articles.articles (feed_url, guid, title) VALUES (?, ?, ?)
297297 `, otherFeed, "other-1", "Go Concurrency Tips")
298298 assert.NilError(t, err)
@@ -9,7 +9,7 @@ import (
9 "gotest.tools/v3/assert"9 "gotest.tools/v3/assert"
10 )10 )
11 11
12-func setupTestDB(t *testing.T) *Databases {12+func setupTestDB(t *testing.T) *Store {
13 t.Helper()13 t.Helper()
14 f, err := os.CreateTemp("", "glean-test-*.db")14 f, err := os.CreateTemp("", "glean-test-*.db")
15 assert.NilError(t, err)15 assert.NilError(t, err)
@@ -21,33 +21,33 @@ func setupTestDB(t *testing.T) *Databases {
21 }21 }
22 })22 })
23 23
24- dbs, err := OpenAll(path)24+ dbs, err := Open(path)
25 assert.NilError(t, err)25 assert.NilError(t, err)
26 t.Cleanup(func() { _ = dbs.Close() })26 t.Cleanup(func() { _ = dbs.Close() })
27 return dbs27 return dbs
28 }28 }
29 29
30-func seedArticleReadState(t *testing.T, ctx context.Context, dbs *Databases) (userDID string, feedURL string, readArticleID, unreadArticleID int64) {30+func seedArticleReadState(t *testing.T, ctx context.Context, dbs *Store) (userDID string, feedURL string, readArticleID, unreadArticleID int64) {
31 t.Helper()31 t.Helper()
32 32
33 userDID = "did:test:user1"33 userDID = "did:test:user1"
34 feedURL = "https://example.com/feed.xml"34 feedURL = "https://example.com/feed.xml"
35 35
36- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)36+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
37 assert.NilError(t, err)37 assert.NilError(t, err)
38 38
39- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, feedURL, "Test Feed")39+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, feedURL, "Test Feed")
40 assert.NilError(t, err)40 assert.NilError(t, err)
41 41
42- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, userDID, feedURL)42+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, userDID, feedURL)
43 assert.NilError(t, err)43 assert.NilError(t, err)
44 44
45- res, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, url) VALUES (?, ?, ?, ?)`,45+ res, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, url) VALUES (?, ?, ?, ?)`,
46 feedURL, "guid-read", "Read Article", "https://example.com/read")46 feedURL, "guid-read", "Read Article", "https://example.com/read")
47 assert.NilError(t, err)47 assert.NilError(t, err)
48 readArticleID, _ = res.LastInsertId()48 readArticleID, _ = res.LastInsertId()
49 49
50- res, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, url) VALUES (?, ?, ?, ?)`,50+ res, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.articles (feed_url, guid, title, url) VALUES (?, ?, ?, ?)`,
51 feedURL, "guid-unread", "Unread Article", "https://example.com/unread")51 feedURL, "guid-unread", "Unread Article", "https://example.com/unread")
52 assert.NilError(t, err)52 assert.NilError(t, err)
53 unreadArticleID, _ = res.LastInsertId()53 unreadArticleID, _ = res.LastInsertId()
@@ -190,19 +190,19 @@ func TestGetArticle_IncludesFullContent(t *testing.T) {
190 assert.Assert(t, !article.FullContent.Valid)190 assert.Assert(t, !article.FullContent.Valid)
191 }191 }
192 192
193-func seedSearchData(t *testing.T, ctx context.Context, dbs *Databases) (userDID, feedURL string) {193+func seedSearchData(t *testing.T, ctx context.Context, dbs *Store) (userDID, feedURL string) {
194 t.Helper()194 t.Helper()
195 195
196 userDID = "did:test:searcher"196 userDID = "did:test:searcher"
197 feedURL = "https://search.example.com/feed.xml"197 feedURL = "https://search.example.com/feed.xml"
198 198
199- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)199+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
200 assert.NilError(t, err)200 assert.NilError(t, err)
201 201
202- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, feedURL, "Tech Blog")202+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, feedURL, "Tech Blog")
203 assert.NilError(t, err)203 assert.NilError(t, err)
204 204
205- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, userDID, feedURL)205+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.subscriptions (user_did, feed_url) VALUES (?, ?)`, userDID, feedURL)
206 assert.NilError(t, err)206 assert.NilError(t, err)
207 207
208 articles := []struct {208 articles := []struct {
@@ -213,7 +213,7 @@ func seedSearchData(t *testing.T, ctx context.Context, dbs *Databases) (userDID,
213 {"g3", "Python Data Science", "NumPy and Pandas tutorial", "Python is popular for data analysis"},213 {"g3", "Python Data Science", "NumPy and Pandas tutorial", "Python is popular for data analysis"},
214 }214 }
215 for _, a := range articles {215 for _, a := range articles {
216- _, err := dbs.DB().ExecContext(ctx, `216+ _, err := dbs.SQLDB().ExecContext(ctx, `
217 INSERT INTO articles.articles (feed_url, guid, title, summary, content) VALUES (?, ?, ?, ?, ?)217 INSERT INTO articles.articles (feed_url, guid, title, summary, content) VALUES (?, ?, ?, ?, ?)
218 `, feedURL, a.guid, a.title, a.summary, a.content)218 `, feedURL, a.guid, a.title, a.summary, a.content)
219 assert.NilError(t, err)219 assert.NilError(t, err)
@@ -289,10 +289,10 @@ func TestSearchArticles_ScopedToSubscriptions(t *testing.T) {
289 userDID, feedURL := seedSearchData(t, ctx, dbs)289 userDID, feedURL := seedSearchData(t, ctx, dbs)
290 290
291 otherFeed := "https://other.example.com/feed.xml"291 otherFeed := "https://other.example.com/feed.xml"
292- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, otherFeed, "Other Feed")292+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO articles.feeds (feed_url, title) VALUES (?, ?)`, otherFeed, "Other Feed")
293 assert.NilError(t, err)293 assert.NilError(t, err)
294 294
295- _, err = dbs.DB().ExecContext(ctx, `295+ _, err = dbs.SQLDB().ExecContext(ctx, `
296 INSERT INTO articles.articles (feed_url, guid, title) VALUES (?, ?, ?)296 INSERT INTO articles.articles (feed_url, guid, title) VALUES (?, ?, ?)
297 `, otherFeed, "other-1", "Go Concurrency Tips")297 `, otherFeed, "other-1", "Go Concurrency Tips")
298 assert.NilError(t, err)298 assert.NilError(t, err)
modified internal/db/batch_test.go +2 -2
@@ -47,10 +47,10 @@ func TestBatchCreateUsers_Empty(t *testing.T) {
4747 assert.NilError(t, err)
4848 }
4949
50-func seedSubscriptionData(t *testing.T, ctx context.Context, dbs *Databases) (userDID string) {
50+func seedSubscriptionData(t *testing.T, ctx context.Context, dbs *Store) (userDID string) {
5151 t.Helper()
5252 userDID = "did:test:subuser"
53- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
53+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
5454 assert.NilError(t, err)
5555 return userDID
5656 }
@@ -47,10 +47,10 @@ func TestBatchCreateUsers_Empty(t *testing.T) {
47 assert.NilError(t, err)47 assert.NilError(t, err)
48 }48 }
49 49
50-func seedSubscriptionData(t *testing.T, ctx context.Context, dbs *Databases) (userDID string) {50+func seedSubscriptionData(t *testing.T, ctx context.Context, dbs *Store) (userDID string) {
51 t.Helper()51 t.Helper()
52 userDID = "did:test:subuser"52 userDID = "did:test:subuser"
53- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)53+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
54 assert.NilError(t, err)54 assert.NilError(t, err)
55 return userDID55 return userDID
56 }56 }
modified internal/db/db.go +10 -10
@@ -16,7 +16,7 @@ type DB struct {
1616 *sql.DB
1717 }
1818
19-type Databases struct {
19+type Store struct {
2020 Users *UserStore
2121 Articles *ArticleStore
2222
@@ -25,7 +25,7 @@ type Databases struct {
2525
2626 var multiDriverSeq int64
2727
28-func OpenAll(basePath string) (*Databases, error) {
28+func Open(basePath string) (*Store, error) {
2929 articlesPath := basePath + "_articles"
3030 recsPath := basePath + "_recs"
3131
@@ -113,21 +113,21 @@ func OpenAll(basePath string) (*Databases, error) {
113113 return nil, err
114114 }
115115
116- return &Databases{
116+ return &Store{
117117 Users: NewUserStore(d),
118118 Articles: NewArticleStore(d),
119119 db: d,
120120 }, nil
121121 }
122122
123-func (d *Databases) Close() error {
124- if d.db != nil {
125- _ = d.db.Close()
123+func (s *Store) Close() error {
124+ if s.db != nil {
125+ _ = s.db.Close()
126126 }
127127 return nil
128128 }
129129
130-func (d *Databases) InitVecTables(dimension int) error {
130+func (s *Store) InitVecTables(dimension int) error {
131131 if dimension <= 0 {
132132 return nil
133133 }
@@ -135,15 +135,15 @@ func (d *Databases) InitVecTables(dimension int) error {
135135 fmt.Sprintf(`CREATE VIRTUAL TABLE IF NOT EXISTS recs.feed_embeddings USING vec0(feed_url TEXT PRIMARY KEY, embedding float[%d])`, dimension),
136136 fmt.Sprintf(`CREATE VIRTUAL TABLE IF NOT EXISTS recs.article_embeddings USING vec0(article_id INTEGER PRIMARY KEY, embedding float[%d])`, dimension),
137137 } {
138- if _, err := d.db.ExecContext(context.Background(), stmt); err != nil {
138+ if _, err := s.db.ExecContext(context.Background(), stmt); err != nil {
139139 return fmt.Errorf("create vec0 table: %w", err)
140140 }
141141 }
142142 return nil
143143 }
144144
145-func (d *Databases) DB() *sql.DB {
146- return d.db.DB
145+func (s *Store) SQLDB() *sql.DB {
146+ return s.db.DB
147147 }
148148
149149 func initUsersSchema(db *DB) error {
@@ -16,7 +16,7 @@ type DB struct {
16 *sql.DB16 *sql.DB
17 }17 }
18 18
19-type Databases struct {19+type Store struct {
20 Users *UserStore20 Users *UserStore
21 Articles *ArticleStore21 Articles *ArticleStore
22 22
@@ -25,7 +25,7 @@ type Databases struct {
25 25
26 var multiDriverSeq int6426 var multiDriverSeq int64
27 27
28-func OpenAll(basePath string) (*Databases, error) {28+func Open(basePath string) (*Store, error) {
29 articlesPath := basePath + "_articles"29 articlesPath := basePath + "_articles"
30 recsPath := basePath + "_recs"30 recsPath := basePath + "_recs"
31 31
@@ -113,21 +113,21 @@ func OpenAll(basePath string) (*Databases, error) {
113 return nil, err113 return nil, err
114 }114 }
115 115
116- return &Databases{116+ return &Store{
117 Users: NewUserStore(d),117 Users: NewUserStore(d),
118 Articles: NewArticleStore(d),118 Articles: NewArticleStore(d),
119 db: d,119 db: d,
120 }, nil120 }, nil
121 }121 }
122 122
123-func (d *Databases) Close() error {123+func (s *Store) Close() error {
124- if d.db != nil {124+ if s.db != nil {
125- _ = d.db.Close()125+ _ = s.db.Close()
126 }126 }
127 return nil127 return nil
128 }128 }
129 129
130-func (d *Databases) InitVecTables(dimension int) error {130+func (s *Store) InitVecTables(dimension int) error {
131 if dimension <= 0 {131 if dimension <= 0 {
132 return nil132 return nil
133 }133 }
@@ -135,15 +135,15 @@ func (d *Databases) InitVecTables(dimension int) error {
135 fmt.Sprintf(`CREATE VIRTUAL TABLE IF NOT EXISTS recs.feed_embeddings USING vec0(feed_url TEXT PRIMARY KEY, embedding float[%d])`, dimension),135 fmt.Sprintf(`CREATE VIRTUAL TABLE IF NOT EXISTS recs.feed_embeddings USING vec0(feed_url TEXT PRIMARY KEY, embedding float[%d])`, dimension),
136 fmt.Sprintf(`CREATE VIRTUAL TABLE IF NOT EXISTS recs.article_embeddings USING vec0(article_id INTEGER PRIMARY KEY, embedding float[%d])`, dimension),136 fmt.Sprintf(`CREATE VIRTUAL TABLE IF NOT EXISTS recs.article_embeddings USING vec0(article_id INTEGER PRIMARY KEY, embedding float[%d])`, dimension),
137 } {137 } {
138- if _, err := d.db.ExecContext(context.Background(), stmt); err != nil {138+ if _, err := s.db.ExecContext(context.Background(), stmt); err != nil {
139 return fmt.Errorf("create vec0 table: %w", err)139 return fmt.Errorf("create vec0 table: %w", err)
140 }140 }
141 }141 }
142 return nil142 return nil
143 }143 }
144 144
145-func (d *Databases) DB() *sql.DB {145+func (s *Store) SQLDB() *sql.DB {
146- return d.db.DB146+ return s.db.DB
147 }147 }
148 148
149 func initUsersSchema(db *DB) error {149 func initUsersSchema(db *DB) error {
modified internal/db/follow.go +1 -1
@@ -106,7 +106,7 @@ func (s *UserStore) IsFollowing(ctx context.Context, userDID, targetDID string)
106106 return true, nil
107107 }
108108
109-func (s *UserStore) GetFollowDIDs(ctx context.Context, userDID string) ([]string, error) {
109+func (s *UserStore) FollowDIDs(ctx context.Context, userDID string) ([]string, error) {
110110 rows, err := s.db.QueryContext(ctx, `
111111 SELECT target_did FROM follows WHERE user_did = ?
112112 `, userDID)
@@ -106,7 +106,7 @@ func (s *UserStore) IsFollowing(ctx context.Context, userDID, targetDID string)
106 return true, nil106 return true, nil
107 }107 }
108 108
109-func (s *UserStore) GetFollowDIDs(ctx context.Context, userDID string) ([]string, error) {109+func (s *UserStore) FollowDIDs(ctx context.Context, userDID string) ([]string, error) {
110 rows, err := s.db.QueryContext(ctx, `110 rows, err := s.db.QueryContext(ctx, `
111 SELECT target_did FROM follows WHERE user_did = ?111 SELECT target_did FROM follows WHERE user_did = ?
112 `, userDID)112 `, userDID)
modified internal/db/follow_test.go +9 -9
@@ -7,15 +7,15 @@ import (
77 "gotest.tools/v3/assert"
88 )
99
10-func seedFollowData(t *testing.T, ctx context.Context, dbs *Databases) (userDID, targetDID string) {
10+func seedFollowData(t *testing.T, ctx context.Context, dbs *Store) (userDID, targetDID string) {
1111 t.Helper()
1212
1313 userDID = "did:test:follower"
1414 targetDID = "did:test:followed"
1515
16- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
16+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
1717 assert.NilError(t, err)
18- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, targetDID)
18+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, targetDID)
1919 assert.NilError(t, err)
2020
2121 return userDID, targetDID
@@ -83,7 +83,7 @@ func TestListFollows(t *testing.T) {
8383 userDID, _ := seedFollowData(t, ctx, dbs)
8484
8585 target2 := "did:test:followed2"
86- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, target2)
86+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, target2)
8787 assert.NilError(t, err)
8888
8989 err = dbs.Users.UpsertFollow(ctx, userDID, "did:test:followed", "uri1", "cid1")
@@ -102,7 +102,7 @@ func TestListFollowers(t *testing.T) {
102102 _, targetDID := seedFollowData(t, ctx, dbs)
103103
104104 follower2 := "did:test:follower2"
105- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, follower2)
105+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, follower2)
106106 assert.NilError(t, err)
107107
108108 err = dbs.Users.UpsertFollow(ctx, "did:test:follower", targetDID, "uri1", "cid1")
@@ -115,13 +115,13 @@ func TestListFollowers(t *testing.T) {
115115 assert.Equal(t, len(followers), 2)
116116 }
117117
118-func TestGetFollowDIDs(t *testing.T) {
118+func TestFollowDIDs(t *testing.T) {
119119 ctx := context.Background()
120120 dbs := setupTestDB(t)
121121 userDID, _ := seedFollowData(t, ctx, dbs)
122122
123123 target2 := "did:test:followed2"
124- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, target2)
124+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, target2)
125125 assert.NilError(t, err)
126126
127127 err = dbs.Users.UpsertFollow(ctx, userDID, "did:test:followed", "uri1", "cid1")
@@ -129,7 +129,7 @@ func TestGetFollowDIDs(t *testing.T) {
129129 err = dbs.Users.UpsertFollow(ctx, userDID, target2, "uri2", "cid2")
130130 assert.NilError(t, err)
131131
132- dids, err := dbs.Users.GetFollowDIDs(ctx, userDID)
132+ dids, err := dbs.Users.FollowDIDs(ctx, userDID)
133133 assert.NilError(t, err)
134134 assert.Equal(t, len(dids), 2)
135135 }
@@ -162,7 +162,7 @@ func TestSyncFollows_AddsNewRemovesStale(t *testing.T) {
162162 assert.NilError(t, err)
163163 assert.Equal(t, following2, true)
164164
165- dids, err := dbs.Users.GetFollowDIDs(ctx, userDID)
165+ dids, err := dbs.Users.FollowDIDs(ctx, userDID)
166166 assert.NilError(t, err)
167167 assert.Equal(t, len(dids), 2)
168168 }
@@ -7,15 +7,15 @@ import (
7 "gotest.tools/v3/assert"7 "gotest.tools/v3/assert"
8 )8 )
9 9
10-func seedFollowData(t *testing.T, ctx context.Context, dbs *Databases) (userDID, targetDID string) {10+func seedFollowData(t *testing.T, ctx context.Context, dbs *Store) (userDID, targetDID string) {
11 t.Helper()11 t.Helper()
12 12
13 userDID = "did:test:follower"13 userDID = "did:test:follower"
14 targetDID = "did:test:followed"14 targetDID = "did:test:followed"
15 15
16- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)16+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, userDID)
17 assert.NilError(t, err)17 assert.NilError(t, err)
18- _, err = dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, targetDID)18+ _, err = dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, targetDID)
19 assert.NilError(t, err)19 assert.NilError(t, err)
20 20
21 return userDID, targetDID21 return userDID, targetDID
@@ -83,7 +83,7 @@ func TestListFollows(t *testing.T) {
83 userDID, _ := seedFollowData(t, ctx, dbs)83 userDID, _ := seedFollowData(t, ctx, dbs)
84 84
85 target2 := "did:test:followed2"85 target2 := "did:test:followed2"
86- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, target2)86+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, target2)
87 assert.NilError(t, err)87 assert.NilError(t, err)
88 88
89 err = dbs.Users.UpsertFollow(ctx, userDID, "did:test:followed", "uri1", "cid1")89 err = dbs.Users.UpsertFollow(ctx, userDID, "did:test:followed", "uri1", "cid1")
@@ -102,7 +102,7 @@ func TestListFollowers(t *testing.T) {
102 _, targetDID := seedFollowData(t, ctx, dbs)102 _, targetDID := seedFollowData(t, ctx, dbs)
103 103
104 follower2 := "did:test:follower2"104 follower2 := "did:test:follower2"
105- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, follower2)105+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, follower2)
106 assert.NilError(t, err)106 assert.NilError(t, err)
107 107
108 err = dbs.Users.UpsertFollow(ctx, "did:test:follower", targetDID, "uri1", "cid1")108 err = dbs.Users.UpsertFollow(ctx, "did:test:follower", targetDID, "uri1", "cid1")
@@ -115,13 +115,13 @@ func TestListFollowers(t *testing.T) {
115 assert.Equal(t, len(followers), 2)115 assert.Equal(t, len(followers), 2)
116 }116 }
117 117
118-func TestGetFollowDIDs(t *testing.T) {118+func TestFollowDIDs(t *testing.T) {
119 ctx := context.Background()119 ctx := context.Background()
120 dbs := setupTestDB(t)120 dbs := setupTestDB(t)
121 userDID, _ := seedFollowData(t, ctx, dbs)121 userDID, _ := seedFollowData(t, ctx, dbs)
122 122
123 target2 := "did:test:followed2"123 target2 := "did:test:followed2"
124- _, err := dbs.DB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, target2)124+ _, err := dbs.SQLDB().ExecContext(ctx, `INSERT INTO users (did) VALUES (?)`, target2)
125 assert.NilError(t, err)125 assert.NilError(t, err)
126 126
127 err = dbs.Users.UpsertFollow(ctx, userDID, "did:test:followed", "uri1", "cid1")127 err = dbs.Users.UpsertFollow(ctx, userDID, "did:test:followed", "uri1", "cid1")
@@ -129,7 +129,7 @@ func TestGetFollowDIDs(t *testing.T) {
129 err = dbs.Users.UpsertFollow(ctx, userDID, target2, "uri2", "cid2")129 err = dbs.Users.UpsertFollow(ctx, userDID, target2, "uri2", "cid2")
130 assert.NilError(t, err)130 assert.NilError(t, err)
131 131
132- dids, err := dbs.Users.GetFollowDIDs(ctx, userDID)132+ dids, err := dbs.Users.FollowDIDs(ctx, userDID)
133 assert.NilError(t, err)133 assert.NilError(t, err)
134 assert.Equal(t, len(dids), 2)134 assert.Equal(t, len(dids), 2)
135 }135 }
@@ -162,7 +162,7 @@ func TestSyncFollows_AddsNewRemovesStale(t *testing.T) {
162 assert.NilError(t, err)162 assert.NilError(t, err)
163 assert.Equal(t, following2, true)163 assert.Equal(t, following2, true)
164 164
165- dids, err := dbs.Users.GetFollowDIDs(ctx, userDID)165+ dids, err := dbs.Users.FollowDIDs(ctx, userDID)
166 assert.NilError(t, err)166 assert.NilError(t, err)
167 assert.Equal(t, len(dids), 2)167 assert.Equal(t, len(dids), 2)
168 }168 }
modified internal/db/oauth_store.go +1 -1
@@ -14,7 +14,7 @@ type OAuthStore struct {
1414 db *DB
1515 }
1616
17-func NewOAuthStore(dbs *Databases) *OAuthStore {
17+func NewOAuthStore(dbs *Store) *OAuthStore {
1818 return &OAuthStore{db: dbs.db}
1919 }
2020
@@ -14,7 +14,7 @@ type OAuthStore struct {
14 db *DB14 db *DB
15 }15 }
16 16
17-func NewOAuthStore(dbs *Databases) *OAuthStore {17+func NewOAuthStore(dbs *Store) *OAuthStore {
18 return &OAuthStore{db: dbs.db}18 return &OAuthStore{db: dbs.db}
19 }19 }
20 20
modified internal/db/store.go +7 -7
@@ -8,15 +8,15 @@ import (
88 "pkg.rbrt.fr/glean/internal/feed"
99 )
1010
11-type FeedStoreAdapter struct {
11+type FeedAdapter struct {
1212 store *ArticleStore
1313 }
1414
15-func NewFeedStoreAdapter(store *ArticleStore) *FeedStoreAdapter {
16- return &FeedStoreAdapter{store: store}
15+func NewFeedAdapter(store *ArticleStore) *FeedAdapter {
16+ return &FeedAdapter{store: store}
1717 }
1818
19-func (a *FeedStoreAdapter) GetFeedsToFetch(ctx context.Context, olderThan time.Duration, limit int) ([]*feed.Feed, error) {
19+func (a *FeedAdapter) GetFeedsToFetch(ctx context.Context, olderThan time.Duration, limit int) ([]*feed.Feed, error) {
2020 dbFeeds, err := a.store.GetFeedsToFetch(ctx, olderThan, limit)
2121 if err != nil {
2222 return nil, err
@@ -28,13 +28,13 @@ func (a *FeedStoreAdapter) GetFeedsToFetch(ctx context.Context, olderThan time.D
2828 return feeds, nil
2929 }
3030
31-func (a *FeedStoreAdapter) RecordFetchError(ctx context.Context, feedURL, lastError string) error {
31+func (a *FeedAdapter) RecordFetchError(ctx context.Context, feedURL, lastError string) error {
3232 return a.store.MarkFeedFetchError(ctx, feedURL, lastError)
3333 }
3434
35-func (a *FeedStoreAdapter) StoreFetchResult(ctx context.Context, feedURL string, articles []feed.Article, faviconURL string) error {
35+func (a *FeedAdapter) StoreFetchResult(ctx context.Context, feedURL string, articles []feed.Article, faviconURL string) error {
3636 if len(articles) > 0 {
37- if err := a.store.UpsertArticlesBatch(ctx, articles); err != nil {
37+ if err := a.store.BatchUpsertArticles(ctx, articles); err != nil {
3838 return fmt.Errorf("failed to save articles: %w", err)
3939 }
4040 }
@@ -8,15 +8,15 @@ import (
8 "pkg.rbrt.fr/glean/internal/feed"8 "pkg.rbrt.fr/glean/internal/feed"
9 )9 )
10 10
11-type FeedStoreAdapter struct {11+type FeedAdapter struct {
12 store *ArticleStore12 store *ArticleStore
13 }13 }
14 14
15-func NewFeedStoreAdapter(store *ArticleStore) *FeedStoreAdapter {15+func NewFeedAdapter(store *ArticleStore) *FeedAdapter {
16- return &FeedStoreAdapter{store: store}16+ return &FeedAdapter{store: store}
17 }17 }
18 18
19-func (a *FeedStoreAdapter) GetFeedsToFetch(ctx context.Context, olderThan time.Duration, limit int) ([]*feed.Feed, error) {19+func (a *FeedAdapter) GetFeedsToFetch(ctx context.Context, olderThan time.Duration, limit int) ([]*feed.Feed, error) {
20 dbFeeds, err := a.store.GetFeedsToFetch(ctx, olderThan, limit)20 dbFeeds, err := a.store.GetFeedsToFetch(ctx, olderThan, limit)
21 if err != nil {21 if err != nil {
22 return nil, err22 return nil, err
@@ -28,13 +28,13 @@ func (a *FeedStoreAdapter) GetFeedsToFetch(ctx context.Context, olderThan time.D
28 return feeds, nil28 return feeds, nil
29 }29 }
30 30
31-func (a *FeedStoreAdapter) RecordFetchError(ctx context.Context, feedURL, lastError string) error {31+func (a *FeedAdapter) RecordFetchError(ctx context.Context, feedURL, lastError string) error {
32 return a.store.MarkFeedFetchError(ctx, feedURL, lastError)32 return a.store.MarkFeedFetchError(ctx, feedURL, lastError)
33 }33 }
34 34
35-func (a *FeedStoreAdapter) StoreFetchResult(ctx context.Context, feedURL string, articles []feed.Article, faviconURL string) error {35+func (a *FeedAdapter) StoreFetchResult(ctx context.Context, feedURL string, articles []feed.Article, faviconURL string) error {
36 if len(articles) > 0 {36 if len(articles) > 0 {
37- if err := a.store.UpsertArticlesBatch(ctx, articles); err != nil {37+ if err := a.store.BatchUpsertArticles(ctx, articles); err != nil {
38 return fmt.Errorf("failed to save articles: %w", err)38 return fmt.Errorf("failed to save articles: %w", err)
39 }39 }
40 }40 }
modified internal/db/user.go +1 -1
@@ -69,7 +69,7 @@ func (s *UserStore) GetUser(ctx context.Context, did string) (*User, error) {
6969 return u, nil
7070 }
7171
72-func (s *UserStore) ListUserDIDs(ctx context.Context) (map[string]bool, error) {
72+func (s *UserStore) UserDIDs(ctx context.Context) (map[string]bool, error) {
7373 rows, err := s.db.QueryContext(ctx, `SELECT did FROM users`)
7474 if err != nil {
7575 return nil, err
@@ -69,7 +69,7 @@ func (s *UserStore) GetUser(ctx context.Context, did string) (*User, error) {
69 return u, nil69 return u, nil
70 }70 }
71 71
72-func (s *UserStore) ListUserDIDs(ctx context.Context) (map[string]bool, error) {72+func (s *UserStore) UserDIDs(ctx context.Context) (map[string]bool, error) {
73 rows, err := s.db.QueryContext(ctx, `SELECT did FROM users`)73 rows, err := s.db.QueryContext(ctx, `SELECT did FROM users`)
74 if err != nil {74 if err != nil {
75 return nil, err75 return nil, err
modified internal/server/server.go +4 -4
@@ -58,7 +58,7 @@ func splitString(s, sep string) []string {
5858 }
5959
6060 type Server struct {
61- dbs *db.Databases
61+ dbs *db.Store
6262 router *chi.Mux
6363 templates *template.Template
6464 logger *slog.Logger
@@ -73,7 +73,7 @@ type Server struct {
7373 sessionKey []byte
7474 }
7575
76-func New(dbs *db.Databases, clientID, callbackURL, addr string, scheduler *feed.Scheduler, engine *cluster.Engine, logger *slog.Logger, sessionKey []byte) *Server {
76+func New(dbs *db.Store, clientID, callbackURL, addr string, scheduler *feed.Scheduler, engine *cluster.Engine, logger *slog.Logger, sessionKey []byte) *Server {
7777 oauthStore := db.NewOAuthStore(dbs)
7878
7979 var config oauth.ClientConfig
@@ -204,7 +204,7 @@ func (s *Server) setupRoutes() {
204204 s.router.Post("/auth/logout", s.handleAuthLogout)
205205 s.router.Get("/oauth/client-metadata", s.handleOAuthClientMetadata)
206206
207- xrpc := atproto.NewXRPCHandler(s.dbs.DB(), s.engine)
207+ xrpc := atproto.NewXRPCHandler(s.dbs.SQLDB(), s.engine)
208208 s.router.Get("/xrpc/at.glean.listSubscriptions", xrpc.ListSubscriptions)
209209 s.router.Get("/xrpc/at.glean.listAnnotations", xrpc.ListAnnotations)
210210 s.router.Get("/xrpc/at.glean.listLikes", xrpc.ListLikes)
@@ -416,7 +416,7 @@ func (s *Server) BackfillFromCollectionDir(ctx context.Context, collectionDirURL
416416 return
417417 }
418418
419- existing, err := s.dbs.Users.ListUserDIDs(ctx)
419+ existing, err := s.dbs.Users.UserDIDs(ctx)
420420 if err != nil {
421421 s.logger.Error("failed to list existing users", "error", err)
422422 return
@@ -58,7 +58,7 @@ func splitString(s, sep string) []string {
58 }58 }
59 59
60 type Server struct {60 type Server struct {
61- dbs *db.Databases61+ dbs *db.Store
62 router *chi.Mux62 router *chi.Mux
63 templates *template.Template63 templates *template.Template
64 logger *slog.Logger64 logger *slog.Logger
@@ -73,7 +73,7 @@ type Server struct {
73 sessionKey []byte73 sessionKey []byte
74 }74 }
75 75
76-func New(dbs *db.Databases, clientID, callbackURL, addr string, scheduler *feed.Scheduler, engine *cluster.Engine, logger *slog.Logger, sessionKey []byte) *Server {76+func New(dbs *db.Store, clientID, callbackURL, addr string, scheduler *feed.Scheduler, engine *cluster.Engine, logger *slog.Logger, sessionKey []byte) *Server {
77 oauthStore := db.NewOAuthStore(dbs)77 oauthStore := db.NewOAuthStore(dbs)
78 78
79 var config oauth.ClientConfig79 var config oauth.ClientConfig
@@ -204,7 +204,7 @@ func (s *Server) setupRoutes() {
204 s.router.Post("/auth/logout", s.handleAuthLogout)204 s.router.Post("/auth/logout", s.handleAuthLogout)
205 s.router.Get("/oauth/client-metadata", s.handleOAuthClientMetadata)205 s.router.Get("/oauth/client-metadata", s.handleOAuthClientMetadata)
206 206
207- xrpc := atproto.NewXRPCHandler(s.dbs.DB(), s.engine)207+ xrpc := atproto.NewXRPCHandler(s.dbs.SQLDB(), s.engine)
208 s.router.Get("/xrpc/at.glean.listSubscriptions", xrpc.ListSubscriptions)208 s.router.Get("/xrpc/at.glean.listSubscriptions", xrpc.ListSubscriptions)
209 s.router.Get("/xrpc/at.glean.listAnnotations", xrpc.ListAnnotations)209 s.router.Get("/xrpc/at.glean.listAnnotations", xrpc.ListAnnotations)
210 s.router.Get("/xrpc/at.glean.listLikes", xrpc.ListLikes)210 s.router.Get("/xrpc/at.glean.listLikes", xrpc.ListLikes)
@@ -416,7 +416,7 @@ func (s *Server) BackfillFromCollectionDir(ctx context.Context, collectionDirURL
416 return416 return
417 }417 }
418 418
419- existing, err := s.dbs.Users.ListUserDIDs(ctx)419+ existing, err := s.dbs.Users.UserDIDs(ctx)
420 if err != nil {420 if err != nil {
421 s.logger.Error("failed to list existing users", "error", err)421 s.logger.Error("failed to list existing users", "error", err)
422 return422 return
modified main.go +3 -3
@@ -43,7 +43,7 @@ func main() {
4343 logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
4444
4545 vec.Auto()
46- dbs, err := db.OpenAll(*dbPath)
46+ dbs, err := db.Open(*dbPath)
4747 if err != nil {
4848 logger.Error("failed to open databases", "error", err)
4949 os.Exit(1)
@@ -53,7 +53,7 @@ func main() {
5353 clientID := envOr("GLEAN_OAUTH_CLIENT_ID", "")
5454 callbackURL := envOr("GLEAN_OAUTH_REDIRECT_URL", "")
5555
56- storeAdapter := db.NewFeedStoreAdapter(dbs.Articles)
56+ storeAdapter := db.NewFeedAdapter(dbs.Articles)
5757 scheduler := feed.NewScheduler(storeAdapter, logger, *fetchInterval, 30*time.Minute)
5858
5959 var embedder cluster.Embedder
@@ -73,7 +73,7 @@ func main() {
7373 }
7474 }
7575
76- engine := cluster.NewEngine(dbs.DB(), embedder, logger)
76+ engine := cluster.NewEngine(dbs.SQLDB(), embedder, logger)
7777
7878 srv := server.New(dbs, clientID, callbackURL, *addr, scheduler, engine, logger, []byte(sessionKey))
7979
@@ -43,7 +43,7 @@ func main() {
43 logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))43 logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
44 44
45 vec.Auto()45 vec.Auto()
46- dbs, err := db.OpenAll(*dbPath)46+ dbs, err := db.Open(*dbPath)
47 if err != nil {47 if err != nil {
48 logger.Error("failed to open databases", "error", err)48 logger.Error("failed to open databases", "error", err)
49 os.Exit(1)49 os.Exit(1)
@@ -53,7 +53,7 @@ func main() {
53 clientID := envOr("GLEAN_OAUTH_CLIENT_ID", "")53 clientID := envOr("GLEAN_OAUTH_CLIENT_ID", "")
54 callbackURL := envOr("GLEAN_OAUTH_REDIRECT_URL", "")54 callbackURL := envOr("GLEAN_OAUTH_REDIRECT_URL", "")
55 55
56- storeAdapter := db.NewFeedStoreAdapter(dbs.Articles)56+ storeAdapter := db.NewFeedAdapter(dbs.Articles)
57 scheduler := feed.NewScheduler(storeAdapter, logger, *fetchInterval, 30*time.Minute)57 scheduler := feed.NewScheduler(storeAdapter, logger, *fetchInterval, 30*time.Minute)
58 58
59 var embedder cluster.Embedder59 var embedder cluster.Embedder
@@ -73,7 +73,7 @@ func main() {
73 }73 }
74 }74 }
75 75
76- engine := cluster.NewEngine(dbs.DB(), embedder, logger)76+ engine := cluster.NewEngine(dbs.SQLDB(), embedder, logger)
77 77
78 srv := server.New(dbs, clientID, callbackURL, *addr, scheduler, engine, logger, []byte(sessionKey))78 srv := server.New(dbs, clientID, callbackURL, *addr, scheduler, engine, logger, []byte(sessionKey))
79 79