Files
relspecgo/pkg/writers/bun
Hein 3524e86282 feat: add --types flag and stdlib nullable type support for bun/gorm writers
* Fix pgsql reader double-quoting defaults: normalizePostgresDefault strips
  surrounding SQL string literal quotes from column_default before storing,
  matching the convention used by every other reader.

* Add NullableTypes field to WriterOptions with NullableTypeResolveSpec
  (default) and NullableTypeStdlib constants.

* Both bun and gorm TypeMappers now accept a typeStyle parameter. stdlib
  mode produces sql.NullString/NullInt32/NullTime etc. for nullable scalars,
  plain Go slices for arrays, and time.Time for NOT NULL timestamps. Default
  resolvespec behaviour is unchanged.

* Add --types flag to convert and split commands.

* Update bun/README.md and gorm/README.md with side-by-side generated code
  examples, updated type mapping tables, and Writer Options documentation.
2026-04-30 16:00:54 +02:00
..
2025-12-17 20:44:02 +02:00
2025-12-16 18:10:40 +02:00

Bun Writer

Generates Go source files with Bun model definitions from database schema information.

Overview

The Bun Writer converts RelSpec's internal database model representation into Go source code with Bun struct definitions, complete with proper tags, relationships, and table configuration.

Features

  • Generates Bun-compatible Go structs
  • Creates proper bun struct tags
  • Adds relationship fields
  • Supports both single-file and multi-file output
  • Maps SQL types to Go types
  • Handles nullable fields with sql.Null* types
  • Generates table aliases

Usage

Basic Example

package main

import (
    "git.warky.dev/wdevs/relspecgo/pkg/models"
    "git.warky.dev/wdevs/relspecgo/pkg/writers"
    "git.warky.dev/wdevs/relspecgo/pkg/writers/bun"
)

func main() {
    options := &writers.WriterOptions{
        OutputPath:  "models.go",
        PackageName: "models",
    }

    writer := bun.NewWriter(options)
    err := writer.WriteDatabase(db)
    if err != nil {
        panic(err)
    }
}

CLI Examples

# Generate Bun models from a DBML schema (default: resolvespec types)
relspec convert --from dbml --from-path schema.dbml \
  --to bun --to-path models.go --package models

# Use standard library database/sql nullable types instead of resolvespec
relspec convert --from dbml --from-path schema.dbml \
  --to bun --to-path models.go --package models \
  --types stdlib

# Explicitly select resolvespec types (same as omitting --types)
relspec convert --from pgsql --from-conn "postgres://localhost/mydb" \
  --to bun --to-path models.go --package models \
  --types resolvespec

# Multi-file output (one file per table)
relspec convert --from json --from-path schema.json \
  --to bun --to-path models/ --package models

Generated Code Examples

Default — resolvespec types (--types resolvespec)

package models

import (
    resolvespec_common "github.com/bitechdev/ResolveSpec/pkg/spectypes"
    "github.com/uptrace/bun"
)

type User struct {
    bun.BaseModel `bun:"table:users,alias:u"`

    ID        int64                              `bun:"id,type:uuid,pk," json:"id"`
    Username  string                             `bun:"username,type:text,notnull," json:"username"`
    Email     resolvespec_common.SqlString       `bun:"email,type:text,nullzero," json:"email"`
    Tags      resolvespec_common.SqlStringArray  `bun:"tags,type:text[],default:'{}',notnull," json:"tags"`
    CreatedAt resolvespec_common.SqlTimeStamp    `bun:"created_at,type:timestamptz,default:now(),notnull," json:"created_at"`
}

Standard library — --types stdlib

package models

import (
    "database/sql"
    "time"
    "github.com/uptrace/bun"
)

type User struct {
    bun.BaseModel `bun:"table:users,alias:u"`

    ID        string         `bun:"id,type:uuid,pk," json:"id"`
    Username  string         `bun:"username,type:text,notnull," json:"username"`
    Email     sql.NullString `bun:"email,type:text,nullzero," json:"email"`
    Tags      []string       `bun:"tags,type:text[],default:'{}',notnull," json:"tags"`
    CreatedAt time.Time      `bun:"created_at,type:timestamptz,default:now(),notnull," json:"created_at"`
}

Supported Bun Tags

  • table - Table name and alias
  • column - Column name (auto-derived if not specified)
  • pk - Primary key
  • autoincrement - Auto-increment
  • notnull - NOT NULL constraint
  • unique - Unique constraint
  • default - Default value
  • rel - Relationship definition
  • type - Explicit SQL type

Type Mapping

The nullable type package is selected with --types (or WriterOptions.NullableTypes).

SQL Type NOT NULL (both) Nullable — resolvespec Nullable — stdlib
bigint int64 SqlInt64 sql.NullInt64
integer int32 SqlInt32 sql.NullInt32
smallint int16 SqlInt16 sql.NullInt16
text, varchar string SqlString sql.NullString
boolean bool SqlBool sql.NullBool
timestamp, timestamptz time.Time* SqlTimeStamp sql.NullTime
numeric, decimal float64 SqlFloat64 sql.NullFloat64
uuid string SqlUUID sql.NullString
jsonb string SqlJSONB sql.NullString
text[] SqlStringArray SqlStringArray []string
integer[] SqlInt32Array SqlInt32Array []int32
uuid[] SqlUUIDArray SqlUUIDArray []string
vector SqlVector SqlVector []float32

* In resolvespec mode, NOT NULL timestamps use SqlTimeStamp (not time.Time) unless the base type is a simple integer or boolean. In stdlib mode, NOT NULL timestamps use time.Time.

Writer Options

NullableTypes

Controls which Go package is used for nullable column types. Set via the --types CLI flag or WriterOptions.NullableTypes:

// Use resolvespec types (default — omit NullableTypes or set to "resolvespec")
options := &writers.WriterOptions{
    OutputPath:    "models.go",
    PackageName:   "models",
    NullableTypes: writers.NullableTypeResolveSpec,
}

// Use standard library database/sql types
options := &writers.WriterOptions{
    OutputPath:    "models.go",
    PackageName:   "models",
    NullableTypes: writers.NullableTypeStdlib,
}

Metadata Options

options := &writers.WriterOptions{
    OutputPath:  "models.go",
    PackageName: "models",
    Metadata: map[string]any{
        "multi_file":          true, // Enable multi-file mode
        "populate_refs":       true, // Populate RefDatabase/RefSchema
        "generate_get_id_str": true, // Generate GetIDStr() methods
    },
}

Notes

  • Model names are derived from table names (singularized, PascalCase)
  • Table aliases are auto-generated from table names
  • Nullable columns use resolvespec_common.SqlString, resolvespec_common.SqlTimeStamp, etc. by default; pass --types stdlib to use sql.NullString, sql.NullTime, etc. instead
  • Array columns use resolvespec_common.SqlStringArray, resolvespec_common.SqlInt32Array, etc. by default; --types stdlib produces plain Go slices ([]string, []int32, …)
  • Multi-file mode: one file per table named sql_{schema}_{table}.go
  • Generated code is auto-formatted
  • JSON tags are automatically added