feat(bun): generate native Go array slices for PostgreSQL array columns
Bun's pgdialect scans/appends native slices directly, so array columns
(text[], integer[], uuid[], ...) always generate as plain []string,
[]int32, etc. with an explicit "array" bun tag, regardless of --types
(sqltypes/stdlib/baselib). The SqlXxxArray wrapper types are no longer
used for Bun array columns (gorm is unaffected and keeps using them).
Adds --array-nullable pointer_slice to represent nullable array columns
as *[]T instead of []T, so callers can distinguish SQL NULL (nil) from
'{}' (pointer to an empty slice). Verified end-to-end against a live
PostgreSQL instance for NULL/{}/populated arrays in every --types mode.
Closes #13
This commit is contained in:
+44
-10
@@ -88,11 +88,11 @@ import (
|
||||
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"`
|
||||
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 []string `bun:"tags,type:text[],array,default:'{}',notnull," json:"tags"`
|
||||
CreatedAt sql_types.SqlTimeStamp `bun:"created_at,type:timestamptz,default:now(),notnull," json:"created_at"`
|
||||
}
|
||||
```
|
||||
|
||||
@@ -113,7 +113,7 @@ type User struct {
|
||||
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"`
|
||||
Tags []string `bun:"tags,type:text[],array,default:'{}',notnull," json:"tags"`
|
||||
CreatedAt time.Time `bun:"created_at,type:timestamptz,default:now(),notnull," json:"created_at"`
|
||||
}
|
||||
```
|
||||
@@ -145,11 +145,17 @@ The nullable type package is selected with `--types` (or `WriterOptions.Nullable
|
||||
| `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` |
|
||||
| `text[]` | `[]string`† | `[]string`† | `[]string`† |
|
||||
| `integer[]` | `[]int32`† | `[]int32`† | `[]int32`† |
|
||||
| `uuid[]` | `[]string`† | `[]string`† | `[]string`† |
|
||||
| `vector` | `SqlVector` | `SqlVector` | `[]float32` |
|
||||
|
||||
† Array columns always use a plain native Go slice with an explicit `array`
|
||||
bun tag (`bun:"tags,type:text[],array,..."`), in every `--types` mode — the
|
||||
`SqlXxxArray` wrapper types are never used, since bun's pgdialect scans/appends
|
||||
native slices directly. Regardless of NOT NULL, unless `--array-nullable
|
||||
pointer_slice` is set — see [NullableArrays](#nullablearrays) below.
|
||||
|
||||
\* 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
|
||||
@@ -174,6 +180,34 @@ options := &writers.WriterOptions{
|
||||
}
|
||||
```
|
||||
|
||||
### NullableArrays
|
||||
|
||||
Controls how nullable PostgreSQL array columns are represented in stdlib/baselib
|
||||
`--types` mode (no effect in `sqltypes` mode, which always uses the `SqlXxxArray`
|
||||
wrapper types). Set via the `--array-nullable` CLI flag or `WriterOptions.NullableArrays`:
|
||||
|
||||
```go
|
||||
// Default: every array column is a plain slice, e.g. []string.
|
||||
// SQL NULL and '{}' both scan into a nil/zero-length slice, so callers
|
||||
// cannot distinguish them.
|
||||
options := &writers.WriterOptions{
|
||||
NullableArrays: writers.NullableArraysSlice,
|
||||
}
|
||||
|
||||
// Nullable array columns become a pointer to a slice, e.g. *[]string.
|
||||
// A nil pointer means SQL NULL; a non-nil pointer to an empty slice
|
||||
// means '{}'. NOT NULL array columns are unaffected and stay plain slices.
|
||||
options := &writers.WriterOptions{
|
||||
NullableArrays: writers.NullableArraysPointerSlice,
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
tags []string `bun:"tags,type:text[],notnull,"` // NOT NULL, either mode
|
||||
tags []string `bun:"tags,type:text[],nullzero,"` // nullable, default (slice)
|
||||
tags *[]string `bun:"tags,type:text[],nullzero,"` // nullable, pointer_slice
|
||||
```
|
||||
|
||||
### Metadata Options
|
||||
|
||||
```go
|
||||
@@ -248,7 +282,7 @@ Example `extra-fields.json`:
|
||||
- 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.
|
||||
- Array columns always use plain Go slices (`[]string`, `[]int32`, …) with an explicit `array` bun tag, regardless of `--types`; pass `--array-nullable pointer_slice` to use `*[]string` etc. for nullable array columns.
|
||||
- Multi-file mode: one file per table named `sql_{schema}_{table}.go`
|
||||
- Generated code is auto-formatted
|
||||
- JSON tags are automatically added
|
||||
|
||||
Reference in New Issue
Block a user