OOro

驱动接口

Driver、Dialect、Inspector、Capabilities、Logger 和第三方 SQL 驱动开发参考。

Oro 驱动边界是 database/sql。官方驱动和第三方驱动都只需要实现公开接口。

Driver

type Driver interface {
    Name() string
    Open(ctx context.Context) (*sql.DB, error)
    Dialect() oro.Dialect
    Inspector(db *sql.DB) oro.Inspector
    TranslateError(err error) error
    Owned() bool
}
方法 说明
Name() 驱动名称,用于日志和错误上下文
Open(ctx) 打开 *sql.DB
Dialect() 返回 SQL 方言编译器
Inspector(db) 返回数据库结构检查器
TranslateError(err) 把数据库错误转成 Oro 标准错误
Owned() DB 是否由 ORM 创建,关闭时是否负责释放

官方驱动提供 Open(dsn)Wrap(*sql.DB) 两种形态。用户自己 import 具体 SQL driver。

import (
    "github.com/duxweb/oro"
    "github.com/duxweb/oro/driver/sqlite"
    _ "modernc.org/sqlite"
)

db, err := oro.Open(oro.Config{
    Connections: map[string]oro.ConnectionConfig{
        "default": {Driver: sqlite.Open("file:app.db")},
    },
})

Dialect

type Dialect interface {
    Name() string
    Capabilities() oro.Capabilities
    QuoteIdent(name string) string
    Placeholder(index int) string
    DataType(column oro.ColumnSpec) (string, error)
    NormalizeType(dbType string) (oro.ColumnType, error)
    Compile(stmt oro.Statement) (oro.CompiledSQL, error)
    CompileSchema(change oro.SchemaChange) ([]oro.CompiledSQL, error)
}

Dialect 负责两件事:

  • 把查询 AST 编译成 SQL;
  • 把模型结构变更编译成 DDL。

Oro 根包负责构建 AST。驱动不需要解析链式查询,只需要处理 oro.Statement

Capabilities

type Capabilities struct {
    Returning       bool
    Upsert          bool
    Savepoint       bool
    LockForUpdate   bool
    LockForShare    bool
    LockNoWait      bool
    LockSkipLocked  bool
    FullJoin        bool
    JSON            bool
    FullText        bool
    CheckConstraint bool
}

能力开关影响编译和回退策略。例如不支持 RETURNING 的数据库会走主键回填或必要的回查路径。

Inspector

type Inspector interface {
    Tables(ctx context.Context) ([]oro.TableInfo, error)
    Table(ctx context.Context, name string) (*oro.TableSpec, error)
    Indexes(ctx context.Context, table string) ([]oro.IndexSpec, error)
    Constraints(ctx context.Context, table string) ([]oro.ConstraintSpec, error)
}

Sync(ctx) 依赖 Inspector 对比当前数据库结构和模型定义。

Logger

日志接口保持极小:

type Logger interface {
    Log(ctx context.Context, event oro.LogEvent)
}

可以直接适配 slogzapzerolog 等日志库。

db, err := oro.Open(oro.Config{
    Logger: oro.LoggerFunc(func(ctx context.Context, event oro.LogEvent) {
        slog.InfoContext(ctx, "sql", "op", event.Operation, "sql", event.SQL, "err", event.Err)
    }),
    LogLevel: oro.LogLevelInfo,
})

第三方驱动建议

第三方 SQL 驱动建议按这个目录组织:

driver/oracle/
  oracle.go       // Open / Wrap / Option
  dialect.go      // Dialect.Compile / CompileSchema
  inspector.go    // Inspector
  errors.go       // TranslateError

最低可用版本应实现:

  • SELECTINSERTUPDATEDELETE 编译;
  • 占位符和标识符引用;
  • 基础字段类型映射;
  • 唯一冲突和约束错误转换;
  • 表、列、索引检查。

MongoDB 这类文档数据库不建议塞进当前驱动接口,除非有完整 SQL 兼容层。否则应做独立 ODM,而不是伪装成关系型 ORM 驱动。

编辑此页