Skip to content

Commit

Permalink
SQLite3 support
Browse files Browse the repository at this point in the history
* SQLite3 caching support
  • Loading branch information
faabiosr committed Mar 14, 2018
1 parent 733702e commit d4c9b20
Show file tree
Hide file tree
Showing 6 changed files with 407 additions and 2 deletions.
8 changes: 7 additions & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
name = "gopkg.in/redis.v4"
version = "4.2.4"

[[constraint]]
name = "github.com/mattn/go-sqlite3"
version = "1.6.0"

[prune]
go-tests = true
unused-packages = true
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ configure:
test:
@go test -v .

test-coverage: configure
test-coverage:
@go test -coverprofile=cover.out -v .
@go tool cover -html=cover.out -o cover.html
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,25 @@ func init() {
}
```

### Sqlite3

```go
package main

import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
)

var cache cachego.Cache

func init() {
db, _ := sql.Open("sqlite3", "./cache.db")

cache, _ = NewSqlite3(db, "cache")
}
```

### Chain

```go
Expand Down
186 changes: 186 additions & 0 deletions sqlite3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package cachego

import (
"database/sql"
"fmt"
errors "github.com/pkg/errors"
"time"
)

type (
// Sqlite3 store for caching data
Sqlite3 struct {
db *sql.DB
table string
}
)

// NewSqlite3 - Create an instance of Sqlite3
func NewSqlite3(db *sql.DB, table string) (*Sqlite3, error) {
if err := createTable(db, table); err != nil {
return nil, errors.Wrap(err, "Unable to create database table")
}

return &Sqlite3{db, table}, nil
}

func createTable(db *sql.DB, table string) error {
stmt := `CREATE TABLE IF NOT EXISTS %s (
key text PRIMARY KEY,
value text NOT NULL,
lifetime integer NOT NULL
);`

_, err := db.Exec(fmt.Sprintf(stmt, table))

return err
}

// Check if cached key exists in SQL storage
func (s *Sqlite3) Contains(key string) bool {
if _, err := s.Fetch(key); err != nil {
return false
}

return true
}

// Delete the cached key from Sqlite3 storage
func (s *Sqlite3) Delete(key string) error {
tx, err := s.db.Begin()

if err != nil {
return errors.Wrap(err, "Unable to delete")
}

stmt, err := tx.Prepare(
fmt.Sprintf("DELETE FROM %s WHERE key = ?", s.table),
)

if err != nil {
return errors.Wrap(err, "Unable to delete")
}

defer stmt.Close()

_, err = stmt.Exec(key)

if err != nil {
return errors.Wrap(err, "Unable to delete")
}

tx.Commit()

return nil
}

// Retrieve the cached value from key of the Sqlite3 storage
func (s *Sqlite3) Fetch(key string) (string, error) {
stmt, err := s.db.Prepare(
fmt.Sprintf("SELECT value, lifetime FROM %s WHERE key = ?", s.table),
)

if err != nil {
return "", errors.Wrap(err, "Unable to retrieve the value")
}

defer stmt.Close()

var value string
var lifetime int64

err = stmt.QueryRow(key).Scan(&value, &lifetime)

if err != nil {
return "", errors.Wrap(err, "Unable to retrieve the value")
}

if lifetime == 0 {
return value, nil
}

if lifetime <= time.Now().Unix() {
s.Delete(key)

return "", errors.New("Cache expired")
}

return value, nil
}

// Retrieve multiple cached value from keys of the Sqlite3 storage
func (s *Sqlite3) FetchMulti(keys []string) map[string]string {
result := make(map[string]string)

for _, key := range keys {
if value, err := s.Fetch(key); err == nil {
result[key] = value
}
}

return result
}

// Remove all cached keys in Sqlite3 storage
func (s *Sqlite3) Flush() error {
tx, err := s.db.Begin()

if err != nil {
return errors.Wrap(err, "Unable to flush")
}

stmt, err := tx.Prepare(
fmt.Sprintf("DELETE FROM %s", s.table),
)

if err != nil {
return errors.Wrap(err, "Unable to flush")
}

defer stmt.Close()

_, err = stmt.Exec()

if err != nil {
return errors.Wrap(err, "Unable to flush")
}

tx.Commit()

return nil
}

// Save a value in Sqlite3 storage by key
func (s *Sqlite3) Save(key string, value string, lifeTime time.Duration) error {
duration := int64(0)

if lifeTime > 0 {
duration = time.Now().Unix() + int64(lifeTime.Seconds())
}

tx, err := s.db.Begin()

if err != nil {
return errors.Wrap(err, "Unable to save")
}

stmt, err := tx.Prepare(
fmt.Sprintf("INSERT OR REPLACE INTO %s (key, value, lifetime) VALUES (?, ?, ?)", s.table),
)

if err != nil {
return errors.Wrap(err, "Unable to save")
}

defer stmt.Close()

_, err = stmt.Exec(key, value, duration)

if err != nil {
return errors.Wrap(err, "Unable to save")
}

tx.Commit()

return nil
}
Loading

0 comments on commit d4c9b20

Please sign in to comment.