move-migrations-to-option (#1)
Removes global variables and sets up migrations as optional. Reviewed-on: #1 Co-authored-by: Mason Payne <mason@masonitestudios.com> Co-committed-by: Mason Payne <mason@masonitestudios.com>main
parent
72df3adf0d
commit
b08636ba39
27
db.go
27
db.go
|
@ -16,25 +16,20 @@ type Migrations struct {
|
|||
|
||||
type Options func(*LibSqlDB) error
|
||||
|
||||
// use something like this in the user's code -> //go:embed migrations/*.sql
|
||||
var _migrationFiles embed.FS
|
||||
|
||||
var migrations []Migrations
|
||||
|
||||
// func NewLibSqlDB is defined in embedded.go and remote-only.go files
|
||||
// these files are used to define the LibSqlDB struct and the NewLibSqlDB function
|
||||
// they have different initializations based on the environment, embedded or remote-only
|
||||
// Windows does not currently support the embedded database, so the remote-only file is used
|
||||
|
||||
// setupMigrations initializes the filesystem and reads the migration files into the migrations variable
|
||||
func setupMigrations() error {
|
||||
func (t *LibSqlDB) setupMigrations() error {
|
||||
// Walk through the embedded files and read their contents
|
||||
err := fs.WalkDir(_migrationFiles, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
err := fs.WalkDir(t.migrationFiles, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !d.IsDir() {
|
||||
content, err := _migrationFiles.ReadFile(path)
|
||||
content, err := t.migrationFiles.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -43,7 +38,7 @@ func setupMigrations() error {
|
|||
name: filepath.Base(path),
|
||||
query: string(content),
|
||||
}
|
||||
migrations = append(migrations, migration)
|
||||
t.migrations = append(t.migrations, migration)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
@ -55,6 +50,10 @@ func setupMigrations() error {
|
|||
|
||||
// Migrate updates the connected LibSqlDB to the latest schema based on the given migrations
|
||||
func (t *LibSqlDB) Migrate() error {
|
||||
if !t.useMigrations {
|
||||
return fmt.Errorf("migrations not enabled")
|
||||
}
|
||||
|
||||
// check if migration table exists
|
||||
var migrationsCheck string
|
||||
//goland:noinspection SqlResolve
|
||||
|
@ -70,7 +69,7 @@ func (t *LibSqlDB) Migrate() error {
|
|||
}
|
||||
}
|
||||
|
||||
for _, migration := range migrations {
|
||||
for _, migration := range t.migrations {
|
||||
var migrationInHistory string
|
||||
err = t.DB.QueryRow("SELECT name FROM migrations WHERE name = ?", migration.name).Scan(&migrationInHistory)
|
||||
if err != nil {
|
||||
|
@ -138,3 +137,11 @@ func WithReadYourWrites(readYourWrites bool) Options {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithMigrationFiles(migrationFiles embed.FS) Options {
|
||||
return func(l *LibSqlDB) error {
|
||||
l.useMigrations = true
|
||||
l.migrationFiles = migrationFiles
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
17
embedded.go
17
embedded.go
|
@ -22,15 +22,14 @@ type LibSqlDB struct {
|
|||
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
|
||||
}
|
||||
|
||||
var syncInterval = 200 * time.Millisecond
|
||||
|
||||
func NewLibSqlDB(primaryUrl string, migrationFiles embed.FS, opts ...Options) (*LibSqlDB, error) {
|
||||
func NewLibSqlDB(primaryUrl string, opts ...Options) (*LibSqlDB, error) {
|
||||
l := libSqlDefaults()
|
||||
|
||||
_migrationFiles = migrationFiles
|
||||
|
||||
for _, option := range opts {
|
||||
err := option(l)
|
||||
if err != nil {
|
||||
|
@ -74,9 +73,11 @@ func NewLibSqlDB(primaryUrl string, migrationFiles embed.FS, opts ...Options) (*
|
|||
|
||||
db := sql.OpenDB(connector)
|
||||
|
||||
err = setupMigrations()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting up migrations | %w", err)
|
||||
if l.useMigrations {
|
||||
err = l.setupMigrations()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting up migrations | %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
l.DB = db
|
||||
|
|
|
@ -17,9 +17,9 @@ func main() {
|
|||
// Open the database
|
||||
tdb, err := libsqldb.NewLibSqlDB(
|
||||
primaryUrl,
|
||||
migrationFiles,
|
||||
libsqldb.WithMigrationFiles(migrationFiles),
|
||||
libsqldb.WithAuthToken(authToken),
|
||||
libsqldb.WithLocalDBName("local.db"),
|
||||
libsqldb.WithLocalDBName("local.db"), // will not be used for remote-only
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to open db %s: %s", primaryUrl, err)
|
||||
|
|
|
@ -32,15 +32,6 @@ tdb, err := libsqldb.NewLibSqlDB(
|
|||
## Why Use This Library?
|
||||
I developed this library to streamline the process of setting up a database connection in Go, complete with built-in migration capabilities. During development, I encountered issues with using the embedded driver on Windows. As I researched, I discovered [others had similar issues](https://github.com/tursodatabase/go-libsql/issues/30). This wrapper solves that problem by automatically selecting the appropriate driver based on your operating system.
|
||||
|
||||
## How to Use
|
||||
For a complete example, check out the examples/basic-usage directory in this repository.
|
||||
|
||||
Before running your application, make sure to set the following environment variables:
|
||||
|
||||
```bash
|
||||
LIBSQL_AUTH_TOKEN
|
||||
LIBSQL_DATABASE_URL
|
||||
```
|
||||
|
||||
### Special Note for Windows Users
|
||||
This library defaults to using the embedded driver for better performance and closer parity with production environments. However, due to the lack of support for embedded LibSQL on Windows, this library uses a remote driver when running on Windows. Special build tags are included to ensure seamless operation across platforms.
|
||||
|
|
|
@ -21,13 +21,14 @@ type LibSqlDB struct {
|
|||
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, migrationFiles embed.FS, opts ...Options) (*LibSqlDB, error) {
|
||||
func NewLibSqlDB(primaryUrl string, opts ...Options) (*LibSqlDB, error) {
|
||||
l := &LibSqlDB{}
|
||||
|
||||
_migrationFiles = migrationFiles
|
||||
|
||||
for _, option := range opts {
|
||||
err := option(l)
|
||||
if err != nil {
|
||||
|
@ -45,14 +46,16 @@ func NewLibSqlDB(primaryUrl string, migrationFiles embed.FS, opts ...Options) (*
|
|||
return nil, fmt.Errorf("error setting up LibSQL db | %w", err)
|
||||
}
|
||||
|
||||
err = setupMigrations()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting up migrations | %w", err)
|
||||
if l.useMigrations {
|
||||
err = l.setupMigrations()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting up migrations | %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &LibSqlDB{
|
||||
DB: db,
|
||||
}, nil
|
||||
l.DB = db
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (t *LibSqlDB) Close() error {
|
||||
|
|
Loading…
Reference in New Issue