chore: add libsql driver
This commit is contained in:
		
							parent
							
								
									b1cc2af8d8
								
							
						
					
					
						commit
						0a4986d476
					
				
							
								
								
									
										120
									
								
								libsql_embed/open.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								libsql_embed/open.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
package libsqlembed
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"database/sql/driver"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/tursodatabase/go-libsql"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	sql.Register("libsql+embed", &db{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type db struct {
 | 
			
		||||
	conns map[string]connector
 | 
			
		||||
	mu    sync.RWMutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type connector struct {
 | 
			
		||||
	*libsql.Connector
 | 
			
		||||
	dsn    string
 | 
			
		||||
	dir    string
 | 
			
		||||
	driver *db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *connector) Close() error {
 | 
			
		||||
	c.driver.mu.Lock()
 | 
			
		||||
	delete(c.driver.conns, c.dsn)
 | 
			
		||||
	c.driver.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	defer os.RemoveAll(c.dir)
 | 
			
		||||
 | 
			
		||||
	if err := c.Connector.Sync(); err != nil {
 | 
			
		||||
		return fmt.Errorf("syncing database: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.Connector.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *db) OpenConnector(dsn string) (driver.Connector, error) {
 | 
			
		||||
	if c, ok := func() (connector, bool) {
 | 
			
		||||
		db.mu.RLock()
 | 
			
		||||
		defer db.mu.RUnlock()
 | 
			
		||||
		c, ok := db.conns[dsn]
 | 
			
		||||
		return c, ok
 | 
			
		||||
	}(); ok {
 | 
			
		||||
		return c, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	db.mu.Lock()
 | 
			
		||||
	defer db.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	u, err := url.Parse(dsn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var primary url.URL
 | 
			
		||||
	primary.Scheme = strings.TrimSuffix(u.Scheme, "+embed")
 | 
			
		||||
	primary.Host = u.Host
 | 
			
		||||
 | 
			
		||||
	dbname, _, _ := strings.Cut(u.Host, ".")
 | 
			
		||||
 | 
			
		||||
	authToken := u.Query().Get("authToken")
 | 
			
		||||
	if authToken == "" {
 | 
			
		||||
		return nil, fmt.Errorf("missing authToken")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	opts := []libsql.Option{
 | 
			
		||||
		libsql.WithAuthToken(authToken),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if refresh, err := strconv.ParseInt(u.Query().Get("refresh"),10,64); err == nil {
 | 
			
		||||
		opts = append(opts, libsql.WithSyncInterval(time.Duration(refresh)*time.Minute))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if readWrite, err := strconv.ParseBool(u.Query().Get("readYourWrites")); err == nil {
 | 
			
		||||
		opts = append(opts, libsql.WithReadYourWrites(readWrite))
 | 
			
		||||
	}
 | 
			
		||||
	if key := u.Query().Get("key"); key != "" {
 | 
			
		||||
		opts = append(opts, libsql.WithEncryption(key))
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	dir, err := os.MkdirTemp("", "libsql-*")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("creating temporary directory: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dbPath := filepath.Join(dir, dbname)
 | 
			
		||||
 | 
			
		||||
	c, err := libsql.NewEmbeddedReplicaConnector(
 | 
			
		||||
		dbPath,
 | 
			
		||||
		primary.String(),
 | 
			
		||||
		opts...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("creating connector: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	connector := connector{c, dsn, dir, db}
 | 
			
		||||
	db.conns[dsn] = connector
 | 
			
		||||
 | 
			
		||||
	return connector, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *db) Open(dsn string) (driver.Conn, error) {
 | 
			
		||||
	c, err := db.OpenConnector(dsn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return c.Connect(context.Background())
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user