feat: generated and identity columns for mssql, sqlite, drizzle, typeorm, bun and gorm readers
- mssql: write computed columns (AS (expr) PERSISTED) and identity; read computed definition and identity - sqlite: write GENERATED ALWAYS AS (expr) STORED; read generated columns via table_xinfo and parse the expression - drizzle: generatedAlwaysAs / generated(Always|ByDefault)AsIdentity, read and write - typeorm: asExpression/generatedType and identity decorators, read and write; decorator scan is now quote-aware - bun, gorm readers: read generated and identity markers - readmes updated
This commit is contained in:
@@ -64,6 +64,8 @@ The reader recognizes the following Bun struct tags:
|
||||
- `autoincrement` - Auto-increment column
|
||||
- `default` - Default value
|
||||
- `unique` - Unique constraint
|
||||
- `generated` - Generated column marker (`Generated`; expression is not in the tag)
|
||||
- `identity` - Identity column marker (`Identity`, `ALWAYS`)
|
||||
- `rel` - Relationship definition
|
||||
|
||||
## Example Bun Model
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package bun
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||
)
|
||||
|
||||
func TestReader_GeneratedAndIdentityMarkers(t *testing.T) {
|
||||
src := `package models
|
||||
|
||||
import "github.com/uptrace/bun"
|
||||
|
||||
type Person struct {
|
||||
bun.BaseModel ` + "`bun:\"table:people,alias:p\"`" + `
|
||||
|
||||
ID int64 ` + "`bun:\"id,pk,type:bigint,autoincrement,identity\"`" + `
|
||||
Seq int64 ` + "`bun:\"seq,type:bigint,scanonly,identity,notnull\"`" + `
|
||||
FullName string ` + "`bun:\"full_name,type:text,scanonly,generated,nullzero\"`" + `
|
||||
First string ` + "`bun:\"first,type:text,nullzero\"`" + `
|
||||
}
|
||||
`
|
||||
path := filepath.Join(t.TempDir(), "person.go")
|
||||
if err := os.WriteFile(path, []byte(src), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
db, err := NewReader(&readers.ReaderOptions{FilePath: path}).ReadDatabase()
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDatabase() error = %v", err)
|
||||
}
|
||||
cols := db.Schemas[0].Tables[0].Columns
|
||||
|
||||
if !cols["id"].Identity || cols["id"].IdentityGeneration != "ALWAYS" {
|
||||
t.Errorf("id: identity = %v/%q, want true/ALWAYS", cols["id"].Identity, cols["id"].IdentityGeneration)
|
||||
}
|
||||
if !cols["seq"].Identity || cols["seq"].IdentityGeneration != "ALWAYS" {
|
||||
t.Errorf("seq: identity = %v/%q, want true/ALWAYS", cols["seq"].Identity, cols["seq"].IdentityGeneration)
|
||||
}
|
||||
if !cols["full_name"].Generated {
|
||||
t.Error("full_name should be generated")
|
||||
}
|
||||
if cols["first"].Generated || cols["first"].Identity {
|
||||
t.Error("first must be an ordinary column")
|
||||
}
|
||||
}
|
||||
@@ -659,6 +659,13 @@ func (r *Reader) parseColumn(fieldName string, fieldType ast.Expr, tag string, s
|
||||
hasExplicitNullableMarker = true
|
||||
case "autoincrement":
|
||||
column.AutoIncrement = true
|
||||
case "generated":
|
||||
// GENERATED ... STORED marker written by the Bun writer; the expression is not in the tag
|
||||
column.Generated = true
|
||||
case "identity":
|
||||
// GENERATED ALWAYS AS IDENTITY marker written by the Bun writer
|
||||
column.Identity = true
|
||||
column.IdentityGeneration = "ALWAYS"
|
||||
case "default":
|
||||
// Default value from Bun tag (e.g., default:gen_random_uuid())
|
||||
column.Default = value
|
||||
|
||||
Reference in New Issue
Block a user