godolt

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 10 Imported by: 0

README

godolt

Go CI Go Lint Go SAST Docs Docs Visualization License

godolt wraps Dolt's operational surface for Go programs, following the gogit precedent — a standalone, dependency-light service-integration module.

Design: SQL-first. The primary workload is many concurrent sessions against dolt sql-server (the embedded driver sustains only one stable connection and is not a target), so version-control verbs — remotes, push, pull, fetch, active branch — run as Dolt stored procedures over the same MySQL wire as queries. The caller supplies the *sql.DB and godolt adds zero driver dependencies. The few operations that cannot run over the wire — clone/init bootstrap, server lifecycle, backups — shell out to the dolt CLI.

db, _ := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/mydb")
client := godolt.New(db)

if err := client.RemoteAdd(ctx, "origin", "file:///path/to/remote"); err != nil {
    log.Fatal(err)
}
msg, err := client.Push(ctx, "origin", "main")

Library Features

Feature Entry Point Description
Client New(db *sql.DB) Wraps an existing *sql.DB connection to a dolt sql-server; the caller owns the driver, pooling, and DSN
Remotes Client.RemoteAdd, Client.RemoteRemove, Client.Remotes Register, remove, and list configured remotes (CALL DOLT_REMOTE(...))
Sync Client.Push, Client.Fetch Push/fetch against a remote (CALL DOLT_PUSH/DOLT_FETCH), returning the server's status message
Sync Client.Pull Pull and merge a remote's branch (CALL DOLT_PULL); returns *PullResult (FastForward, Conflicts, Message) — a non-zero Conflicts means the merge completed but left conflict rows in dolt_conflicts_<table> for the caller to resolve
Branch Client.ActiveBranch The connection's active branch (SELECT active_branch())
Commits Client.HasUncommittedChanges, Client.AddAll, Client.Commit, Client.CommitAll Dirty-status check (dolt_status), stage all (CALL DOLT_ADD('.')), and commit (CALL DOLT_COMMIT) returning the new hash; CommitAll is a no-op on a clean working set — the pattern applications use to wrap sync runs in Dolt commits
Databases CreateDatabase(ctx, db, name) CREATE DATABASE IF NOT EXISTS over a server-wide connection (no database selected — see SplitDSN)
DSN helpers LocalDSN, EnsureParseTime, SplitDSN Build the conventional local-server DSN, append parseTime=true for ORMs like Ent, and split a DSN into its server-wide base and database name
Server lifecycle ServerReachable, StartServer, EnsureServer Probe an address, launch dolt sql-server over a data directory and wait for readiness (caller owns the process), or ensure one is serving — launching detached if not (the shared local-server pattern)
Bootstrap Clone(ctx, remoteURL, dir), InitDir(ctx, dir, name, email) Cold-path operations that shell out to the dolt CLI, since no server exists yet to talk to
Availability Available() Reports whether the dolt CLI is on PATH — the cold path's prerequisite
Backups BackupAdd, BackupSync, BackupRestore Named backup targets, snapshot/sync, and restore — no DOLT_BACKUP stored procedure exists, so these are CLI-exec only. Verified safe to run against a directory a live dolt sql-server is actively serving

Installation

go get github.com/grokify/godolt

Usage

SQL-wire operations (the primary workload)
import (
	"context"
	"database/sql"

	"github.com/grokify/godolt"
	_ "github.com/go-sql-driver/mysql"
)

db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/mydb")
if err != nil {
	log.Fatal(err)
}
client := godolt.New(db)

ctx := context.Background()
if err := client.RemoteAdd(ctx, "origin", "file:///path/to/remote"); err != nil {
	log.Fatal(err)
}

remotes, err := client.Remotes(ctx)

msg, err := client.Push(ctx, "origin", "main")

// Push is fast-forward-only: a remote with commits the local branch
// doesn't have rejects the push (error contains "non-fast-forward").
// Pull to fetch and merge before pushing again.
result, err := client.Pull(ctx, "origin", "main")
if result.Conflicts > 0 {
	// Merge completed; resolve dolt_conflicts_<table> rows before pushing.
}

branch, err := client.ActiveBranch(ctx)
Application store pattern (server lifecycle + commits)

The pattern shared by visionstudio, omniroadmap, and uiforge: ensure a long-lived local dolt sql-server over a data directory, create the app's database, connect with Ent (or any MySQL client), and wrap write runs in Dolt commits.

// Ensure a shared local server is running (launches detached if not).
if err := godolt.EnsureServer("/path/to/data", 13307); err != nil {
	log.Fatal(err)
}

// Create the database if needed, connecting server-wide first.
dsn := godolt.EnsureParseTime(godolt.LocalDSN(13307, "myapp"))
base, dbName, err := godolt.SplitDSN(dsn)
if err != nil {
	log.Fatal(err)
}
serverDB, err := sql.Open("mysql", base)
if err != nil {
	log.Fatal(err)
}
if err := godolt.CreateDatabase(ctx, serverDB, dbName); err != nil {
	log.Fatal(err)
}
_ = serverDB.Close()

// Connect to the database and wrap work in a Dolt commit.
db, err := sql.Open("mysql", dsn)
if err != nil {
	log.Fatal(err)
}
client := godolt.New(db)
// ... write rows ...
hash, err := client.CommitAll(ctx, "sync run 2026-08-19")
if err != nil {
	log.Fatal(err)
}
if hash == "" {
	// Clean working set — nothing to commit.
}
Cold path: bootstrap and backups
if !godolt.Available() {
	log.Fatal("dolt CLI not found on PATH")
}

if err := godolt.InitDir(ctx, "/path/to/db", "my-service", "my-service@local"); err != nil {
	log.Fatal(err)
}

if err := godolt.Clone(ctx, "file:///path/to/remote", "/path/to/clone"); err != nil {
	log.Fatal(err)
}

if err := godolt.BackupAdd(ctx, "/path/to/db", "spike", "file:///path/to/backup"); err != nil {
	log.Fatal(err)
}
if err := godolt.BackupSync(ctx, "/path/to/db", "spike"); err != nil {
	log.Fatal(err)
}

Documentation

Full docs, including release notes, are published at grokify.github.io/godolt.

License

MIT

Documentation

Overview

Package godolt wraps Dolt's operational surface for Go programs, following the gogit precedent (a standalone service-integration module).

Design: SQL-first. The primary workload is many concurrent sessions against `dolt sql-server` (the embedded driver sustains only one stable connection and is not a target), so version-control verbs run as Dolt stored procedures over the same MySQL wire as queries — the caller supplies the *sql.DB and godolt adds zero driver dependencies. The few operations that cannot run over the wire (clone/init bootstrap, server lifecycle) shell out to the dolt CLI (exec.go).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Available

func Available() bool

Available reports whether the dolt CLI is on PATH (the cold path's prerequisite; the SQL path needs only a *sql.DB).

func BackupAdd

func BackupAdd(ctx context.Context, dir, name, url string) error

BackupAdd registers a named backup target for the Dolt database in dir.

func BackupRestore

func BackupRestore(ctx context.Context, workDir, url, dbName string, force bool) error

BackupRestore restores a database from a backup URL into a new subdirectory named dbName under workDir (workDir must not already contain a directory of that name unless force is set).

func BackupSync

func BackupSync(ctx context.Context, dir, name string) error

BackupSync snapshots the Dolt database in dir (branches, tags, working sets) and uploads it to the named backup target.

func Clone

func Clone(ctx context.Context, remoteURL, dir string) error

Clone clones a remote URL into dir (dir must not already contain a Dolt repository).

func CreateDatabase added in v0.3.0

func CreateDatabase(ctx context.Context, db *sql.DB, name string) error

CreateDatabase creates the named database if it does not exist. The caller supplies a *sql.DB connected server-wide (no database selected — see SplitDSN); godolt adds no driver dependency.

func EnsureParseTime added in v0.3.0

func EnsureParseTime(dsn string) string

EnsureParseTime appends parseTime=true to a MySQL DSN if absent. ORMs such as Ent need it to scan DATETIME columns into time.Time.

func EnsureServer added in v0.3.0

func EnsureServer(dataDir string, port int) error

EnsureServer checks that a dolt sql-server is reachable on 127.0.0.1:port, launching one as a detached subprocess over dataDir if not. The launched process keeps serving after the caller exits — suitable for local developer tools that share one long-lived server (the visionstudio/omniroadmap pattern).

func InitDir

func InitDir(ctx context.Context, dir, name, email string) error

InitDir initializes a new Dolt database directory with the given committer identity.

func LocalDSN added in v0.3.0

func LocalDSN(port int, database string) string

LocalDSN returns the conventional DSN for a local dolt sql-server: root with no password on 127.0.0.1.

func ServerReachable added in v0.3.0

func ServerReachable(addr string) bool

ServerReachable reports whether a TCP listener answers on addr (host:port) within 500ms.

func SplitDSN added in v0.3.0

func SplitDSN(dsn string) (base string, database string, err error)

SplitDSN splits a go-sql-driver DSN into the DSN without a database selected (still carrying any query parameters) and the database name. Use it to connect server-wide before the target database exists.

func StartServer added in v0.3.0

func StartServer(dataDir string, port int) (*exec.Cmd, error)

StartServer launches `dolt sql-server` over dataDir on 127.0.0.1:port, creating dataDir if needed, and waits until the server accepts connections. The caller owns the returned process: Wait on it, kill it, or detach. Requires the dolt binary on PATH.

Types

type Client

type Client struct {
	DB *sql.DB
}

Client executes Dolt operations over an existing SQL connection to a dolt sql-server. The caller owns the *sql.DB (driver, pooling, DSN).

func New

func New(db *sql.DB) *Client

New returns a Client over db.

func (*Client) ActiveBranch

func (c *Client) ActiveBranch(ctx context.Context) (string, error)

ActiveBranch returns the connection's active branch.

func (*Client) AddAll added in v0.3.0

func (c *Client) AddAll(ctx context.Context) error

AddAll stages all working-set changes (CALL DOLT_ADD('.')).

func (*Client) Commit added in v0.3.0

func (c *Client) Commit(ctx context.Context, message string) (hash string, err error)

Commit commits staged changes (CALL DOLT_COMMIT('-m', message)) and returns the new commit hash. The message is passed as a bind parameter, so it may contain any characters. Committing with nothing staged returns an error from Dolt; use CommitAll for no-op-when-clean semantics.

func (*Client) CommitAll added in v0.3.0

func (c *Client) CommitAll(ctx context.Context, message string) (hash string, err error)

CommitAll stages and commits all changes with the given message, returning the new commit hash. A clean working set is a no-op returning ("", nil) — the pattern applications use to wrap sync runs in Dolt commits.

func (*Client) Fetch

func (c *Client) Fetch(ctx context.Context, remote string) error

Fetch fetches from remote (CALL DOLT_FETCH).

func (*Client) HasUncommittedChanges added in v0.3.0

func (c *Client) HasUncommittedChanges(ctx context.Context) (bool, error)

HasUncommittedChanges reports whether the working set has staged or unstaged changes (any rows in dolt_status).

func (*Client) Pull

func (c *Client) Pull(ctx context.Context, remote, branch string) (*PullResult, error)

Pull pulls branch from remote (CALL DOLT_PULL) and merges into the active branch. DOLT_PULL returns three columns (fast_forward, conflicts, message) — a different shape from every other stored procedure call() handles, so Pull scans it directly rather than going through call(). A non-zero Conflicts count means DOLT_PULL completed the merge but left conflict rows in dolt_conflicts_<table> for the caller to resolve; it is not returned as an error, since that is expected, resolvable local state, not a failure of the pull itself.

func (*Client) Push

func (c *Client) Push(ctx context.Context, remote, branch string) (string, error)

Push pushes branch to remote (CALL DOLT_PUSH). Returns the server message (e.g. "Everything up-to-date").

func (*Client) RemoteAdd

func (c *Client) RemoteAdd(ctx context.Context, name, url string) error

RemoteAdd registers a remote (CALL DOLT_REMOTE('add', name, url)).

func (*Client) RemoteRemove

func (c *Client) RemoteRemove(ctx context.Context, name string) error

RemoteRemove removes a remote.

func (*Client) Remotes

func (c *Client) Remotes(ctx context.Context) ([]Remote, error)

Remotes lists configured remotes from the dolt_remotes system table.

type PullResult added in v0.2.0

type PullResult struct {
	FastForward bool
	Conflicts   int
	Message     string
}

PullResult reports the outcome of a CALL DOLT_PULL.

type Remote

type Remote struct {
	Name string
	URL  string
}

Remote is a configured Dolt remote.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL