Files
sqlite3/sqlite3reader/api.go

84 lines
2.0 KiB
Go
Raw Normal View History

2023-05-31 18:45:45 +01:00
// Package sqlite3reader implements an SQLite VFS for immutable databases.
//
// The "reader" [sqlite3vfs.VFS] permits accessing any [io.ReaderAt]
// as an immutable SQLite database.
//
// Importing package sqlite3reader registers the VFS.
//
// import _ "github.com/ncruces/go-sqlite3/sqlite3reader"
package sqlite3reader
import (
"io"
"io/fs"
"sync"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/sqlite3vfs"
)
func init() {
sqlite3vfs.Register("reader", vfs{})
}
var (
readerMtx sync.RWMutex
readerDBs = map[string]SizeReaderAt{}
)
// Create creates an immutable database from reader.
// The caller should insure that data from reader does not mutate,
// otherwise SQLite might return incorrect query results and/or [sqlite3.CORRUPT] errors.
func Create(name string, reader SizeReaderAt) {
readerMtx.Lock()
defer readerMtx.Unlock()
readerDBs[name] = reader
}
// Delete deletes a shared memory database.
func Delete(name string) {
readerMtx.Lock()
defer readerMtx.Unlock()
delete(readerDBs, name)
}
// A SizeReaderAt is a ReaderAt with a Size method.
// Use [NewSizeReaderAt] to adapt different Size interfaces.
type SizeReaderAt interface {
Size() (int64, error)
io.ReaderAt
}
// NewSizeReaderAt returns a SizeReaderAt given an io.ReaderAt
// that implements one of:
// - Size() (int64, error)
// - Size() int64
// - Len() int
// - Stat() (fs.FileInfo, error)
// - Seek(offset int64, whence int) (int64, error)
func NewSizeReaderAt(r io.ReaderAt) SizeReaderAt {
return sizer{r}
}
type sizer struct{ io.ReaderAt }
func (s sizer) Size() (int64, error) {
switch s := s.ReaderAt.(type) {
case interface{ Size() (int64, error) }:
return s.Size()
case interface{ Size() int64 }:
return s.Size(), nil
case interface{ Len() int }:
return int64(s.Len()), nil
case interface{ Stat() (fs.FileInfo, error) }:
fi, err := s.Stat()
if err != nil {
return 0, err
}
return fi.Size(), nil
case io.Seeker:
return s.Seek(0, io.SeekEnd)
}
return 0, sqlite3.IOERR_SEEK
}