parent
d10e3dcd4a
commit
fd091c5c4b
|
@ -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
20
sqkv.go
|
@ -1,6 +1,7 @@
|
||||||
package sqkv
|
package sqkv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -14,8 +15,13 @@ type DB struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens (or creates) a new SQKV database
|
// Open opens (or creates) a new SQKV database
|
||||||
func Open(path string) (*DB, error) {
|
func Open(path string, opts ...OpenOption) (*DB, error) {
|
||||||
dsn := fmt.Sprintf("file:%s?cache=shared&mode=rwc", path)
|
cfg := &OpenConfig{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
dsn := fmt.Sprintf("file:%s%s", path, cfg)
|
||||||
db, err := sql.Open("sqlite", dsn)
|
db, err := sql.Open("sqlite", dsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -28,6 +34,16 @@ func Open(path string) (*DB, error) {
|
||||||
return sqkv, err
|
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
|
// Get returns a value from the default bucket
|
||||||
func (d *DB) Get(key string) (string, error) {
|
func (d *DB) Get(key string) (string, error) {
|
||||||
b, err := d.Bucket(DefaultBucket)
|
b, err := d.Bucket(DefaultBucket)
|
||||||
|
|
29
sqkv_test.go
29
sqkv_test.go
|
@ -2,6 +2,7 @@ package sqkv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ func TestDefault(t *testing.T) {
|
||||||
|
|
||||||
db, err := Open(dbPath)
|
db, err := Open(dbPath)
|
||||||
assert.NoErr(err) // Should create database
|
assert.NoErr(err) // Should create database
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
err = db.Put("foo", "bar")
|
err = db.Put("foo", "bar")
|
||||||
assert.NoErr(err) // Should put kv
|
assert.NoErr(err) // Should put kv
|
||||||
|
@ -39,6 +41,7 @@ func TestBucket(t *testing.T) {
|
||||||
|
|
||||||
db, err := Open(dbPath)
|
db, err := Open(dbPath)
|
||||||
assert.NoErr(err) // Should create database
|
assert.NoErr(err) // Should create database
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
_, err = db.Bucket("honk")
|
_, err = db.Bucket("honk")
|
||||||
assert.True(errors.Is(err, ErrBucketDoesNotExist)) // Bucket does not exist; should error
|
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")
|
_, err = b.Get("foo")
|
||||||
assert.True(errors.Is(err, ErrKeyDoesNotExist))
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue