feat: add open options

Signed-off-by: jolheiser <john.olheiser@gmail.com>
main
jolheiser 2022-11-15 12:04:54 -06:00
parent d10e3dcd4a
commit fd091c5c4b
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
3 changed files with 132 additions and 2 deletions

85
options.go 100644
View File

@ -0,0 +1,85 @@
package sqkv
import (
"fmt"
"strings"
)
// OpenMode for opening a DB
type OpenMode string
const (
OpenModeReadOnly OpenMode = "ro"
OpenModeReadWrite OpenMode = "rw"
OpenModeReadWriteCreate OpenMode = "rwc"
OpenModeMemory OpenMode = "memory"
)
// OpenCache for setting the cache mode
type OpenCache string
const (
OpenCacheShared OpenCache = "shared"
OpenCachePrivate OpenCache = "private"
)
// OpenJournalMode for setting the journal mode
type OpenJournalMode string
const (
OpenJournalModeDelete = "delete"
OpenJournalModeTruncate = "truncate"
OpenJournalModePersist = "persist"
OpenJournalModeMemory = "memory"
OpenJournalModeWAL = "wal"
OpenJournalModeOff = "off"
)
// OpenConfig is a configuration for opening a DB
type OpenConfig struct {
Mode OpenMode
Cache OpenCache
JournalMode OpenJournalMode
}
// String implements fmt.Stringer
func (oc OpenConfig) String() string {
var opts []string
if oc.Mode != "" {
opts = append(opts, "mode="+string(oc.Mode))
}
if oc.Cache != "" {
opts = append(opts, "cache="+string(oc.Cache))
}
if oc.JournalMode != "" {
opts = append(opts, fmt.Sprintf("_pragma=journal_mode(%s)", oc.JournalMode))
}
if len(opts) == 0 {
return ""
}
return "?" + strings.Join(opts, "&")
}
// OpenOption is a func for setting open config values
type OpenOption func(*OpenConfig)
// WithMode sets the mode for opening the DB
func WithMode(mode OpenMode) OpenOption {
return func(oc *OpenConfig) {
oc.Mode = mode
}
}
// WithCache sets the cache for opening the DB
func WithCache(cache OpenCache) OpenOption {
return func(oc *OpenConfig) {
oc.Cache = cache
}
}
// WithJournalMode sets the journal mode for the DB
func WithJournalMode(journalMode OpenJournalMode) OpenOption {
return func(oc *OpenConfig) {
oc.JournalMode = journalMode
}
}

20
sqkv.go
View File

@ -1,6 +1,7 @@
package sqkv
import (
"context"
"database/sql"
"fmt"
"regexp"
@ -14,8 +15,13 @@ type DB struct {
}
// Open opens (or creates) a new SQKV database
func Open(path string) (*DB, error) {
dsn := fmt.Sprintf("file:%s?cache=shared&mode=rwc", path)
func Open(path string, opts ...OpenOption) (*DB, error) {
cfg := &OpenConfig{}
for _, opt := range opts {
opt(cfg)
}
dsn := fmt.Sprintf("file:%s%s", path, cfg)
db, err := sql.Open("sqlite", dsn)
if err != nil {
return nil, err
@ -28,6 +34,16 @@ func Open(path string) (*DB, error) {
return sqkv, err
}
// Close closes the connection to the database
func (d *DB) Close() error {
return d.db.Close()
}
// Conn returns a direct DB connection
func (d *DB) Conn() (*sql.Conn, error) {
return d.db.Conn(context.Background())
}
// Get returns a value from the default bucket
func (d *DB) Get(key string) (string, error) {
b, err := d.Bucket(DefaultBucket)

View File

@ -2,6 +2,7 @@ package sqkv
import (
"errors"
"os"
"path/filepath"
"testing"
@ -16,6 +17,7 @@ func TestDefault(t *testing.T) {
db, err := Open(dbPath)
assert.NoErr(err) // Should create database
defer db.Close()
err = db.Put("foo", "bar")
assert.NoErr(err) // Should put kv
@ -39,6 +41,7 @@ func TestBucket(t *testing.T) {
db, err := Open(dbPath)
assert.NoErr(err) // Should create database
defer db.Close()
_, err = db.Bucket("honk")
assert.True(errors.Is(err, ErrBucketDoesNotExist)) // Bucket does not exist; should error
@ -65,3 +68,29 @@ func TestBucket(t *testing.T) {
_, err = b.Get("foo")
assert.True(errors.Is(err, ErrKeyDoesNotExist))
}
func TestOptions(t *testing.T) {
assert := is.New(t)
tmp := t.TempDir()
dbPath := filepath.Join(tmp, "opt.db")
_, err := Open(dbPath, WithMode(OpenModeReadOnly))
assert.True(err != nil) // Database should not be created
_, err = Open(dbPath, WithMode(OpenModeReadWrite))
assert.True(err != nil) // Database should not be created
_, err = Open(dbPath, WithMode(OpenModeMemory))
assert.NoErr(err) // Database should not be created, but no error
_, err = os.Stat(dbPath)
assert.True(err != nil) // Database should not be created on disk
db, err := Open(dbPath, WithJournalMode(OpenJournalModeWAL))
defer db.Close()
var jm string
row := db.db.QueryRow("PRAGMA journal_mode")
assert.NoErr(row.Scan(&jm)) // Should return PRAGMA result
assert.Equal(jm, "wal") // Journal mode should be WAL
}