* 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.
GORM Writer
Generates Go source files with GORM model definitions from database schema information.
Overview
The GORM Writer converts RelSpec's internal database model representation into Go source code with GORM struct definitions, complete with proper tags, relationships, and methods.
Features
- Generates GORM-compatible Go structs
- Creates proper
gormstruct tags - Generates
TableName()methods - Adds relationship fields (belongs-to, has-many)
- Supports both single-file and multi-file output
- Auto-generates helper methods (optional)
- Maps SQL types to Go types
- Handles nullable fields with custom sql_types
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/gorm"
)
func main() {
// Assume db is a *models.Database from a reader
options := &writers.WriterOptions{
OutputPath: "models.go",
PackageName: "models",
}
writer := gorm.NewWriter(options)
err := writer.WriteDatabase(db)
if err != nil {
panic(err)
}
}
CLI Examples
# Generate GORM models from a DBML schema (default: resolvespec types)
relspec convert --from dbml --from-path schema.dbml \
--to gorm --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 gorm --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 gorm --to-path models.go --package models \
--types resolvespec
# Multi-file output (one file per table)
relspec convert --from json --from-path schema.json \
--to gorm --to-path models/ --package models
Output Modes
Single File Mode
Generates all models in one file:
relspec --input pgsql --conn "..." --output gorm --out-file models.go
Multi-File Mode
Generates one file per table (auto-detected when output is a directory):
relspec --input pgsql --conn "..." --output gorm --out-file models/
Files are named: sql_{schema}_{table}.go
Generated Code Examples
Default — resolvespec types (--types resolvespec)
package models
import (
sql_types "github.com/bitechdev/ResolveSpec/pkg/spectypes"
)
type ModelUser struct {
ID string `gorm:"column:id;type:uuid;primaryKey" json:"id"`
Username string `gorm:"column:username;type:text;not null" json:"username"`
Email sql_types.SqlString `gorm:"column:email;type:text" json:"email,omitempty"`
Tags sql_types.SqlStringArray `gorm:"column:tags;type:text[];not null;default:'{}'" json:"tags"`
CreatedAt sql_types.SqlTimeStamp `gorm:"column:created_at;type:timestamptz;not null;default:now()" json:"created_at"`
}
func (ModelUser) TableName() string {
return "public.users"
}
Standard library — --types stdlib
package models
import (
"database/sql"
"time"
)
type ModelUser struct {
ID string `gorm:"column:id;type:uuid;primaryKey" json:"id"`
Username string `gorm:"column:username;type:text;not null" json:"username"`
Email sql.NullString `gorm:"column:email;type:text" json:"email,omitempty"`
Tags []string `gorm:"column:tags;type:text[];not null;default:'{}'" json:"tags"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;default:now()" json:"created_at"`
}
func (ModelUser) TableName() string {
return "public.users"
}
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
Configure additional writer behavior using metadata in WriterOptions:
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
},
}
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 |
SqlString |
sql.NullString |
text[] |
SqlStringArray |
SqlStringArray |
[]string |
integer[] |
SqlInt32Array |
SqlInt32Array |
[]int32 |
uuid[] |
SqlUUIDArray |
SqlUUIDArray |
[]string |
vector |
SqlVector |
SqlVector |
[]float32 |
Relationship Generation
The writer automatically generates relationship fields:
- Belongs-to: Generated for tables with foreign keys
- Has-many: Generated for tables referenced by foreign keys
- Relationship field names use 3-letter prefixes
- Includes proper
gormtags withforeignKeyandreferences
Notes
- Model names are prefixed with "Model" (e.g.,
ModelUser) - Nullable columns use
sql_types.SqlString,sql_types.SqlInt64, etc. by default; pass--types stdlibto usesql.NullString,sql.NullInt64, etc. instead - Array columns use
sql_types.SqlStringArray,sql_types.SqlInt32Array, etc. by default;--types stdlibproduces plain Go slices ([]string,[]int32, …) - Generated code is auto-formatted with
go fmt - JSON tags are automatically added
- Supports schema-qualified table names in
TableName()method