[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/store/RFC.md fully. Find ONE featur... #107
11 changed files with 98 additions and 98 deletions
|
|
@ -32,7 +32,7 @@ func (storeInstance *Store) Compact(options CompactOptions) core.Result {
|
|||
if err := storeInstance.ensureReady("store.Compact"); err != nil {
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
if err := ensureJournalSchema(storeInstance.database); err != nil {
|
||||
if err := ensureJournalSchema(storeInstance.sqliteDatabase); err != nil {
|
||||
return core.Result{Value: core.E("store.Compact", "ensure journal schema", err), OK: false}
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ func (storeInstance *Store) Compact(options CompactOptions) core.Result {
|
|||
return core.Result{Value: core.E("store.Compact", "ensure archive directory", result.Value.(error)), OK: false}
|
||||
}
|
||||
|
||||
rows, err := storeInstance.database.Query(
|
||||
rows, err := storeInstance.sqliteDatabase.Query(
|
||||
"SELECT entry_id, bucket_name, measurement, fields_json, tags_json, committed_at FROM "+journalEntriesTableName+" WHERE archived_at IS NULL AND committed_at < ? ORDER BY committed_at",
|
||||
options.Before.UnixMilli(),
|
||||
)
|
||||
|
|
@ -134,7 +134,7 @@ func (storeInstance *Store) Compact(options CompactOptions) core.Result {
|
|||
}
|
||||
fileClosed = true
|
||||
|
||||
transaction, err := storeInstance.database.Begin()
|
||||
transaction, err := storeInstance.sqliteDatabase.Begin()
|
||||
if err != nil {
|
||||
return core.Result{Value: core.E("store.Compact", "begin archive transaction", err), OK: false}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ func TestCompact_Compact_Good_GzipArchive(t *testing.T) {
|
|||
storeInstance.CommitToJournal("session-b", map[string]any{"like": 2}, map[string]string{"workspace": "session-b"}).OK,
|
||||
)
|
||||
|
||||
_, err = storeInstance.database.Exec(
|
||||
_, err = storeInstance.sqliteDatabase.Exec(
|
||||
"UPDATE "+journalEntriesTableName+" SET committed_at = ? WHERE measurement = ?",
|
||||
time.Now().Add(-48*time.Hour).UnixMilli(),
|
||||
"session-a",
|
||||
|
|
@ -76,7 +76,7 @@ func TestCompact_Compact_Good_ZstdArchive(t *testing.T) {
|
|||
storeInstance.CommitToJournal("session-a", map[string]any{"like": 1}, map[string]string{"workspace": "session-a"}).OK,
|
||||
)
|
||||
|
||||
_, err = storeInstance.database.Exec(
|
||||
_, err = storeInstance.sqliteDatabase.Exec(
|
||||
"UPDATE "+journalEntriesTableName+" SET committed_at = ? WHERE measurement = ?",
|
||||
time.Now().Add(-48*time.Hour).UnixMilli(),
|
||||
"session-a",
|
||||
|
|
|
|||
|
|
@ -54,20 +54,20 @@ func TestCoverage_GetAll_Bad_ScanError(t *testing.T) {
|
|||
require.NoError(t, storeInstance.Set("g", "good", "value"))
|
||||
|
||||
// Restructure the table to allow NULLs, then insert a NULL-key row.
|
||||
_, err = storeInstance.database.Exec("ALTER TABLE entries RENAME TO entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("ALTER TABLE entries RENAME TO entries_backup")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec(`CREATE TABLE entries (
|
||||
_, err = storeInstance.sqliteDatabase.Exec(`CREATE TABLE entries (
|
||||
group_name TEXT,
|
||||
entry_key TEXT,
|
||||
entry_value TEXT,
|
||||
expires_at INTEGER
|
||||
)`)
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("INSERT INTO entries SELECT * FROM entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("INSERT INTO entries SELECT * FROM entries_backup")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("INSERT INTO entries (group_name, entry_key, entry_value) VALUES ('g', NULL, 'null-key-val')")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("INSERT INTO entries (group_name, entry_key, entry_value) VALUES ('g', NULL, 'null-key-val')")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("DROP TABLE entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("DROP TABLE entries_backup")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = storeInstance.GetAll("g")
|
||||
|
|
@ -146,20 +146,20 @@ func TestCoverage_Render_Bad_ScanError(t *testing.T) {
|
|||
|
||||
require.NoError(t, storeInstance.Set("g", "good", "value"))
|
||||
|
||||
_, err = storeInstance.database.Exec("ALTER TABLE entries RENAME TO entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("ALTER TABLE entries RENAME TO entries_backup")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec(`CREATE TABLE entries (
|
||||
_, err = storeInstance.sqliteDatabase.Exec(`CREATE TABLE entries (
|
||||
group_name TEXT,
|
||||
entry_key TEXT,
|
||||
entry_value TEXT,
|
||||
expires_at INTEGER
|
||||
)`)
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("INSERT INTO entries SELECT * FROM entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("INSERT INTO entries SELECT * FROM entries_backup")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("INSERT INTO entries (group_name, entry_key, entry_value) VALUES ('g', NULL, 'null-key-val')")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("INSERT INTO entries (group_name, entry_key, entry_value) VALUES ('g', NULL, 'null-key-val')")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("DROP TABLE entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("DROP TABLE entries_backup")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = storeInstance.Render("{{ .good }}", "g")
|
||||
|
|
@ -231,20 +231,20 @@ func TestCoverage_GroupsSeq_Bad_ScanError(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
defer storeInstance.Close()
|
||||
|
||||
_, err = storeInstance.database.Exec("ALTER TABLE entries RENAME TO entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("ALTER TABLE entries RENAME TO entries_backup")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec(`CREATE TABLE entries (
|
||||
_, err = storeInstance.sqliteDatabase.Exec(`CREATE TABLE entries (
|
||||
group_name TEXT,
|
||||
entry_key TEXT,
|
||||
entry_value TEXT,
|
||||
expires_at INTEGER
|
||||
)`)
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("INSERT INTO entries SELECT * FROM entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("INSERT INTO entries SELECT * FROM entries_backup")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("INSERT INTO entries (group_name, entry_key, entry_value) VALUES (NULL, 'k', 'v')")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("INSERT INTO entries (group_name, entry_key, entry_value) VALUES (NULL, 'k', 'v')")
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec("DROP TABLE entries_backup")
|
||||
_, err = storeInstance.sqliteDatabase.Exec("DROP TABLE entries_backup")
|
||||
require.NoError(t, err)
|
||||
|
||||
for groupName, iterationErr := range storeInstance.GroupsSeq("") {
|
||||
|
|
@ -265,8 +265,8 @@ func TestCoverage_GroupsSeq_Bad_RowsError(t *testing.T) {
|
|||
defer database.Close()
|
||||
|
||||
storeInstance := &Store{
|
||||
database: database,
|
||||
cancelPurge: func() {},
|
||||
sqliteDatabase: database,
|
||||
cancelPurge: func() {},
|
||||
}
|
||||
|
||||
for groupName, iterationErr := range storeInstance.GroupsSeq("") {
|
||||
|
|
@ -305,8 +305,8 @@ func TestCoverage_ScopedStore_Bad_GroupsSeqRowsError(t *testing.T) {
|
|||
|
||||
scopedStore := &ScopedStore{
|
||||
backingStore: &Store{
|
||||
database: database,
|
||||
cancelPurge: func() {},
|
||||
sqliteDatabase: database,
|
||||
cancelPurge: func() {},
|
||||
},
|
||||
namespace: "tenant-a",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ func (storeInstance *Store) CommitToJournal(measurement string, fields map[strin
|
|||
if tags == nil {
|
||||
tags = map[string]string{}
|
||||
}
|
||||
if err := ensureJournalSchema(storeInstance.database); err != nil {
|
||||
if err := ensureJournalSchema(storeInstance.sqliteDatabase); err != nil {
|
||||
return core.Result{Value: core.E("store.CommitToJournal", "ensure journal schema", err), OK: false}
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ func (storeInstance *Store) CommitToJournal(measurement string, fields map[strin
|
|||
|
||||
committedAt := time.Now().UnixMilli()
|
||||
if err := insertJournalEntry(
|
||||
storeInstance.database,
|
||||
storeInstance.sqliteDatabase,
|
||||
storeInstance.journalBucket(),
|
||||
measurement,
|
||||
fieldsJSON,
|
||||
|
|
@ -102,7 +102,7 @@ func (storeInstance *Store) QueryJournal(flux string) core.Result {
|
|||
if err := storeInstance.ensureReady("store.QueryJournal"); err != nil {
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
if err := ensureJournalSchema(storeInstance.database); err != nil {
|
||||
if err := ensureJournalSchema(storeInstance.sqliteDatabase); err != nil {
|
||||
return core.Result{Value: core.E("store.QueryJournal", "ensure journal schema", err), OK: false}
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ func isRawSQLJournalQuery(query string) bool {
|
|||
}
|
||||
|
||||
func (storeInstance *Store) queryJournalRows(query string, arguments ...any) core.Result {
|
||||
rows, err := storeInstance.database.Query(query, arguments...)
|
||||
rows, err := storeInstance.sqliteDatabase.Query(query, arguments...)
|
||||
if err != nil {
|
||||
return core.Result{Value: core.E("store.QueryJournal", "query rows", err), OK: false}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ func TestJournal_QueryJournal_Good_BucketFilter(t *testing.T) {
|
|||
storeInstance.CommitToJournal("session-a", map[string]any{"like": 1}, map[string]string{"workspace": "session-a"}).OK,
|
||||
)
|
||||
require.NoError(t, insertJournalEntry(
|
||||
storeInstance.database,
|
||||
storeInstance.sqliteDatabase,
|
||||
"events",
|
||||
"session-b",
|
||||
`{"like":2}`,
|
||||
|
|
@ -165,13 +165,13 @@ func TestJournal_QueryJournal_Good_AbsoluteRangeWithStop(t *testing.T) {
|
|||
storeInstance.CommitToJournal("session-b", map[string]any{"like": 2}, map[string]string{"workspace": "session-b"}).OK,
|
||||
)
|
||||
|
||||
_, err = storeInstance.database.Exec(
|
||||
_, err = storeInstance.sqliteDatabase.Exec(
|
||||
"UPDATE "+journalEntriesTableName+" SET committed_at = ? WHERE measurement = ?",
|
||||
time.Date(2026, 3, 29, 12, 0, 0, 0, time.UTC).UnixMilli(),
|
||||
"session-a",
|
||||
)
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec(
|
||||
_, err = storeInstance.sqliteDatabase.Exec(
|
||||
"UPDATE "+journalEntriesTableName+" SET committed_at = ? WHERE measurement = ?",
|
||||
time.Date(2026, 3, 30, 12, 0, 0, 0, time.UTC).UnixMilli(),
|
||||
"session-b",
|
||||
|
|
@ -198,13 +198,13 @@ func TestJournal_QueryJournal_Good_AbsoluteRangeHonoursStop(t *testing.T) {
|
|||
storeInstance.CommitToJournal("session-b", map[string]any{"like": 2}, map[string]string{"workspace": "session-b"}).OK,
|
||||
)
|
||||
|
||||
_, err = storeInstance.database.Exec(
|
||||
_, err = storeInstance.sqliteDatabase.Exec(
|
||||
"UPDATE "+journalEntriesTableName+" SET committed_at = ? WHERE measurement = ?",
|
||||
time.Date(2026, 3, 29, 12, 0, 0, 0, time.UTC).UnixMilli(),
|
||||
"session-a",
|
||||
)
|
||||
require.NoError(t, err)
|
||||
_, err = storeInstance.database.Exec(
|
||||
_, err = storeInstance.sqliteDatabase.Exec(
|
||||
"UPDATE "+journalEntriesTableName+" SET committed_at = ? WHERE measurement = ?",
|
||||
time.Date(2026, 3, 30, 12, 0, 0, 0, time.UTC).UnixMilli(),
|
||||
"session-b",
|
||||
|
|
|
|||
|
|
@ -588,8 +588,8 @@ func TestScope_Quota_Bad_QuotaCheckQueryError(t *testing.T) {
|
|||
defer database.Close()
|
||||
|
||||
storeInstance := &Store{
|
||||
database: database,
|
||||
cancelPurge: func() {},
|
||||
sqliteDatabase: database,
|
||||
cancelPurge: func() {},
|
||||
}
|
||||
|
||||
scopedStore, err := NewScopedWithQuota(storeInstance, "tenant-a", QuotaConfig{MaxKeys: 1})
|
||||
|
|
@ -895,7 +895,7 @@ func rawEntryCount(tb testing.TB, storeInstance *Store, group string) int {
|
|||
tb.Helper()
|
||||
|
||||
var count int
|
||||
err := storeInstance.database.QueryRow(
|
||||
err := storeInstance.sqliteDatabase.QueryRow(
|
||||
"SELECT COUNT(*) FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ?",
|
||||
group,
|
||||
).Scan(&count)
|
||||
|
|
|
|||
52
store.go
52
store.go
|
|
@ -60,7 +60,7 @@ type JournalConfiguration struct {
|
|||
|
||||
// Usage example: `storeInstance, err := store.New(":memory:")`
|
||||
type Store struct {
|
||||
database *sql.DB
|
||||
sqliteDatabase *sql.DB
|
||||
databasePath string
|
||||
purgeContext context.Context
|
||||
cancelPurge context.CancelFunc
|
||||
|
|
@ -85,7 +85,7 @@ func (storeInstance *Store) ensureReady(operation string) error {
|
|||
if storeInstance == nil {
|
||||
return core.E(operation, "store is nil", nil)
|
||||
}
|
||||
if storeInstance.database == nil {
|
||||
if storeInstance.sqliteDatabase == nil {
|
||||
return core.E(operation, "store is not initialised", nil)
|
||||
}
|
||||
|
||||
|
|
@ -242,12 +242,12 @@ func openSQLiteStore(operation, databasePath string) (*Store, error) {
|
|||
|
||||
purgeContext, cancel := context.WithCancel(context.Background())
|
||||
return &Store{
|
||||
database: sqliteDatabase,
|
||||
databasePath: databasePath,
|
||||
purgeContext: purgeContext,
|
||||
cancelPurge: cancel,
|
||||
purgeInterval: 60 * time.Second,
|
||||
watchers: make(map[string][]chan Event),
|
||||
sqliteDatabase: sqliteDatabase,
|
||||
databasePath: databasePath,
|
||||
purgeContext: purgeContext,
|
||||
cancelPurge: cancel,
|
||||
purgeInterval: 60 * time.Second,
|
||||
watchers: make(map[string][]chan Event),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -293,10 +293,10 @@ func (storeInstance *Store) Close() error {
|
|||
storeInstance.orphanWorkspaces = nil
|
||||
storeInstance.orphanWorkspacesLock.Unlock()
|
||||
|
||||
if storeInstance.database == nil {
|
||||
if storeInstance.sqliteDatabase == nil {
|
||||
return orphanCleanupErr
|
||||
}
|
||||
if err := storeInstance.database.Close(); err != nil {
|
||||
if err := storeInstance.sqliteDatabase.Close(); err != nil {
|
||||
return core.E("store.Close", "database close", err)
|
||||
}
|
||||
return orphanCleanupErr
|
||||
|
|
@ -310,7 +310,7 @@ func (storeInstance *Store) Get(group, key string) (string, error) {
|
|||
|
||||
var value string
|
||||
var expiresAt sql.NullInt64
|
||||
err := storeInstance.database.QueryRow(
|
||||
err := storeInstance.sqliteDatabase.QueryRow(
|
||||
"SELECT "+entryValueColumn+", expires_at FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND "+entryKeyColumn+" = ?",
|
||||
group, key,
|
||||
).Scan(&value, &expiresAt)
|
||||
|
|
@ -335,7 +335,7 @@ func (storeInstance *Store) Set(group, key, value string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
_, err := storeInstance.database.Exec(
|
||||
_, err := storeInstance.sqliteDatabase.Exec(
|
||||
"INSERT INTO "+entriesTableName+" ("+entryGroupColumn+", "+entryKeyColumn+", "+entryValueColumn+", expires_at) VALUES (?, ?, ?, NULL) "+
|
||||
"ON CONFLICT("+entryGroupColumn+", "+entryKeyColumn+") DO UPDATE SET "+entryValueColumn+" = excluded."+entryValueColumn+", expires_at = NULL",
|
||||
group, key, value,
|
||||
|
|
@ -354,7 +354,7 @@ func (storeInstance *Store) SetWithTTL(group, key, value string, timeToLive time
|
|||
}
|
||||
|
||||
expiresAt := time.Now().Add(timeToLive).UnixMilli()
|
||||
_, err := storeInstance.database.Exec(
|
||||
_, err := storeInstance.sqliteDatabase.Exec(
|
||||
"INSERT INTO "+entriesTableName+" ("+entryGroupColumn+", "+entryKeyColumn+", "+entryValueColumn+", expires_at) VALUES (?, ?, ?, ?) "+
|
||||
"ON CONFLICT("+entryGroupColumn+", "+entryKeyColumn+") DO UPDATE SET "+entryValueColumn+" = excluded."+entryValueColumn+", expires_at = excluded.expires_at",
|
||||
group, key, value, expiresAt,
|
||||
|
|
@ -372,7 +372,7 @@ func (storeInstance *Store) Delete(group, key string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
deleteResult, err := storeInstance.database.Exec("DELETE FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND "+entryKeyColumn+" = ?", group, key)
|
||||
deleteResult, err := storeInstance.sqliteDatabase.Exec("DELETE FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND "+entryKeyColumn+" = ?", group, key)
|
||||
if err != nil {
|
||||
return core.E("store.Delete", "delete row", err)
|
||||
}
|
||||
|
|
@ -393,7 +393,7 @@ func (storeInstance *Store) Count(group string) (int, error) {
|
|||
}
|
||||
|
||||
var count int
|
||||
err := storeInstance.database.QueryRow(
|
||||
err := storeInstance.sqliteDatabase.QueryRow(
|
||||
"SELECT COUNT(*) FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND (expires_at IS NULL OR expires_at > ?)",
|
||||
group, time.Now().UnixMilli(),
|
||||
).Scan(&count)
|
||||
|
|
@ -409,7 +409,7 @@ func (storeInstance *Store) DeleteGroup(group string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
deleteResult, err := storeInstance.database.Exec("DELETE FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ?", group)
|
||||
deleteResult, err := storeInstance.sqliteDatabase.Exec("DELETE FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ?", group)
|
||||
if err != nil {
|
||||
return core.E("store.DeleteGroup", "delete group", err)
|
||||
}
|
||||
|
|
@ -432,11 +432,11 @@ func (storeInstance *Store) DeletePrefix(groupPrefix string) error {
|
|||
var rows *sql.Rows
|
||||
var err error
|
||||
if groupPrefix == "" {
|
||||
rows, err = storeInstance.database.Query(
|
||||
rows, err = storeInstance.sqliteDatabase.Query(
|
||||
"SELECT DISTINCT " + entryGroupColumn + " FROM " + entriesTableName + " ORDER BY " + entryGroupColumn,
|
||||
)
|
||||
} else {
|
||||
rows, err = storeInstance.database.Query(
|
||||
rows, err = storeInstance.sqliteDatabase.Query(
|
||||
"SELECT DISTINCT "+entryGroupColumn+" FROM "+entriesTableName+" WHERE "+entryGroupColumn+" LIKE ? ESCAPE '^' ORDER BY "+entryGroupColumn,
|
||||
escapeLike(groupPrefix)+"%",
|
||||
)
|
||||
|
|
@ -501,7 +501,7 @@ func (storeInstance *Store) GetPage(group string, offset, limit int) ([]KeyValue
|
|||
return nil, core.E("store.GetPage", "limit must be zero or positive", nil)
|
||||
}
|
||||
|
||||
rows, err := storeInstance.database.Query(
|
||||
rows, err := storeInstance.sqliteDatabase.Query(
|
||||
"SELECT "+entryKeyColumn+", "+entryValueColumn+" FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND (expires_at IS NULL OR expires_at > ?) ORDER BY "+entryKeyColumn+" LIMIT ? OFFSET ?",
|
||||
group, time.Now().UnixMilli(), limit, offset,
|
||||
)
|
||||
|
|
@ -532,7 +532,7 @@ func (storeInstance *Store) AllSeq(group string) iter.Seq2[KeyValue, error] {
|
|||
return
|
||||
}
|
||||
|
||||
rows, err := storeInstance.database.Query(
|
||||
rows, err := storeInstance.sqliteDatabase.Query(
|
||||
"SELECT "+entryKeyColumn+", "+entryValueColumn+" FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND (expires_at IS NULL OR expires_at > ?) ORDER BY "+entryKeyColumn,
|
||||
group, time.Now().UnixMilli(),
|
||||
)
|
||||
|
|
@ -625,12 +625,12 @@ func (storeInstance *Store) CountAll(groupPrefix string) (int, error) {
|
|||
var count int
|
||||
var err error
|
||||
if groupPrefix == "" {
|
||||
err = storeInstance.database.QueryRow(
|
||||
err = storeInstance.sqliteDatabase.QueryRow(
|
||||
"SELECT COUNT(*) FROM "+entriesTableName+" WHERE (expires_at IS NULL OR expires_at > ?)",
|
||||
time.Now().UnixMilli(),
|
||||
).Scan(&count)
|
||||
} else {
|
||||
err = storeInstance.database.QueryRow(
|
||||
err = storeInstance.sqliteDatabase.QueryRow(
|
||||
"SELECT COUNT(*) FROM "+entriesTableName+" WHERE "+entryGroupColumn+" LIKE ? ESCAPE '^' AND (expires_at IS NULL OR expires_at > ?)",
|
||||
escapeLike(groupPrefix)+"%", time.Now().UnixMilli(),
|
||||
).Scan(&count)
|
||||
|
|
@ -672,12 +672,12 @@ func (storeInstance *Store) GroupsSeq(groupPrefix ...string) iter.Seq2[string, e
|
|||
var err error
|
||||
now := time.Now().UnixMilli()
|
||||
if actualGroupPrefix == "" {
|
||||
rows, err = storeInstance.database.Query(
|
||||
rows, err = storeInstance.sqliteDatabase.Query(
|
||||
"SELECT DISTINCT "+entryGroupColumn+" FROM "+entriesTableName+" WHERE (expires_at IS NULL OR expires_at > ?) ORDER BY "+entryGroupColumn,
|
||||
now,
|
||||
)
|
||||
} else {
|
||||
rows, err = storeInstance.database.Query(
|
||||
rows, err = storeInstance.sqliteDatabase.Query(
|
||||
"SELECT DISTINCT "+entryGroupColumn+" FROM "+entriesTableName+" WHERE "+entryGroupColumn+" LIKE ? ESCAPE '^' AND (expires_at IS NULL OR expires_at > ?) ORDER BY "+entryGroupColumn,
|
||||
escapeLike(actualGroupPrefix)+"%", now,
|
||||
)
|
||||
|
|
@ -818,12 +818,12 @@ func (storeInstance *Store) purgeExpiredMatchingGroupPrefix(groupPrefix string)
|
|||
)
|
||||
now := time.Now().UnixMilli()
|
||||
if groupPrefix == "" {
|
||||
deleteResult, err = storeInstance.database.Exec(
|
||||
deleteResult, err = storeInstance.sqliteDatabase.Exec(
|
||||
"DELETE FROM "+entriesTableName+" WHERE expires_at IS NOT NULL AND expires_at <= ?",
|
||||
now,
|
||||
)
|
||||
} else {
|
||||
deleteResult, err = storeInstance.database.Exec(
|
||||
deleteResult, err = storeInstance.sqliteDatabase.Exec(
|
||||
"DELETE FROM "+entriesTableName+" WHERE expires_at IS NOT NULL AND expires_at <= ? AND "+entryGroupColumn+" LIKE ? ESCAPE '^'",
|
||||
now, escapeLike(groupPrefix)+"%",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ func TestStore_New_Good_WALMode(t *testing.T) {
|
|||
defer storeInstance.Close()
|
||||
|
||||
var mode string
|
||||
err = storeInstance.database.QueryRow("PRAGMA journal_mode").Scan(&mode)
|
||||
err = storeInstance.sqliteDatabase.QueryRow("PRAGMA journal_mode").Scan(&mode)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "wal", mode, "journal_mode should be WAL")
|
||||
}
|
||||
|
|
@ -840,8 +840,8 @@ func TestStore_Close_Good_OperationsFailAfterClose(t *testing.T) {
|
|||
func TestStore_Close_Bad_DriverCloseError(t *testing.T) {
|
||||
database := testCloseErrorDatabase(t)
|
||||
storeInstance := &Store{
|
||||
database: database,
|
||||
cancelPurge: func() {},
|
||||
sqliteDatabase: database,
|
||||
cancelPurge: func() {},
|
||||
}
|
||||
|
||||
err := storeInstance.Close()
|
||||
|
|
@ -1400,8 +1400,8 @@ func TestStore_PurgeExpired_Bad_ClosedStore(t *testing.T) {
|
|||
func TestStore_PurgeExpired_Bad_RowsAffectedError(t *testing.T) {
|
||||
database := testRowsAffectedErrorDatabase(t)
|
||||
storeInstance := &Store{
|
||||
database: database,
|
||||
cancelPurge: func() {},
|
||||
sqliteDatabase: database,
|
||||
cancelPurge: func() {},
|
||||
}
|
||||
|
||||
_, err := storeInstance.PurgeExpired()
|
||||
|
|
@ -1423,7 +1423,7 @@ func TestStore_PurgeExpired_Good_BackgroundPurge(t *testing.T) {
|
|||
// The expired key should have been removed by the background goroutine.
|
||||
// Use a raw query to check the row is actually gone (not just filtered by Get).
|
||||
var count int
|
||||
err = storeInstance.database.QueryRow("SELECT COUNT(*) FROM entries WHERE group_name = ?", "g").Scan(&count)
|
||||
err = storeInstance.sqliteDatabase.QueryRow("SELECT COUNT(*) FROM entries WHERE group_name = ?", "g").Scan(&count)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, count, "background purge should have deleted the expired row")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func (storeInstance *Store) Transaction(operation func(*StoreTransaction) error)
|
|||
return core.E("store.Transaction", "operation is nil", nil)
|
||||
}
|
||||
|
||||
transaction, err := storeInstance.database.Begin()
|
||||
transaction, err := storeInstance.sqliteDatabase.Begin()
|
||||
if err != nil {
|
||||
return core.E("store.Transaction", "begin transaction", err)
|
||||
}
|
||||
|
|
|
|||
56
workspace.go
56
workspace.go
|
|
@ -37,11 +37,11 @@ var defaultWorkspaceStateDirectory = ".core/state/"
|
|||
//
|
||||
// Usage example: `workspace, err := storeInstance.NewWorkspace("scroll-session-2026-03-30"); if err != nil { return }; defer workspace.Discard(); _ = workspace.Put("like", map[string]any{"user": "@alice"})`
|
||||
type Workspace struct {
|
||||
name string
|
||||
backingStore *Store
|
||||
database *sql.DB
|
||||
databasePath string
|
||||
filesystem *core.Fs
|
||||
name string
|
||||
backingStore *Store
|
||||
workspaceDatabase *sql.DB
|
||||
databasePath string
|
||||
filesystem *core.Fs
|
||||
|
||||
closeLock sync.Mutex
|
||||
closed bool
|
||||
|
|
@ -78,7 +78,7 @@ func (workspace *Workspace) ensureReady(operation string) error {
|
|||
if workspace.backingStore == nil {
|
||||
return core.E(operation, "workspace store is nil", nil)
|
||||
}
|
||||
if workspace.database == nil {
|
||||
if workspace.workspaceDatabase == nil {
|
||||
return core.E(operation, "workspace database is nil", nil)
|
||||
}
|
||||
if workspace.filesystem == nil {
|
||||
|
|
@ -127,11 +127,11 @@ func (storeInstance *Store) NewWorkspace(name string) (*Workspace, error) {
|
|||
}
|
||||
|
||||
return &Workspace{
|
||||
name: name,
|
||||
backingStore: storeInstance,
|
||||
database: workspaceDatabase,
|
||||
databasePath: databasePath,
|
||||
filesystem: filesystem,
|
||||
name: name,
|
||||
backingStore: storeInstance,
|
||||
workspaceDatabase: workspaceDatabase,
|
||||
databasePath: databasePath,
|
||||
filesystem: filesystem,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -186,11 +186,11 @@ func discoverOrphanWorkspaces(stateDirectory string, backingStore *Store) []*Wor
|
|||
continue
|
||||
}
|
||||
orphanWorkspaces = append(orphanWorkspaces, &Workspace{
|
||||
name: workspaceNameFromPath(stateDirectory, databasePath),
|
||||
backingStore: backingStore,
|
||||
database: workspaceDatabase,
|
||||
databasePath: databasePath,
|
||||
filesystem: filesystem,
|
||||
name: workspaceNameFromPath(stateDirectory, databasePath),
|
||||
backingStore: backingStore,
|
||||
workspaceDatabase: workspaceDatabase,
|
||||
databasePath: databasePath,
|
||||
filesystem: filesystem,
|
||||
})
|
||||
}
|
||||
return orphanWorkspaces
|
||||
|
|
@ -238,11 +238,11 @@ func (storeInstance *Store) RecoverOrphans(stateDirectory string) []*Workspace {
|
|||
continue
|
||||
}
|
||||
orphanWorkspaces = append(orphanWorkspaces, &Workspace{
|
||||
name: workspaceNameFromPath(stateDirectory, databasePath),
|
||||
backingStore: storeInstance,
|
||||
database: workspaceDatabase,
|
||||
databasePath: databasePath,
|
||||
filesystem: filesystem,
|
||||
name: workspaceNameFromPath(stateDirectory, databasePath),
|
||||
backingStore: storeInstance,
|
||||
workspaceDatabase: workspaceDatabase,
|
||||
databasePath: databasePath,
|
||||
filesystem: filesystem,
|
||||
})
|
||||
}
|
||||
return orphanWorkspaces
|
||||
|
|
@ -266,7 +266,7 @@ func (workspace *Workspace) Put(kind string, data map[string]any) error {
|
|||
return err
|
||||
}
|
||||
|
||||
_, err = workspace.database.Exec(
|
||||
_, err = workspace.workspaceDatabase.Exec(
|
||||
"INSERT INTO "+workspaceEntriesTableName+" (entry_kind, entry_data, created_at) VALUES (?, ?, ?)",
|
||||
kind,
|
||||
dataJSON,
|
||||
|
|
@ -327,7 +327,7 @@ func (workspace *Workspace) Query(sqlQuery string) core.Result {
|
|||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
rows, err := workspace.database.Query(sqlQuery)
|
||||
rows, err := workspace.workspaceDatabase.Query(sqlQuery)
|
||||
if err != nil {
|
||||
return core.Result{Value: core.E("store.Workspace.Query", "query workspace", err), OK: false}
|
||||
}
|
||||
|
|
@ -345,7 +345,7 @@ func (workspace *Workspace) aggregateFields() (map[string]any, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := workspace.database.Query(
|
||||
rows, err := workspace.workspaceDatabase.Query(
|
||||
"SELECT entry_kind, COUNT(*) FROM " + workspaceEntriesTableName + " GROUP BY entry_kind ORDER BY entry_kind",
|
||||
)
|
||||
if err != nil {
|
||||
|
|
@ -384,7 +384,7 @@ func (workspace *Workspace) closeAndCleanup(removeFiles bool) error {
|
|||
if workspace == nil {
|
||||
return nil
|
||||
}
|
||||
if workspace.database == nil || workspace.filesystem == nil {
|
||||
if workspace.workspaceDatabase == nil || workspace.filesystem == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -396,7 +396,7 @@ func (workspace *Workspace) closeAndCleanup(removeFiles bool) error {
|
|||
}
|
||||
workspace.closed = true
|
||||
|
||||
if err := workspace.database.Close(); err != nil {
|
||||
if err := workspace.workspaceDatabase.Close(); err != nil {
|
||||
return core.E("store.Workspace.closeAndRemoveFiles", "close workspace database", err)
|
||||
}
|
||||
if !removeFiles {
|
||||
|
|
@ -414,11 +414,11 @@ func (storeInstance *Store) commitWorkspaceAggregate(workspaceName string, field
|
|||
if err := storeInstance.ensureReady("store.Workspace.Commit"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ensureJournalSchema(storeInstance.database); err != nil {
|
||||
if err := ensureJournalSchema(storeInstance.sqliteDatabase); err != nil {
|
||||
return core.E("store.Workspace.Commit", "ensure journal schema", err)
|
||||
}
|
||||
|
||||
transaction, err := storeInstance.database.Begin()
|
||||
transaction, err := storeInstance.sqliteDatabase.Begin()
|
||||
if err != nil {
|
||||
return core.E("store.Workspace.Commit", "begin transaction", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ func TestWorkspace_RecoverOrphans_Good(t *testing.T) {
|
|||
workspace, err := storeInstance.NewWorkspace("orphan-session")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, workspace.Put("like", map[string]any{"user": "@alice"}))
|
||||
require.NoError(t, workspace.database.Close())
|
||||
require.NoError(t, workspace.workspaceDatabase.Close())
|
||||
|
||||
orphans := storeInstance.RecoverOrphans(stateDirectory)
|
||||
require.Len(t, orphans, 1)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue