dalgo2mysql

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 25, 2026 License: MIT Imports: 13 Imported by: 0

README

dalgo2mysql

MySQL-specific DALgo driver. Wraps github.com/dal-go/dalgo2sql to provide the dal.DB surface, and adds MySQL-native implementations of:

  • dbschema.SchemaReader — schema introspection via information_schema scoped to the connected database (DATABASE())
  • ddl.Applier — MySQL-flavored CREATE TABLE / CREATE INDEX / DROP TABLE / ALTER TABLE
  • dal.ConcurrencyAware — advertises SupportsConcurrentConnections() = true (MySQL supports concurrent connections from multiple goroutines and processes, unlike SQLite which serializes writers)

Constructor usage

import (
    "github.com/dal-go/dalgo/dal"
    "github.com/dal-go/dalgo2mysql"
    "github.com/dal-go/dalgo2sql"
)

// Minimal — no per-collection primary-key configuration.
db, err := dalgo2mysql.NewDatabase("user:pass@tcp(127.0.0.1:3306)/mydb?parseTime=true")

// With per-collection recordset options (required for Insert/Get/Delete with map[string]any data):
db, err := dalgo2mysql.NewDatabaseWithOptions(dsn, dal.NewSchema(nil, nil),
    dalgo2sql.DbOptions{
        Recordsets: map[string]*dalgo2sql.Recordset{
            "widgets": dalgo2sql.NewRecordset("widgets", dalgo2sql.Table,
                []dal.FieldRef{dal.Field("id")}),
        },
    })
if err != nil {
    return err
}
defer db.Close()

The DSN is in go-sql-driver/mysql format. Always include ?parseTime=true so DATETIME/TIMESTAMP columns scan into time.Time rather than []byte.

Type mapping

dbschema.Type MySQL column type
String VARCHAR(255) (or VARCHAR(n) when Length is set)
Int BIGINT
Float DOUBLE
Bool BOOLEAN (stored as tinyint(1))
Time DATETIME
Decimal DECIMAL (or DECIMAL(total, scale) when Precision is set)
Bytes BLOB

String always maps to VARCHAR, never TEXT: a VARCHAR(255) can serve as a PRIMARY KEY or index member under utf8mb4 on InnoDB, whereas TEXT/BLOB columns cannot be indexed without an explicit prefix length. This matters for the conventional id primary key, which is a String.

On introspection MySQL reports BOOLEAN columns as tinyint; dbschemaTypeFromMySQL maps tinyint back to dbschema.Bool.

Running the tests

The tests that touch a live database are gated on the DALGO2MYSQL_TEST_DSN environment variable. When it is not set, those tests are skipped so plain CI passes without a database.

Start a local MySQL 8.4 server (Docker). lower_case_table_names=0 keeps identifiers case-sensitive and case-preserving:

docker run -d \
  --name mysql84 \
  -e MYSQL_USER=ovdb \
  -e MYSQL_PASSWORD=ovdb \
  -e MYSQL_DATABASE=ovdb \
  -e MYSQL_ROOT_PASSWORD=ovdb \
  -p 13306:3306 \
  mysql:8.4 --lower_case_table_names=0

Then run the tests:

DALGO2MYSQL_TEST_DSN='ovdb:ovdb@tcp(127.0.0.1:13306)/ovdb?parseTime=true' \
    go test ./... -count=1 -v

MySQL driver: github.com/go-sql-driver/mysql (pure Go, CGO_ENABLED=0)

This package uses github.com/go-sql-driver/mysql — a pure-Go MySQL driver exposed through the standard database/sql interface (driver name "mysql"). No C toolchain is required; the package compiles with CGO_ENABLED=0.

Placeholder dialect

MySQL uses ? positional parameter markers, which is exactly dalgo2sql's default (PlaceholderQuestion). Unlike dalgo2postgres (which forces PlaceholderDollar for $1, $2, …), dalgo2mysql leaves dalgo2sql.DbOptions.Placeholder at its zero value.

Identifier case: preserved, not folded

Unlike PostgreSQL — which folds unquoted identifiers to lower case — MySQL with lower_case_table_names=0 preserves identifier case: table names are case-sensitive, and column names are case-insensitive but case-preserving. dalgo2mysql back-tick quotes identifiers in DDL (escaping embedded back-ticks by doubling) but does not lower-case them, so the bare identifiers that dalgo2sql's DML and dalgo's structured-query rendering emit already match the back-tick-quoted DDL. No case-folding workaround is needed.

DDL is non-transactional

MySQL implicitly commits the current transaction before and after every DDL statement (CREATE / DROP / ALTER), so schema changes cannot be rolled back atomically. SupportsTransactionalDDL() returns false (this differs from dalgo2postgres, which returns true). A multi-statement CreateCollection or AlterCollection that fails midway leaves earlier statements applied; callers that need clean recovery should drop the affected table.

Documentation

Overview

Package dalgo2mysql is the MySQL-specific DALgo driver.

It composes github.com/dal-go/dalgo2sql for the dal.DB read/write surface (transactions, recordset reader, Get/Set/Insert/Delete) and adds MySQL-native implementations of:

Index

Constants

View Source
const Version = "0.1.0"

Version is the dalgo2mysql package version. Updated by hand on each release; consumed by Adapter.Version().

Variables

This section is empty.

Functions

This section is empty.

Types

type Database

type Database struct {
	dal.ConcurrencyAvailable // SupportsConcurrentConnections() = true

	dal.DB // delegate for the dal.DB surface
	// contains filtered or unexported fields
}

Database is the dalgo2mysql driver instance. It implements dal.DB by embedding a dal.DB obtained from dalgo2sql.NewDatabase, and adds MySQL-specific dbschema, ddl, and concurrency surfaces.

The embedded dal.DB (rather than a named field) is what lets Database satisfy dal.DB itself: dal.DB is sealed by an unexported marker method, and embedding is the only way for that method to be promoted onto a decorating type — see dal.NewDB's doc comment.

Construct via NewDatabase. Database values are safe for concurrent use — the underlying MySQL server and go-sql-driver connection pool both support concurrent connections from multiple goroutines.

func NewDatabase

func NewDatabase(dsn string) (*Database, error)

NewDatabase opens a connection to the MySQL server identified by dsn using github.com/go-sql-driver/mysql (pure Go, CGO_ENABLED=0), pings to surface connectivity errors at construction time, wraps the *sql.DB via dalgo2sql.NewDatabase for the dal.DB surface, and returns a *Database that satisfies dal.DB + dal.ConcurrencyAware.

The dsn is in go-sql-driver/mysql format, e.g. "user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=true".

Use NewDatabaseWithOptions when you need to supply per-collection primary-key metadata (required for Insert/Get/Delete with map[string]any data).

func NewDatabaseWithOptions

func NewDatabaseWithOptions(dsn string, schema dal.Schema, opts dalgo2sql.DbOptions) (*Database, error)

NewDatabaseWithOptions is like NewDatabase but accepts a dal.Schema and dalgo2sql.DbOptions so callers can configure per-collection primary-key mappings required by Insert/Get/Delete operations.

Example — open a DB whose "widgets" table has "id" as its primary key:

db, err := dalgo2mysql.NewDatabaseWithOptions(dsn, dal.NewSchema(nil, nil),
    dalgo2sql.DbOptions{
        Recordsets: map[string]*dalgo2sql.Recordset{
            "widgets": dalgo2sql.NewRecordset("widgets", dalgo2sql.Table,
                []dal.FieldRef{dal.Field("id")}),
        },
    })

func (*Database) Adapter

func (d *Database) Adapter() dal.Adapter

Adapter returns the driver/version identifier.

func (*Database) AlterCollection

func (d *Database) AlterCollection(ctx context.Context, name string, ops ...ddl.AlterOp) error

AlterCollection applies ops in order. Because MySQL DDL auto-commits, ops are NOT applied atomically: a failure midway leaves earlier ops applied.

func (*Database) Close

func (d *Database) Close() error

Close closes the underlying *sql.DB. After Close the Database value is unusable; further method calls will fail with an error from database/sql.

func (*Database) CreateCollection

func (d *Database) CreateCollection(ctx context.Context, c dbschema.CollectionDef, opts ...ddl.Option) error

CreateCollection creates a table and its inline indexes.

Because MySQL DDL is auto-committing (non-transactional), a failure while creating an index leaves the table — and any previously created indexes — in place. Callers that need clean rollback should drop the table on error.

func (*Database) Delete

func (d *Database) Delete(ctx context.Context, key *dalrecord.Key) error

func (*Database) DeleteMulti

func (d *Database) DeleteMulti(ctx context.Context, keys []*dalrecord.Key) error

func (*Database) DescribeCollection

func (d *Database) DescribeCollection(ctx context.Context, ref *dal.CollectionRef) (*dbschema.CollectionDef, error)

DescribeCollection returns the full schema definition for the named table. It queries information_schema for columns and primary-key membership.

func (*Database) DropCollection

func (d *Database) DropCollection(ctx context.Context, name string, opts ...ddl.Option) error

DropCollection drops the table and all its indexes (MySQL drops table-owned indexes automatically).

func (*Database) ExecuteQueryToRecordsReader

func (d *Database) ExecuteQueryToRecordsReader(ctx context.Context, query dal.Query) (dal.RecordsReader, error)

func (*Database) ExecuteQueryToRecordsetReader

func (d *Database) ExecuteQueryToRecordsetReader(ctx context.Context, query dal.Query, opts ...recordset.Option) (dal.RecordsetReader, error)

func (*Database) Exists

func (d *Database) Exists(ctx context.Context, key *dalrecord.Key) (bool, error)

func (*Database) Get

func (d *Database) Get(ctx context.Context, record dalrecord.Record) error

func (*Database) GetMulti

func (d *Database) GetMulti(ctx context.Context, records []dalrecord.Record) error

func (*Database) ID

func (d *Database) ID() string

ID returns the driver-issued database ID (delegated to dalgo2sql).

func (*Database) Insert

func (d *Database) Insert(ctx context.Context, record dalrecord.Record, opts ...dal.InsertOption) error

func (*Database) ListCollections

func (d *Database) ListCollections(ctx context.Context, parent *dalrecord.Key) ([]dal.CollectionRef, error)

ListCollections returns user-defined base tables in the connected database (scoped to DATABASE()) in alphabetical order. The parent *dalrecord.Key is ignored — MySQL has a flat table namespace within a schema.

func (*Database) ListConstraints

func (d *Database) ListConstraints(ctx context.Context, ref *dal.CollectionRef) ([]dbschema.ConstraintDef, error)

ListConstraints returns a best-effort survey of constraints on the table via information_schema:

  • PRIMARY KEY constraint (one row if any PK columns exist)
  • UNIQUE constraints
  • FOREIGN KEY constraints

CHECK constraints are NOT enumerated here; read them from DescribeCollection if needed.

func (*Database) ListIndexes

func (d *Database) ListIndexes(ctx context.Context, ref *dal.CollectionRef) ([]dbschema.IndexDef, error)

ListIndexes returns the non-primary-key indexes on the named table via information_schema.statistics.

func (*Database) ListReferrers

func (d *Database) ListReferrers(ctx context.Context, ref *dal.CollectionRef) ([]dbschema.Referrer, error)

ListReferrers returns the collections that reference ref via foreign keys. It queries information_schema.key_column_usage for rows whose referenced_table_name is the named table.

func (*Database) RunReadonlyTransaction

func (d *Database) RunReadonlyTransaction(ctx context.Context, f dal.ROTxWorker, opts ...dal.TransactionOption) error

func (*Database) RunReadwriteTransaction

func (d *Database) RunReadwriteTransaction(ctx context.Context, f dal.RWTxWorker, opts ...dal.TransactionOption) error

func (*Database) Schema

func (d *Database) Schema() dal.Schema

Schema returns the dal-level Schema (delegated to dalgo2sql).

func (*Database) Set

func (d *Database) Set(ctx context.Context, record dalrecord.Record) error

func (*Database) SetMulti

func (d *Database) SetMulti(ctx context.Context, records []dalrecord.Record) error

func (*Database) SupportsConcurrentConnections added in v0.2.0

func (d *Database) SupportsConcurrentConnections() bool

SupportsConcurrentConnections reports MySQL's own concurrency behaviour (always true — see dal.ConcurrencyAvailable), not dalgo2sql's. An explicit method is required here: dal.ConcurrencyAvailable and the embedded dal.DB (whose Backend requirement embeds dal.ConcurrencyAware) both declare this method at the same promotion depth, which Go otherwise treats as an ambiguous selector.

func (*Database) SupportsTransactionalDDL

func (d *Database) SupportsTransactionalDDL() bool

SupportsTransactionalDDL reports that MySQL does NOT support transactional DDL. Unlike PostgreSQL, MySQL implicitly commits the current transaction before (and after) every DDL statement such as CREATE / DROP / ALTER, so DDL cannot be rolled back atomically. Callers must not rely on BEGIN/ROLLBACK to undo schema changes.

func (*Database) Update

func (d *Database) Update(ctx context.Context, key *dalrecord.Key, updates []update.Update, preconditions ...dal.Precondition) error

func (*Database) UpdateMulti

func (d *Database) UpdateMulti(ctx context.Context, keys []*dalrecord.Key, updates []update.Update, preconditions ...dal.Precondition) error

func (*Database) UpdateRecord

func (d *Database) UpdateRecord(ctx context.Context, record dalrecord.Record, updates []update.Update, preconditions ...dal.Precondition) error

UpdateRecord is not supported at the database level by dalgo2sql; use Update with an explicit key instead, or call UpdateRecord inside a RunReadwriteTransaction where the transaction object does support it.

func (*Database) Upsert

func (d *Database) Upsert(ctx context.Context, record dalrecord.Record) error

Jump to

Keyboard shortcuts

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