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:
@@ -127,4 +127,5 @@ go test ./pkg/writers/mssql/...
|
||||
- Views are not currently supported in the writer
|
||||
- Sequences are not supported (MSSQL uses IDENTITY instead)
|
||||
- Partitioning and advanced features are not supported
|
||||
- Generated DDL assumes no triggers or computed columns
|
||||
- Generated DDL assumes no triggers
|
||||
- Generated columns are written as computed columns `[col] AS (expr) PERSISTED` (no type, no DEFAULT); identity columns as `IDENTITY(1,1)`
|
||||
|
||||
@@ -187,6 +187,16 @@ func (w *Writer) writeCreateTable(schema *models.Schema, table *models.Table) er
|
||||
func (w *Writer) generateColumnDefinition(col *models.Column) string {
|
||||
parts := []string{fmt.Sprintf("[%s]", col.Name)}
|
||||
|
||||
// Computed column: "name AS (expr) PERSISTED" has no data type and cannot carry
|
||||
// IDENTITY or a DEFAULT. PERSISTED mirrors the stored semantics of Column.Generated.
|
||||
if col.Generated && col.GenerationExpression != "" {
|
||||
parts = append(parts, fmt.Sprintf("AS (%s) PERSISTED", col.GenerationExpression))
|
||||
if col.NotNull {
|
||||
parts = append(parts, "NOT NULL")
|
||||
}
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
// Type with length/precision
|
||||
baseType := mssql.ConvertCanonicalToMSSQL(col.Type)
|
||||
typeStr := baseType
|
||||
@@ -215,7 +225,7 @@ func (w *Writer) generateColumnDefinition(col *models.Column) string {
|
||||
parts = append(parts, typeStr)
|
||||
|
||||
// IDENTITY for auto-increment
|
||||
if col.AutoIncrement {
|
||||
if col.AutoIncrement || col.Identity {
|
||||
parts = append(parts, "IDENTITY(1,1)")
|
||||
}
|
||||
|
||||
|
||||
@@ -204,3 +204,19 @@ func TestWriteComments(t *testing.T) {
|
||||
assert.Contains(t, output, "User accounts table")
|
||||
assert.Contains(t, output, "Primary key")
|
||||
}
|
||||
|
||||
func TestGenerateColumnDefinition_ComputedAndIdentity(t *testing.T) {
|
||||
writer := NewWriter(&writers.WriterOptions{})
|
||||
|
||||
computed := &models.Column{
|
||||
Name: "full_name",
|
||||
Type: "string",
|
||||
Generated: true,
|
||||
GenerationExpression: "[first] + ' ' + [last]",
|
||||
Default: "ignored",
|
||||
}
|
||||
assert.Equal(t, "[full_name] AS ([first] + ' ' + [last]) PERSISTED", writer.generateColumnDefinition(computed))
|
||||
|
||||
identity := &models.Column{Name: "id", Type: "int", NotNull: true, Identity: true, IdentityGeneration: "ALWAYS"}
|
||||
assert.Equal(t, "[id] INT IDENTITY(1,1) NOT NULL", writer.generateColumnDefinition(identity))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user