remote.go
package engines
import (
"database/sql"
"log"
"time"
"github.com/readysite/readysite/pkg/database"
"github.com/tursodatabase/go-libsql"
)
// RemoteOption configures a remote database
type RemoteOption func(*remoteConfig)
type remoteConfig struct {
syncInterval time.Duration
}
// WithSyncInterval sets the automatic sync interval.
// If not set, sync must be called manually.
func WithSyncInterval(d time.Duration) RemoteOption {
return func(c *remoteConfig) {
c.syncInterval = d
}
}
// NewRemote creates a new embedded replica database that syncs with a remote libSQL server.
// It maintains a local copy for fast reads while syncing writes to the primary.
//
// The localPath is where the local replica is stored.
// The primaryURL is the remote libSQL server URL (e.g., "libsql://db-name.turso.io").
// The authToken is the authentication token for the remote server.
//
// Example:
//
// db := engines.NewRemote(
// "./data/replica.db",
// os.Getenv("DB_URL"),
// os.Getenv("DB_TOKEN"),
// engines.WithSyncInterval(time.Minute),
// )
func NewRemote(localPath, primaryURL, authToken string, opts ...RemoteOption) *database.Database {
cfg := &remoteConfig{}
for _, opt := range opts {
opt(cfg)
}
// Build libsql options
libsqlOpts := []libsql.Option{
libsql.WithAuthToken(authToken),
}
if cfg.syncInterval > 0 {
libsqlOpts = append(libsqlOpts, libsql.WithSyncInterval(cfg.syncInterval))
}
connector, err := libsql.NewEmbeddedReplicaConnector(
localPath,
primaryURL,
libsqlOpts...,
)
if err != nil {
log.Fatal("Failed to create database connector:", err)
}
db := sql.OpenDB(connector)
return &database.Database{DB: db, Sync: syncer{connector}}
}
type syncer struct {
connector *libsql.Connector
}
func (s syncer) Sync() error {
_, err := s.connector.Sync()
return err
}