{"id":35038047,"url":"https://github.com/padurean/gosmig","last_synced_at":"2025-12-27T08:04:05.646Z","repository":{"id":319371849,"uuid":"1071034239","full_name":"padurean/gosmig","owner":"padurean","description":"Simple, minimal SQL database migrations written in Go. Build your own migration CLI with it. Std lib database/sql and SQLX supported out of the box.","archived":false,"fork":false,"pushed_at":"2025-11-02T20:10:12.000Z","size":2816,"stargazers_count":71,"open_issues_count":0,"forks_count":5,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-02T22:07:56.140Z","etag":null,"topics":["database","database-migrate-ext","database-migration","database-migrations","db-migrate","db-migration","db-migrations","dbmigrate","dbmigration","dbmigrator","go","golang","rdbms","sql"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/padurean.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-06T19:18:25.000Z","updated_at":"2025-11-02T20:08:55.000Z","dependencies_parsed_at":"2025-10-18T23:14:14.976Z","dependency_job_id":"43ab9bc6-4b65-4ba0-846f-df48a2693f0e","html_url":"https://github.com/padurean/gosmig","commit_stats":null,"previous_names":["padurean/gosmig"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/padurean/gosmig","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/padurean%2Fgosmig","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/padurean%2Fgosmig/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/padurean%2Fgosmig/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/padurean%2Fgosmig/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/padurean","download_url":"https://codeload.github.com/padurean/gosmig/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/padurean%2Fgosmig/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28075695,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-27T02:00:05.897Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","database-migrate-ext","database-migration","database-migrations","db-migrate","db-migration","db-migrations","dbmigrate","dbmigration","dbmigrator","go","golang","rdbms","sql"],"created_at":"2025-12-27T08:03:58.085Z","updated_at":"2025-12-27T08:04:05.634Z","avatar_url":"https://github.com/padurean.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"https://raw.githubusercontent.com/padurean/gosmig/e52c9cc1e4a04ee418aef7936966c06e621ee265/graphics/gosmig-banner.png\" title=\"GoSMig\" alt=\"GoSMig logo\" /\u003e\n\n[![Coverage](https://img.shields.io/badge/coverage-100%25-limegreen?style=flat\u0026labelColor=black\u0026logo=go\u0026logoColor=white\u0026logoSize=auto)](https://github.com/padurean/gosmig/actions/workflows/checks.yml)\n[![Go Test](https://github.com/padurean/gosmig/actions/workflows/checks.yml/badge.svg)](https://github.com/padurean/gosmig/actions/workflows/checks.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/padurean/gosmig)](https://goreportcard.com/report/github.com/padurean/gosmig)\n[![Go Reference](https://pkg.go.dev/badge/github.com/padurean/gosmig.svg)](https://pkg.go.dev/github.com/padurean/gosmig)\n[![License: Unlicense](https://img.shields.io/badge/license-Unlicense-blue.svg)](http://unlicense.org/)\n\n**GoSMig** \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; ☆⋆｡𖦹°‧★🛸\n\nSimple, minimal SQL migrations written in Go.\n\nBuild your own migration CLI with it.\n\nStandard library [**`database/sql`**](https://pkg.go.dev/database/sql) and [**`sqlx`**](https://github.com/jmoiron/sqlx) supported out of the box.\n\nSee the [examples](https://github.com/padurean/gosmig/tree/examples) for usage with both.\n\nCan be used with any database library that implements the standard interfaces.\n\n**GoSMig 💫 in action:**\n\u003cimg src=\"https://raw.githubusercontent.com/padurean/gosmig/877ff597533e76a80deb88dfacbdd18a8a4b5e43/gosmig-demo.svg\" title=\"GoSMig demo\" alt=\"GoSMig demo\" /\u003e\n\n## Features\n\n- [x] **Database Agnostic** - Works with any database that implements a subset of Go's standard `database/sql` interfaces (see the  [Core Types](#core-types) section lower for more details)\n- [x] **Type-Safe** - Full Go generics support for compile-time type safety\n- [x] **Flexible** - Supports both transactional and non-transactional migrations\n- [x] **Simple** - Minimal API with clear semantics\n- [x] **CLI-Ready** - No actual CLI is provided, but a built-in command-line interface handler makes it easy to build your own CLI tool\n- [x] **Timeouts** - Configurable operation timeouts\n- [x] **Robust Error Handling** - Validation, version conflict detection, transaction safety, and clear error messages\n- [x] **Rollback Support** - Safe migration rollbacks\n- [x] **Status Tracking** - View migration status with paging support\n- [x] **Tested** - Comprehensive test suite with PostgreSQL integration tests\n- [x] **Zero Dependencies** - No external dependencies, only the Go standard library (and [golang.org/x/term](https://pkg.go.dev/golang.org/x/term) for pager support - i.e. for pagination - in the `status` command output)\n\n**ℹ️ NOTEs**:\n\n- You will need a database driver (e.g., [**`pgx`**](https://github.com/jackc/pgx) for PostgreSQL) and optionally [**`sqlx`**](https://github.com/jmoiron/sqlx).\n- These are not dependencies of gosmig itself: while [**`pgx`**](https://github.com/jackc/pgx) and [**`sqlx`**](https://github.com/jmoiron/sqlx) show up in [go.mod](go.mod), they are used only in the examples and tests - gosmig does not actually depend on them.\n\n## Installation\n\n```bash\ngo get github.com/padurean/gosmig\n```\n\n## Quick Start\n\n### Example with [**`database/sql`**](https://pkg.go.dev/database/sql)\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"database/sql\"\n    \"log\"\n    \"time\"\n\n    _ \"github.com/jackc/pgx/v5/stdlib\"\n    \"github.com/padurean/gosmig\"\n)\n\nfunc main() {\n    // Define your migrations\n    migrations := []gosmig.MigrationSQL{\n        {\n            Version: 1,\n            UpDown: \u0026gosmig.UpDownSQL{\n                Up: func(ctx context.Context, tx *sql.Tx) error {\n                    _, err := tx.ExecContext(ctx, `\n                        CREATE TABLE users (\n                            id SERIAL PRIMARY KEY,\n                            name TEXT NOT NULL,\n                            email TEXT UNIQUE NOT NULL,\n                            created_at TIMESTAMPTZ DEFAULT NOW()\n                        )`)\n                    return err\n                },\n                Down: func(ctx context.Context, tx *sql.Tx) error {\n                    _, err := tx.ExecContext(ctx, `DROP TABLE users`)\n                    return err\n                },\n            },\n        },\n        {\n            Version: 2,\n            UpDownNoTX: \u0026gosmig.UpDownNoTXSQL{\n                Up: func(ctx context.Context, db *sql.DB) error {\n                    _, err := db.ExecContext(ctx, `CREATE INDEX CONCURRENTLY idx_users_created_at ON users (created_at)`)\n                    return err\n                },\n                Down: func(ctx context.Context, db *sql.DB) error {\n                    _, err := db.ExecContext(ctx, `DROP INDEX CONCURRENTLY IF EXISTS idx_users_created_at`)\n                    return err\n                },\n            },\n        },\n    }\n\n    // Create the migration tool\n    migrate, err := gosmig.New(migrations, connectToDB, nil)\n    if err != nil {\n        log.Fatalf(\"Failed to create migration tool: %v\", err)\n    }\n\n    // Run migrations - handles CLI arguments automatically\n    migrate()\n}\n\nfunc connectToDB(url string, timeout time.Duration) (*sql.DB, error) {\n    db, err := sql.Open(\"pgx\", url)\n    if err != nil {\n        return nil, err\n    }\n\n    ctx, cancel := context.WithTimeout(context.Background(), timeout)\n    defer cancel()\n\n    if err := db.PingContext(ctx); err != nil {\n        return nil, err\n    }\n\n    return db, nil\n}\n```\n\n### Example with [**`sqlx`**](https://github.com/jmoiron/sqlx)\n\nVery similar with the [**`database/sql`**](https://pkg.go.dev/database/sql) example above,\nbut with the following changes:\n\n- define 2 type aliases:\n  - `MigrationSQLX  = gosmig.Migration[*sql.Row, sql.Result, *sql.Tx, *sql.TxOptions, *sqlx.DB]`\n  - `UpDownNoTXSQLX = gosmig.UpDown[*sql.Row, sql.Result, *sqlx.DB]`\n- replace `sql.DB` with `sqlx.DB` and `sql.Open` with `sqlx.Open`\n\nFull example:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"database/sql\"\n    \"log\"\n    \"time\"\n\n    _ \"github.com/jackc/pgx/v5/stdlib\"\n    \"github.com/jmoiron/sqlx\"\n    \"github.com/padurean/gosmig\"\n)\n\nfunc main() {\n    // Define type aliases for convenience\n    type (\n        MigrationSQLX  = gosmig.Migration[*sql.Row, sql.Result, *sql.Tx, *sql.TxOptions, *sqlx.DB]\n        UpDownNoTXSQLX = gosmig.UpDown[*sql.Row, sql.Result, *sqlx.DB]\n    )\n\n    migrations := []MigrationSQLX{\n        {\n            Version: 1,\n            UpDown: \u0026gosmig.UpDownSQL{ // Note: UpDownSQL works for both stdlib and sqlx\n                Up: func(ctx context.Context, tx *sql.Tx) error {\n                    _, err := tx.ExecContext(ctx, `CREATE TABLE products (id SERIAL PRIMARY KEY, name TEXT)`)\n                    return err\n                },\n                Down: func(ctx context.Context, tx *sql.Tx) error {\n                    _, err := tx.ExecContext(ctx, `DROP TABLE products`)\n                    return err\n                },\n            },\n        },\n        {\n            Version: 2,\n            UpDownNoTX: \u0026UpDownNoTXSQLX{\n                Up: func(ctx context.Context, db *sqlx.DB) error {\n                    _, err := db.ExecContext(ctx, `CREATE INDEX CONCURRENTLY idx_users_created_at ON users (created_at)`)\n                    return err\n                },\n                Down: func(ctx context.Context, db *sqlx.DB) error {\n                    _, err := db.ExecContext(ctx, `DROP INDEX CONCURRENTLY IF EXISTS idx_users_created_at`)\n                    return err\n                },\n            },\n        },\n    }\n\n    migrate, err := gosmig.New(migrations, connectToSQLXDB, nil)\n    if err != nil {\n        log.Fatalf(\"Failed to create migration tool: %v\", err)\n    }\n\n    migrate()\n}\n\nfunc connectToSQLXDB(url string, timeout time.Duration) (*sqlx.DB, error) {\n    db, err := sqlx.Open(\"pgx\", url)\n    if err != nil {\n        return nil, err\n    }\n\n    ctx, cancel := context.WithTimeout(context.Background(), timeout)\n    defer cancel()\n\n    if err := db.PingContext(ctx); err != nil {\n        return nil, err\n    }\n\n    return db, nil\n}\n```\n\n💡 Check the [examples](https://github.com/padurean/gosmig/tree/examples) branch for complete, runnable examples.\n\n## CLI Usage\n\nOnce you've built your migration tool, use it from the command line:\n\n### Migrate Up\n\n```console\n# Apply all pending migrations\n./your-migration-tool \"postgres://user:pass@localhost:5432/dbname?sslmode=disable\" up\n\n[x] Applied migration version 1\n[x] Applied migration version 2\n[x] Applied migration version 3\n3 migration(s) applied\n```\n\n### Migrate Up One\n\n```console\n# Apply only the next migration\n./your-migration-tool \"postgres://user:pass@localhost:5432/dbname?sslmode=disable\" up-one\n\n[x] Applied migration version 4\n1 migration(s) applied\n```\n\n### Migrate Down (One)\n\n```console\n# Roll back the last migration\n./your-migration-tool \"postgres://user:pass@localhost:5432/dbname?sslmode=disable\" down\n\n[x]--\u003e[ ] Rolled back migration version 4\n```\n\n### Check Migration Status\n\n```console\n# Check migration status\n./your-migration-tool \"postgres://user:pass@localhost:5432/dbname?sslmode=disable\" status\n\nVERSION    STATUS\n3          [ ] PENDING\n2          [x] APPLIED\n1          [x] APPLIED\n```\n\n### Get Current Database Version\n\n```console\n# Get current database version\n./your-migration-tool \"postgres://user:pass@localhost:5432/dbname?sslmode=disable\" version\n\nCurrent database version:\n5\n```\n\n## Commands Summary\n\n| Command | Description |\n|---------|-------------|\n| `up` | Apply all pending migrations |\n| `up-one` | Apply only the next pending migration |\n| `down` | Roll back the most recent migration |\n| `status` | Show the status of all migrations (uses pager for long lists) |\n| `version` | Show the current database version |\n\n## Migration Types\n\n### Transactional Migrations (`UpDown`)\n\nUse `UpDown` for migrations that should run within a database transaction. This is the recommended approach for most migrations as it ensures atomicity.\n\n```go\n{\n    Version: 1,\n    UpDown: \u0026gosmig.UpDownSQL{\n        Up: func(ctx context.Context, tx *sql.Tx) error {\n            // Your migration code here\n            return nil\n        },\n        Down: func(ctx context.Context, tx *sql.Tx) error {\n            // Your rollback code here\n            return nil\n        },\n    },\n}\n```\n\n### Non-Transactional Migrations (`UpDownNoTX`)\n\nUse `UpDownNoTX` for migrations that cannot or should not run in a transaction, such as:\n\n- Index creation with `CONCURRENTLY` in PostgreSQL\n- Operations that require multiple transactions\n- DDL operations that don't support transactions in some databases\n\n```go\n{\n    Version: 2,\n    UpDownNoTX: \u0026gosmig.UpDownNoTXSQL{\n        Up: func(ctx context.Context, db *sql.DB) error {\n            // Your non-transactional migration code here\n            return nil\n        },\n        Down: func(ctx context.Context, db *sql.DB) error {\n            // Your non-transactional rollback code here\n            return nil\n        },\n    },\n}\n```\n\n## Configuration\n\n### Timeout Configuration\n\nConfigure operation timeouts when creating the migration tool:\n\n```go\nmigrate, err := gosmig.New(migrations, connectToDB, \u0026gosmig.Config{Timeout: 30 * time.Second})\n```\n\nIf you pass **`0`** or a **negative** duration, the default timeout of **10 seconds** will be used.\n\n### Database Connection\n\nThe `connectToDB` function should establish a connection and verify it's working:\n\n```go\nfunc connectToDB(url string, timeout time.Duration) (*sql.DB, error) {\n    db, err := sql.Open(\"pgx\", url)\n    if err != nil {\n        return nil, fmt.Errorf(\"failed to open database: %w\", err)\n    }\n\n    ctx, cancel := context.WithTimeout(context.Background(), timeout)\n    defer cancel()\n\n    if err := db.PingContext(ctx); err != nil {\n        return nil, fmt.Errorf(\"failed to ping database: %w\", err)\n    }\n\n    return db, nil\n}\n```\n\n### Coordinating Concurrent Runs\n\nRunning multiple migration processes at the same time can lead to conflicting writes.\nUse a database-level advisory lock (or the closest equivalent) to ensure only one\ngosmig instance runs at a time:\n\n- **PostgreSQL**: call `SELECT pg_try_advisory_lock(...)` before starting migrations and\n    `SELECT pg_advisory_unlock(...)` afterwards. Choose a consistent 64-bit key so all\n    processes compete for the same lock.\n- **MySQL / MariaDB**: wrap migration runs with `SELECT GET_LOCK('gosmig', timeout)`\n    and `SELECT RELEASE_LOCK('gosmig')` using a shared lock name.\n- **SQL Server**: use `sp_getapplock` / `sp_releaseapplock` with a well-known\n    resource name.\n- **SQLite**: serialize runs with a file lock (one process) or by executing\n    `BEGIN EXCLUSIVE` on a dedicated coordination table before applying migrations.\n\nFor an example for PostgreSQL's advisory locks, see the [with_pg_advisory_lock example](https://github.com/padurean/gosmig/tree/examples/with_pg_advisory_lock) from the [**`examples`** branch](https://github.com/padurean/gosmig/tree/examples).\n\nThis pattern keeps migrations simple while preventing concurrent runs from stepping on each other.\n\n## Type Aliases\n\nFor convenience, gosmig provides type aliases for common use cases:\n\n```go\n// For database/sql\ntype MigrationSQL  = Migration[*sql.Row, sql.Result, *sql.Tx, *sql.TxOptions, *sql.DB]\ntype UpDownSQL     = UpDown[*sql.Row, sql.Result, *sql.Tx]\ntype UpDownNoTXSQL = UpDown[*sql.Row, sql.Result, *sql.DB]\n\n// Define your own for sqlx\ntype MigrationSQLX  = Migration[*sql.Row, sql.Result, *sql.Tx, *sql.TxOptions, *sqlx.DB]\ntype UpDownNoTXSQLX = UpDown[*sql.Row, sql.Result, *sqlx.DB]\n// Note: UpDownSQL works for both database/sql and sqlx\n```\n\n## Migration Table\n\ngosmig automatically creates a `gosmig` table to track applied migrations:\n\n```sql\nCREATE TABLE gosmig (\n    version INTEGER PRIMARY KEY,\n    applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n```\n\n## Error Handling\n\ngosmig provides robust error handling:\n\n- **Validation**: Migrations are validated at startup\n- **Version Conflicts**: Prevents applying migrations if database version changes during execution\n- **Transaction Safety**: Automatic rollback on errors in transactional migrations\n- **Clear Error Messages**: Descriptive error messages with context\n\n## Testing\n\n### Running Tests\n\n```bash\n# Run tests with local PostgreSQL\nmake test\n\n# Run tests with Docker PostgreSQL\nmake test-docker\n\n# Clean up Docker containers\n# NOTE: this doesn't need to be run as `make test-docker` already does it - it\n# is provided here \"just in case\".\nmake test-docker-down\n```\n\n### Test Requirements\n\n- PostgreSQL database (local or Docker)\n- Go 1.25+\n\n## Development\n\n### Prerequisites\n\n- Go 1.25+\n- golangci-lint for linting\n- govulncheck for vulnerability scanning\n\n### Development Commands\n\n```bash\n# Lint code\nmake lint\n\n# Check for vulnerabilities\nmake vulncheck\n\n# Build (includes linting and vulnerability checks)\nmake build\n\n# Build only (skip checks)\nmake build-only\n\n# Run tests\nmake test\n\n# Test with Docker\nmake test-docker\n```\n\nSee [Makefile](Makefile) for all available development commands.\n\n## Supported Databases\n\ngosmig works with any database that implements Go's standard `database/sql` interfaces. Tested with:\n\n- [PostgreSQL](https://www.postgresql.org)\n- Should work with [MySQL](https://www.mysql.com), [SQLite](https://www.sqlite.org), [SQL Server](https://www.microsoft.com/en-us/sql-server), and others\n\n## API Reference\n\n### Core Types\n\n```go\ntype (\n    // Interfaces for database operations (subset of database/sql).\n    // database/sql and sqlx satisfy these interfaces out of the box.\n    // It should be possible to use any database library (wrapper) that satisfies them.\n\n    DBRow interface {\n        Scan(dest ...any) error\n        Err() error\n    }\n\n    DBResult interface {\n        LastInsertId() (int64, error)\n        RowsAffected() (int64, error)\n    }\n\n    DBOrTX[TDBRow DBRow, TDBResult DBResult] interface {\n        QueryRowContext(context.Context, string, ...any) TDBRow\n        ExecContext(context.Context, string, ...any) (TDBResult, error)\n    }\n\n    TXOptions interface{}\n\n    TX[TDBRow DBRow, TDBResult DBResult] interface {\n        QueryRowContext(context.Context, string, ...any) TDBRow\n        ExecContext(context.Context, string, ...any) (TDBResult, error)\n        Commit() error\n        Rollback() error\n    }\n\n    DB[TDBRow DBRow, TDBResult DBResult, TTX TX[TDBRow, TDBResult], TTXO TXOptions] interface {\n        QueryRowContext(context.Context, string, ...any) TDBRow\n        ExecContext(context.Context, string, ...any) (TDBResult, error)\n        BeginTx(context.Context, TTXO) (TTX, error)\n        Close() error\n    }\n\n    // Migration and related types\n\n    UpDown[TDBRow DBRow, TDBResult DBResult, TDBOrTX DBOrTX[TDBRow, TDBResult]] struct {\n        Up   func(ctx context.Context, tx TDBOrTX) error\n        Down func(ctx context.Context, tx TDBOrTX) error\n    }\n\n    Migration[TDBRow DBRow, TDBResult DBResult, TTX TX[TDBRow, TDBResult], TTXO TXOptions, TDB DB[TDBRow, TDBResult, TTX, TTXO]] struct {\n        Version    int\n        UpDown     *UpDown[TDBRow, TDBResult, TTX]\n        UpDownNoTX *UpDown[TDBRow, TDBResult, TDB]\n    }\n\n    MigrationSQL  = Migration[*sql.Row, sql.Result, *sql.Tx, *sql.TxOptions, *sql.DB]\n    UpDownSQL     = UpDown[*sql.Row, sql.Result, *sql.Tx]   // Transactional migration\n    UpDownNoTXSQL = UpDown[*sql.Row, sql.Result, *sql.DB]   // Non-transactional migration\n)\n```\n\n### Main Function\n\n```go\nfunc New[TDBRow, TDBResult, TTX, TTXO, TDB](\n    migrations []Migration[TDBRow, TDBResult, TTX, TTXO, TDB],\n    connectToDB func(url string, timeout time.Duration) (TDB, error),\n    config *Config,\n) (func(), error)\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests for new functionality\n5. Run the test suite\n6. Submit a pull request\n\n## License\n\nThis project is released into the public domain under the [Unlicense](http://unlicense.org/). See the [LICENSE](LICENSE) file for details.\n\n## Changelog\n\n### v0.0.1 (Current)\n\n- Initial release\n- Support for both transactional and non-transactional migrations\n- CLI interface with `up`, `up-one`, `down`, `status`, and `version` commands\n- Full Go generics support\n- Support for [**`database/sql`**](https://pkg.go.dev/database/sql) and [**`sqlx`**](https://github.com/jmoiron/sqlx) out of the box\n- Other database libraries supported via [interfaces](#core-types)\n- Comprehensive test suite\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpadurean%2Fgosmig","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpadurean%2Fgosmig","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpadurean%2Fgosmig/lists"}