2015-05-11 07:45:31 +00:00
|
|
|
package builtin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2015-06-14 00:37:36 +00:00
|
|
|
"database/sql"
|
2015-05-11 07:45:31 +00:00
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
)
|
|
|
|
|
2015-06-14 00:37:36 +00:00
|
|
|
type Blob struct {
|
|
|
|
ID int64
|
|
|
|
Path string `sql:"unique:ux_blob_path"`
|
|
|
|
Data []byte
|
2015-05-11 07:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Blobstore struct {
|
2015-06-14 00:37:36 +00:00
|
|
|
*sql.DB
|
2015-05-11 07:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Del removes an object from the blobstore.
|
|
|
|
func (db *Blobstore) DelBlob(path string) error {
|
2015-06-14 00:37:36 +00:00
|
|
|
blob, _ := getBlob(db, rebind(stmtBlobSelectBlobPath), path)
|
|
|
|
if blob == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
_, err := db.Exec(rebind(stmtBlobDelete), blob.ID)
|
2015-05-11 07:45:31 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get retrieves an object from the blobstore.
|
|
|
|
func (db *Blobstore) GetBlob(path string) ([]byte, error) {
|
2015-06-14 00:37:36 +00:00
|
|
|
blob, err := getBlob(db, rebind(stmtBlobSelectBlobPath), path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return blob.Data, nil
|
2015-05-11 07:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlobReader retrieves an object from the blobstore.
|
|
|
|
// It is the caller's responsibility to call Close on
|
|
|
|
// the ReadCloser when finished reading.
|
|
|
|
func (db *Blobstore) GetBlobReader(path string) (io.ReadCloser, error) {
|
|
|
|
var blob, err = db.GetBlob(path)
|
|
|
|
var buf = bytes.NewBuffer(blob)
|
|
|
|
return ioutil.NopCloser(buf), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetBlob inserts an object into the blobstore.
|
|
|
|
func (db *Blobstore) SetBlob(path string, data []byte) error {
|
2015-06-14 00:37:36 +00:00
|
|
|
blob, _ := getBlob(db, rebind(stmtBlobSelectBlobPath), path)
|
|
|
|
if blob == nil {
|
|
|
|
blob = &Blob{}
|
|
|
|
}
|
2015-05-11 07:45:31 +00:00
|
|
|
blob.Path = path
|
2015-06-14 00:37:36 +00:00
|
|
|
blob.Data = data
|
|
|
|
if blob.ID == 0 {
|
|
|
|
return createBlob(db, rebind(stmtBlobInsert), blob)
|
|
|
|
}
|
|
|
|
return updateBlob(db, rebind(stmtBlobUpdate), blob)
|
2015-05-11 07:45:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetBlobReader inserts an object into the blobstore by
|
|
|
|
// consuming data from r until EOF.
|
|
|
|
func (db *Blobstore) SetBlobReader(path string, r io.Reader) error {
|
|
|
|
var data, _ = ioutil.ReadAll(r)
|
|
|
|
return db.SetBlob(path, data)
|
|
|
|
}
|
|
|
|
|
2015-06-14 00:37:36 +00:00
|
|
|
func NewBlobstore(db *sql.DB) *Blobstore {
|
2015-05-11 07:45:31 +00:00
|
|
|
return &Blobstore{db}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Blob table name in database.
|
|
|
|
const blobTable = "blobs"
|
|
|
|
|
|
|
|
const blobQuery = `
|
|
|
|
SELECT *
|
|
|
|
FROM blobs
|
|
|
|
WHERE blob_path = ?;
|
|
|
|
`
|
|
|
|
|
|
|
|
const blobDeleteStmt = `
|
|
|
|
DELETE FROM blobs
|
|
|
|
WHERE blob_path = ?;
|
|
|
|
`
|