diff --git a/code/faroe-cache-map_go b/code/faroe-cache-map_go deleted file mode 100644 index e7a3357..0000000 --- a/code/faroe-cache-map_go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -// NOTE: -// Go maps do not have a size cap. Use LRU-caches instead for anything serious. - -import ( - "sync" - "time" - - "github.com/faroedev/faroe" -) - -type cacheStruct struct { - records map[string]cacheRecordStruct - m *sync.Mutex -} - -func newCache() *cacheStruct { - storage := &cacheStruct{ - records: map[string]cacheRecordStruct{}, - m: &sync.Mutex{}, - } - - return storage -} - -func (cache *cacheStruct) Get(key string) ([]byte, error) { - cache.m.Lock() - defer cache.m.Unlock() - - record, ok := cache.records[key] - if !ok { - return nil, faroe.ErrCacheEntryNotFound - } - - if time.Now().Compare(record.expiresAt) >= 0 { - delete(cache.records, key) - - return nil, faroe.ErrCacheEntryNotFound - } - - return record.value, nil -} - -func (cache *cacheStruct) Set(key string, value []byte, ttl time.Duration) error { - cache.m.Lock() - defer cache.m.Unlock() - - record := cacheRecordStruct{ - value: value, - expiresAt: time.Now().Add(ttl), - } - cache.records[key] = record - - return nil -} - -func (cache *cacheStruct) Delete(key string) error { - cache.m.Lock() - defer cache.m.Unlock() - - delete(cache.records, key) - - return nil -} - -type cacheRecordStruct struct { - value []byte - expiresAt time.Time -} diff --git a/code/faroe-main-storage-map_go b/code/faroe-main-storage-map_go deleted file mode 100644 index 989077a..0000000 --- a/code/faroe-main-storage-map_go +++ /dev/null @@ -1,86 +0,0 @@ -package main - -// NOTE: -// Go maps do not have a size cap. Use LRU-caches instead for anything serious. - -import ( - "sync" - "time" - - "github.com/faroedev/faroe" -) - -type mainStorageStruct struct { - records map[string]mainStorageRecordStruct - m *sync.Mutex -} - -func newMainStorage() *mainStorageStruct { - storage := &mainStorageStruct{ - records: map[string]mainStorageRecordStruct{}, - m: &sync.Mutex{}, - } - return storage -} - -func (mainStorage *mainStorageStruct) Get(key string) ([]byte, int32, error) { - mainStorage.m.Lock() - defer mainStorage.m.Unlock() - - record, ok := mainStorage.records[key] - if !ok { - return nil, 0, faroe.ErrMainStorageEntryNotFound - } - - return record.value, record.counter, nil -} - -func (mainStorage *mainStorageStruct) Set(key string, value []byte, _ time.Time) error { - mainStorage.m.Lock() - defer mainStorage.m.Unlock() - - mainStorage.records[key] = mainStorageRecordStruct{ - key: key, - value: value, - counter: 0, - } - - return nil -} - -func (mainStorage *mainStorageStruct) Update(key string, value []byte, _ time.Time, counter int32) error { - mainStorage.m.Lock() - defer mainStorage.m.Unlock() - - record, ok := mainStorage.records[key] - if !ok { - return faroe.ErrMainStorageEntryNotFound - } - if record.counter != counter { - return faroe.ErrMainStorageEntryNotFound - } - record.value = value - record.counter++ - mainStorage.records[key] = record - - return nil -} - -func (mainStorage *mainStorageStruct) Delete(key string) error { - mainStorage.m.Lock() - defer mainStorage.m.Unlock() - - _, ok := mainStorage.records[key] - if !ok { - return faroe.ErrMainStorageEntryNotFound - } - delete(mainStorage.records, key) - - return nil -} - -type mainStorageRecordStruct struct { - key string - value []byte - counter int32 -} diff --git a/code/faroe-main-storage-sql-postgresql_go b/code/faroe-main-storage-sql-postgresql_go deleted file mode 100644 index d5f12fb..0000000 --- a/code/faroe-main-storage-sql-postgresql_go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -/* -CREATE TABLE main_storage ( - key TEXT PRIMARY KEY, - value BYTEA NOT NULL, - counter INTEGER NOT NULL, - expires_at TIMESTAMPTZ NOT NULL -); -*/ - -import ( - "database/sql" - "errors" - "fmt" - "time" - - "github.com/faroedev/faroe" -) - -type mainStorageStruct struct { - db *sql.DB -} - -func newMainStorage(db *sql.DB) *mainStorageStruct { - storage := &mainStorageStruct{ - db: db, - } - return storage -} - -func (mainStorage *mainStorageStruct) Get(key string) ([]byte, int32, error) { - row := mainStorage.db.QueryRow("SELECT value, counter FROM main_storage WHERE key = $1", key) - - var value []byte - var counter int32 - err := row.Scan(&value, &counter) - if err != nil && errors.Is(err, sql.ErrNoRows) { - return nil, 0, faroe.ErrMainStorageEntryNotFound - } - if err != nil { - return nil, 0, fmt.Errorf("failed to run query: %s", err.Error()) - } - - return value, counter, nil -} - -func (mainStorage *mainStorageStruct) Set(key string, value []byte, expiresAt time.Time) error { - _, err := mainStorage.db.Exec("INSERT INTO main_storage (key, value, counter, expires_at) VALUES ($1, $2, $3, $4)", key, value, 0, expiresAt.Unix()) - if err != nil { - return fmt.Errorf("failed to run query: %s", err.Error()) - } - - return nil -} - -func (mainStorage *mainStorageStruct) Update(key string, value []byte, expiresAt time.Time, counter int32) error { - result, err := mainStorage.db.Exec("UPDATE main_storage SET value = $1, counter = counter + 1, expires_at = $2 WHERE key = $3 AND counter = $4", value, expiresAt, key, counter) - if err != nil { - return fmt.Errorf("failed to run query: %s", err.Error()) - } - rowsAffected, _ := result.RowsAffected() - if rowsAffected < 1 { - return faroe.ErrMainStorageEntryNotFound - } - - return nil -} - -func (mainStorage *mainStorageStruct) Delete(key string) error { - result, err := mainStorage.db.Exec("DELETE FROM main_storage WHERE key = $1", key) - if err != nil { - return fmt.Errorf("failed to run query: %s", err.Error()) - } - rowsAffected, _ := result.RowsAffected() - if rowsAffected < 1 { - return faroe.ErrMainStorageEntryNotFound - } - - return nil -} diff --git a/code/faroe-main-storage-sql-sqlite_go b/code/faroe-main-storage-sql-sqlite_go deleted file mode 100644 index 14ad0d5..0000000 --- a/code/faroe-main-storage-sql-sqlite_go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -/* -CREATE TABLE main_storage ( - key TEXT NOT NULL PRIMARY KEY, - value BLOB NOT NULL, - counter INTEGER NOT NULL, - expires_at INTEGER NOT NULL -) STRICT; -*/ - -import ( - "database/sql" - "errors" - "fmt" - "time" - - "github.com/faroedev/faroe" -) - -type mainStorageStruct struct { - db *sql.DB -} - -func newMainStorage(db *sql.DB) *mainStorageStruct { - storage := &mainStorageStruct{ - db: db, - } - return storage -} - -func (mainStorage *mainStorageStruct) Get(key string) ([]byte, int32, error) { - row := mainStorage.db.QueryRow("SELECT value, counter FROM main_storage WHERE key = ?", key) - - var value []byte - var counter int32 - err := row.Scan(&value, &counter) - if err != nil && errors.Is(err, sql.ErrNoRows) { - return nil, 0, faroe.ErrMainStorageEntryNotFound - } - if err != nil { - return nil, 0, fmt.Errorf("failed to run query: %s", err.Error()) - } - - return value, counter, nil -} - -func (mainStorage *mainStorageStruct) Set(key string, value []byte, expiresAt time.Time) error { - _, err := mainStorage.db.Exec("INSERT INTO main_storage (key, value, counter, expires_at) VALUES (?, ?, ?, ?)", key, value, 0, expiresAt.Unix()) - if err != nil { - return fmt.Errorf("failed to run query: %s", err.Error()) - } - - return nil -} - -func (mainStorage *mainStorageStruct) Update(key string, value []byte, expiresAt time.Time, counter int32) error { - result, err := mainStorage.db.Exec("UPDATE main_storage SET value = ?, counter = counter + 1, expires_at = ? WHERE key = ? AND counter = ?", value, expiresAt, key, counter) - if err != nil { - return fmt.Errorf("failed to run query: %s", err.Error()) - } - rowsAffected, _ := result.RowsAffected() - if rowsAffected < 1 { - return faroe.ErrMainStorageEntryNotFound - } - - return nil -} - -func (mainStorage *mainStorageStruct) Delete(key string) error { - result, err := mainStorage.db.Exec("DELETE FROM main_storage WHERE key = ?", key) - if err != nil { - return fmt.Errorf("failed to run query: %s", err.Error()) - } - rowsAffected, _ := result.RowsAffected() - if rowsAffected < 1 { - return faroe.ErrMainStorageEntryNotFound - } - - return nil -} diff --git a/code/faroe-storage-map_go b/code/faroe-storage-map_go new file mode 100644 index 0000000..4b301b2 --- /dev/null +++ b/code/faroe-storage-map_go @@ -0,0 +1,91 @@ +package main + +// NOTE: +// Go maps do not have a size cap. Use LRU-caches instead for anything serious. + +import ( + "sync" + "time" + + "github.com/faroedev/faroe" +) + +type storageStruct struct { + records map[string]storageRecordStruct + m *sync.Mutex +} + +func newStorage() *storageStruct { + storage := &storageStruct{ + records: map[string]storageRecordStruct{}, + m: &sync.Mutex{}, + } + return storage +} + +func (storage *storageStruct) Get(key string) ([]byte, int32, error) { + storage.m.Lock() + defer storage.m.Unlock() + + record, ok := storage.records[key] + if !ok { + return nil, 0, faroe.ErrStorageEntryNotFound + } + + return record.value, record.counter, nil +} + +func (storage *storageStruct) Add(key string, value []byte, _ time.Time) error { + storage.m.Lock() + defer storage.m.Unlock() + + _, ok := storage.records[key] + if ok { + return faroe.ErrStorageEntryAlreadyExists + } + + storage.records[key] = storageRecordStruct{ + key: key, + value: value, + counter: 0, + } + + return nil +} + +func (storage *storageStruct) Update(key string, value []byte, _ time.Time, counter int32) error { + storage.m.Lock() + defer storage.m.Unlock() + + record, ok := storage.records[key] + if !ok { + return faroe.ErrStorageEntryNotFound + } + if record.counter != counter { + return faroe.ErrStorageEntryNotFound + } + record.value = value + record.counter++ + storage.records[key] = record + + return nil +} + +func (storage *storageStruct) Delete(key string) error { + storage.m.Lock() + defer storage.m.Unlock() + + _, ok := storage.records[key] + if !ok { + return faroe.ErrStorageEntryNotFound + } + delete(storage.records, key) + + return nil +} + +type storageRecordStruct struct { + key string + value []byte + counter int32 +} diff --git a/code/faroe-main-storage-sql-mysql_go b/code/faroe-storage-sql-mysql_go similarity index 91% rename from code/faroe-main-storage-sql-mysql_go rename to code/faroe-storage-sql-mysql_go index 8947e07..acce160 100644 --- a/code/faroe-main-storage-sql-mysql_go +++ b/code/faroe-storage-sql-mysql_go @@ -45,8 +45,12 @@ func (mainStorage *mainStorageStruct) Get(key string) ([]byte, int32, error) { return value, counter, nil } -func (mainStorage *mainStorageStruct) Set(key string, value []byte, expiresAt time.Time) error { +func (mainStorage *mainStorageStruct) Add(key string, value []byte, expiresAt time.Time) error { _, err := mainStorage.db.Exec("INSERT INTO main_storage (id, value, counter, expires_at) VALUES (?, ?, ?, ?)", key, value, 0, expiresAt.Unix()) + // TODO: Driver-dependent. + if isUniqueConstraintError(err) { + return faroe.ErrStorageEntryAlreadyExists + } if err != nil { return fmt.Errorf("failed to run query: %s", err.Error()) } diff --git a/code/faroe-storage-sql-postgresql_go b/code/faroe-storage-sql-postgresql_go new file mode 100644 index 0000000..927138c --- /dev/null +++ b/code/faroe-storage-sql-postgresql_go @@ -0,0 +1,85 @@ +package main + +/* +CREATE TABLE main_storage ( + key TEXT PRIMARY KEY, + value BYTEA NOT NULL, + counter INTEGER NOT NULL, + expires_at TIMESTAMPTZ NOT NULL +); +*/ + +import ( + "database/sql" + "errors" + "fmt" + "time" + + "github.com/faroedev/faroe" +) + +type storageStruct struct { + db *sql.DB +} + +func newStorage(db *sql.DB) *storageStruct { + storage := &storageStruct{ + db: db, + } + return storage +} + +func (storage *storageStruct) Get(key string) ([]byte, int32, error) { + row := storage.db.QueryRow("SELECT value, counter FROM main_storage WHERE key = $1", key) + + var value []byte + var counter int32 + err := row.Scan(&value, &counter) + if err != nil && errors.Is(err, sql.ErrNoRows) { + return nil, 0, faroe.ErrStorageEntryNotFound + } + if err != nil { + return nil, 0, fmt.Errorf("failed to run query: %s", err.Error()) + } + + return value, counter, nil +} + +func (storage *storageStruct) Add(key string, value []byte, expiresAt time.Time) error { + _, err := storage.db.Exec("INSERT INTO main_storage (key, value, counter, expires_at) VALUES ($1, $2, $3, $4)", key, value, 0, expiresAt.Unix()) + // TODO: Driver-dependent. + if isUniqueConstraintError(err) { + return faroe.ErrStorageEntryAlreadyExists + } + if err != nil { + return fmt.Errorf("failed to run query: %s", err.Error()) + } + + return nil +} + +func (storage *storageStruct) Update(key string, value []byte, expiresAt time.Time, counter int32) error { + result, err := storage.db.Exec("UPDATE main_storage SET value = $1, counter = counter + 1, expires_at = $2 WHERE key = $3 AND counter = $4", value, expiresAt, key, counter) + if err != nil { + return fmt.Errorf("failed to run query: %s", err.Error()) + } + rowsAffected, _ := result.RowsAffected() + if rowsAffected < 1 { + return faroe.ErrStorageEntryNotFound + } + + return nil +} + +func (storage *storageStruct) Delete(key string) error { + result, err := storage.db.Exec("DELETE FROM main_storage WHERE key = $1", key) + if err != nil { + return fmt.Errorf("failed to run query: %s", err.Error()) + } + rowsAffected, _ := result.RowsAffected() + if rowsAffected < 1 { + return faroe.ErrStorageEntryNotFound + } + + return nil +} diff --git a/code/faroe-storage-sql-sqlite_go b/code/faroe-storage-sql-sqlite_go new file mode 100644 index 0000000..1b2626c --- /dev/null +++ b/code/faroe-storage-sql-sqlite_go @@ -0,0 +1,85 @@ +package main + +/* +CREATE TABLE main_storage ( + key TEXT NOT NULL PRIMARY KEY, + value BLOB NOT NULL, + counter INTEGER NOT NULL, + expires_at INTEGER NOT NULL +) STRICT; +*/ + +import ( + "database/sql" + "errors" + "fmt" + "time" + + "github.com/faroedev/faroe" +) + +type storageStruct struct { + db *sql.DB +} + +func newStorage(db *sql.DB) *storageStruct { + storage := &storageStruct{ + db: db, + } + return storage +} + +func (storage *storageStruct) Get(key string) ([]byte, int32, error) { + row := storage.db.QueryRow("SELECT value, counter FROM main_storage WHERE key = ?", key) + + var value []byte + var counter int32 + err := row.Scan(&value, &counter) + if err != nil && errors.Is(err, sql.ErrNoRows) { + return nil, 0, faroe.ErrStorageEntryNotFound + } + if err != nil { + return nil, 0, fmt.Errorf("failed to run query: %s", err.Error()) + } + + return value, counter, nil +} + +func (storage *storageStruct) Add(key string, value []byte, expiresAt time.Time) error { + _, err := storage.db.Exec("INSERT INTO main_storage (key, value, counter, expires_at) VALUES (?, ?, ?, ?)", key, value, 0, expiresAt.Unix()) + // TODO: Driver-dependent. + if isUniqueConstraintError(err) { + return faroe.ErrStorageEntryAlreadyExists + } + if err != nil { + return fmt.Errorf("failed to run query: %s", err.Error()) + } + + return nil +} + +func (storage *storageStruct) Update(key string, value []byte, expiresAt time.Time, counter int32) error { + result, err := storage.db.Exec("UPDATE main_storage SET value = ?, counter = counter + 1, expires_at = ? WHERE key = ? AND counter = ?", value, expiresAt, key, counter) + if err != nil { + return fmt.Errorf("failed to run query: %s", err.Error()) + } + rowsAffected, _ := result.RowsAffected() + if rowsAffected < 1 { + return faroe.ErrStorageEntryNotFound + } + + return nil +} + +func (storage *storageStruct) Delete(key string) error { + result, err := storage.db.Exec("DELETE FROM main_storage WHERE key = ?", key) + if err != nil { + return fmt.Errorf("failed to run query: %s", err.Error()) + } + rowsAffected, _ := result.RowsAffected() + if rowsAffected < 1 { + return faroe.ErrStorageEntryNotFound + } + + return nil +}