libsqldb/embedded.go

117 lines
2.7 KiB
Go

//go:build !windows
package libsqldb
import (
"database/sql"
"embed"
"fmt"
"github.com/hashicorp/go-multierror"
"github.com/tursodatabase/go-libsql"
"os"
"path/filepath"
"time"
)
type LibSqlDB struct {
DB *sql.DB
connector *libsql.Connector // only used for embedded replica
dir string // only used for embedded replica
localDBName string // only used for embedded replica
authToken string
syncInterval time.Duration // only used for embedded replica
encryptionKey string // only used for embedded replica
readYourWrites *bool // only used for embedded replica
useMigrations bool
migrationFiles embed.FS
migrations []migrations
}
func NewLibSqlDB(primaryUrl string, opts ...Options) (*LibSqlDB, error) {
l := libSqlDefaults()
for _, option := range opts {
err := option(l)
if err != nil {
return nil, fmt.Errorf("error applying options | %w", err)
}
}
dir, err := os.MkdirTemp("", "libsql-*")
if err != nil {
fmt.Println("Error creating temporary directory:", err)
return nil, fmt.Errorf("error setting up temporary directory for local database | %w", err)
}
//defer os.RemoveAll(dir)
dbPath := filepath.Join(dir, l.localDBName)
var lsOpts []libsql.Option
if l.authToken != "" {
lsOpts = append(lsOpts, libsql.WithAuthToken(l.authToken))
}
if l.syncInterval != 0 {
lsOpts = append(lsOpts, libsql.WithSyncInterval(l.syncInterval))
}
if l.encryptionKey != "" {
lsOpts = append(lsOpts, libsql.WithEncryption(l.encryptionKey))
}
if l.readYourWrites != nil {
lsOpts = append(lsOpts, libsql.WithReadYourWrites(*l.readYourWrites))
}
connector, err := libsql.NewEmbeddedReplicaConnector(dbPath, primaryUrl,
lsOpts...,
)
if err != nil {
return nil, fmt.Errorf("error creating connector | %w", err)
}
db := sql.OpenDB(connector)
if l.useMigrations {
err = l.setupMigrations()
if err != nil {
return nil, fmt.Errorf("error setting up migrations | %w", err)
}
}
l.DB = db
l.connector = connector
l.dir = dir
return l, nil
}
func libSqlDefaults() *LibSqlDB {
return &LibSqlDB{
localDBName: "local.db",
}
}
func (t *LibSqlDB) Close() error {
var resultError *multierror.Error
if err := t.DB.Close(); err != nil {
resultError = multierror.Append(resultError, fmt.Errorf("failed to close database: %w", err))
}
if t.connector != nil {
if err := t.connector.Close(); err != nil {
resultError = multierror.Append(resultError, fmt.Errorf("failed to close connector: %w", err))
}
}
if t.dir != "" {
if err := os.RemoveAll(t.dir); err != nil {
resultError = multierror.Append(resultError, fmt.Errorf("failed to remove directory %s: %w", t.dir, err))
}
}
return resultError.ErrorOrNil()
}