236 lines
7.8 KiB
Markdown
236 lines
7.8 KiB
Markdown
# 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.
|
|
|
|
With `--types sqltypes`, nullable fields use the [`pkg/sqltypes`](../../sqltypes/README.md) package.
|
|
|
|
## 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
|
|
|
|
```go
|
|
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
|
|
|
|
```bash
|
|
# Generate Bun models from a DBML schema (default: baselib pointer 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
|
|
relspec convert --from dbml --from-path schema.dbml \
|
|
--to bun --to-path models.go --package models \
|
|
--types stdlib
|
|
|
|
# Select sqltypes package types (git.warky.dev/wdevs/relspecgo/pkg/sqltypes)
|
|
relspec convert --from pgsql --from-conn "postgres://localhost/mydb" \
|
|
--to bun --to-path models.go --package models \
|
|
--types sqltypes
|
|
|
|
# Multi-file output (one file per table)
|
|
relspec convert --from json --from-path schema.json \
|
|
--to bun --to-path models/ --package models
|
|
|
|
# Inject computed/scan-only fields that are not present in the database schema
|
|
relspec convert --from dbml --from-path schema.dbml \
|
|
--to bun --to-path models.go --package models \
|
|
--extra-fields '[{"target_table":"projects","name":"ThoughtCount","type":"sql_types.SqlInt64","bun_tag":"thought_count,scanonly","json_tag":"thought_count"}]'
|
|
```
|
|
|
|
## Generated Code Examples
|
|
|
|
### sqltypes package types (`--types sqltypes`)
|
|
|
|
```go
|
|
package models
|
|
|
|
import (
|
|
sql_types "git.warky.dev/wdevs/relspecgo/pkg/sqltypes"
|
|
"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 sql_types.SqlString `bun:"email,type:text,nullzero," json:"email"`
|
|
Tags sql_types.SqlStringArray `bun:"tags,type:text[],default:'{}',notnull," json:"tags"`
|
|
CreatedAt sql_types.SqlTimeStamp `bun:"created_at,type:timestamptz,default:now(),notnull," json:"created_at"`
|
|
}
|
|
```
|
|
|
|
### Standard library — `--types stdlib`
|
|
|
|
```go
|
|
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 — sqltypes | 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 sqltypes 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`:
|
|
|
|
```go
|
|
// Use sqltypes package types
|
|
options := &writers.WriterOptions{
|
|
OutputPath: "models.go",
|
|
PackageName: "models",
|
|
NullableTypes: writers.NullableTypeSqlTypes,
|
|
}
|
|
|
|
// Use standard library database/sql types
|
|
options := &writers.WriterOptions{
|
|
OutputPath: "models.go",
|
|
PackageName: "models",
|
|
NullableTypes: writers.NullableTypeStdlib,
|
|
}
|
|
```
|
|
|
|
### Metadata Options
|
|
|
|
```go
|
|
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
|
|
},
|
|
}
|
|
```
|
|
|
|
#### Extra fields
|
|
|
|
Use `Metadata["extra_fields"]` (or the CLI `--extra-fields` flag) to inject
|
|
custom fields into generated Bun models without editing generated files. This is
|
|
intended for computed columns and scan-only query fields that Bun must scan into
|
|
but that are not real database table columns.
|
|
|
|
Each entry supports:
|
|
|
|
| Field | Required | Description |
|
|
|---|---:|---|
|
|
| `target_table` | No | Optional model scope. Accepts table name (`projects`), qualified table (`public.projects`), or model name (`ModelPublicProjects`). If omitted, the field is added to every generated model. |
|
|
| `name` | Yes | Go struct field name. |
|
|
| `type` | Yes | Go type to emit. |
|
|
| `bun_tag` | No | Raw Bun tag contents, e.g. `thought_count,scanonly`. |
|
|
| `json_tag` | No | Raw JSON tag contents. |
|
|
| `comment` | No | Optional line comment. |
|
|
|
|
```go
|
|
options := &writers.WriterOptions{
|
|
OutputPath: "models.go",
|
|
PackageName: "models",
|
|
Metadata: map[string]any{
|
|
"extra_fields": `[
|
|
{
|
|
"target_table": "projects",
|
|
"name": "ThoughtCount",
|
|
"type": "sql_types.SqlInt64",
|
|
"bun_tag": "thought_count,scanonly",
|
|
"json_tag": "thought_count",
|
|
"comment": "Computed by ResolveSpec queries"
|
|
}
|
|
]`,
|
|
},
|
|
}
|
|
```
|
|
|
|
## Notes
|
|
|
|
- Model names are derived from table names (singularized, PascalCase)
|
|
- Table aliases are auto-generated from table names
|
|
- Nullable columns use plain Go pointer types (`*string`, `*time.Time`, …) by default; pass `--types sqltypes` to use `sql_types.SqlString`, `sql_types.SqlTimeStamp`, etc., or `--types stdlib` to use `sql.NullString`, `sql.NullTime`, etc.
|
|
- Array columns use plain Go slices (`[]string`, `[]int32`, …) by default; `--types sqltypes` uses `sql_types.SqlStringArray`, `sql_types.SqlInt32Array`, etc.
|
|
- Multi-file mode: one file per table named `sql_{schema}_{table}.go`
|
|
- Generated code is auto-formatted
|
|
- JSON tags are automatically added
|