Skip to content

Latest commit

 

History

History
302 lines (224 loc) · 6.24 KB

File metadata and controls

302 lines (224 loc) · 6.24 KB

MySQL Driver

EVO provides a MySQL/MariaDB driver via lib/mysql. It integrates with GORM and the EVO schema migration system, with automatic MariaDB detection.

Installation

import (
    "github.com/getevo/evo/v2"
    "github.com/getevo/evo/v2/lib/mysql"
)

Quick Start

package main

import (
    "github.com/getevo/evo/v2"
    "github.com/getevo/evo/v2/lib/mysql"
)

func main() {
    if err := evo.Setup(mysql.Driver{}); err != nil {
        panic(err)
    }
    evo.Run()
}

Configuration (config.yml)

Database:
  Enabled: true
  Type: mysql
  Server: "127.0.0.1:3306"    # host:port
  Username: "root"
  Password: "secret"
  Database: "myapp"
  SSLMode: "false"             # false | true
  Params: "charset=utf8mb4&parseTime=True&loc=Local"
  Debug: 3                     # 1:silent 2:warn 3:error 4:info
  MaxOpenConns: "100"
  MaxIdleConns: "10"
  ConnMaxLifTime: "1h"
  SlowQueryThreshold: "500ms"

Recommended Params for MySQL

charset=utf8mb4&parseTime=True&loc=Local
  • charset=utf8mb4 — full Unicode support including emoji.
  • parseTime=True — scan DATE/DATETIME into time.Time.
  • loc=Local — use the server's local timezone.

TiDB

TiDB is wire-compatible with MySQL. Use the same mysql driver and point Server at your TiDB cluster:

Database:
  Type: mysql
  Server: "tidb-host:4000"

Driver API

mysql.Driver

Implements db.Driver. Pass it to evo.Setup():

evo.Setup(mysql.Driver{})

The driver:

  1. Builds the DSN: user:password@tcp(host:port)/database?params
  2. Opens a GORM connection.
  3. Runs SELECT VERSION() to detect MariaDB vs MySQL and stores the result for use by the JSON type system.
  4. Registers MySQLDialect for schema-aware DDL and migration.

mysql.RegisterDialect()

Registers the MySQL dialect without opening a connection. Use in tests or standalone scripts:

package main

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "github.com/getevo/evo/v2/lib/mysql"
    "github.com/getevo/evo/v2/lib/db/schema"
)

func main() {
    mysql.RegisterDialect()

    dsn := "root:password@tcp(localhost:3306)/myapp?parseTime=True"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    schema.UseModels(&MyModel{})

    stmts := mysql.Driver{}.GetMigrationScript(db)
    for _, s := range stmts {
        println(s)
    }
}

GORM model example

type Article struct {
    ID        uint      `gorm:"primaryKey;autoIncrement"`
    Title     string    `gorm:"size:255;not null"`
    Body      string    `gorm:"type:longtext"`
    Published bool      `gorm:"default:false;index"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

Register the model and run migrations:

package main

import (
    "github.com/getevo/evo/v2"
    "github.com/getevo/evo/v2/lib/db/schema"
    "github.com/getevo/evo/v2/lib/mysql"
)

func main() {
    evo.Setup(mysql.Driver{})
    schema.UseModels(&Article{})
    evo.Run()
}

Run with migration flag:

./myapp --migration-do          # apply migrations
./myapp --migration-dry-run     # print SQL without executing
./myapp --migration-dump        # dump CREATE TABLE DDL

Database operations

import "github.com/getevo/evo/v2/lib/db"

// Insert
article := Article{Title: "Hello World", Body: "Content here"}
db.Create(&article)

// Query
var articles []Article
db.Where("published = ?", true).Order("created_at DESC").Find(&articles)

// Update
db.Model(&article).Updates(Article{Title: "Updated Title", Published: true})

// Delete (soft-delete if model has DeletedAt)
db.Delete(&article)

// Raw SQL
var count int64
db.Raw("SELECT COUNT(*) FROM articles WHERE published = ?", true).Scan(&count)

MySQL-specific features

JSON columns

import "github.com/getevo/evo/v2/lib/db/types"

type Config struct {
    ID       uint
    Name     string
    Settings types.JSON `gorm:"type:json"`
}

The types.JSON type is automatically serialized/deserialized and works with both MySQL 5.7+ (json) and MariaDB (longtext-based JSON simulation).

Full-text index

type Post struct {
    ID      uint
    Title   string `gorm:"size:255"`
    Content string `gorm:"type:text"`
}

// In migration: CREATE FULLTEXT INDEX idx_posts_content ON posts(content);

Enum column

type User struct {
    ID   uint
    Role string `gorm:"type:enum('admin','user','guest');default:'user'"`
}

With validation:

type User struct {
    ID   uint
    Role string `gorm:"type:enum('admin','user','guest');default:'user'" validation:"enum"`
}

UUID primary key

import "github.com/getevo/evo/v2/lib/db/types"

type Order struct {
    ID   types.UUID `gorm:"type:varchar(36);primaryKey"`
    Ref  string
}

MariaDB detection

The driver automatically detects MariaDB by checking SELECT VERSION():

// internal (happens automatically in Driver.Open)
if strings.Contains(strings.ToLower(ver), "mariadb") {
    schema.SetConfig("mysql_engine", "mariadb")
} else {
    schema.SetConfig("mysql_engine", "mysql")
}

This affects JSON type handling — MariaDB uses longtext while MySQL 5.7+ uses the native json type.

Health checks

import (
    "context"
    "github.com/getevo/evo/v2"
    "github.com/getevo/evo/v2/lib/db"
    "github.com/getevo/evo/v2/lib/mysql"
)

func main() {
    evo.Setup(mysql.Driver{})

    evo.OnHealthCheck(func() error {
        return db.Ping(context.Background(), db.GetInstance())
    })

    evo.OnReadyCheck(func() error {
        result := db.HealthCheck(context.Background(), db.GetInstance())
        if !result.Healthy {
            return fmt.Errorf("database unhealthy: %s", result.Error)
        }
        return nil
    })

    evo.Run()
}

Troubleshooting

Error 1049: Unknown database

Create the database first, or use CREATE DATABASE IF NOT EXISTS myapp;.

Invalid utf8mb4 character

Add charset=utf8mb4 to Params.

Slow queries logged

Adjust SlowQueryThreshold in config — queries exceeding this duration are logged as warnings.

MariaDB JSON stored as text

This is expected. types.JSON handles serialization transparently for both engines.

See Also