diff --git a/schemas/column.go b/schemas/column.go index 08d34b91..2da18ee5 100644 --- a/schemas/column.go +++ b/schemas/column.go @@ -26,6 +26,7 @@ type Column struct { FieldIndex []int // Available only when parsed from a struct SQLType SQLType IsJSON bool + IsJSONB bool Length int64 Length2 int64 Nullable bool diff --git a/tags/parser.go b/tags/parser.go index 53ef0c10..8b97160e 100644 --- a/tags/parser.go +++ b/tags/parser.go @@ -250,10 +250,16 @@ func (parser *Parser) parseFieldWithTags(table *schemas.Table, fieldIndex int, f } if col.SQLType.Name == "" { - var err error - col.SQLType, err = parser.getSQLTypeByType(field.Type) - if err != nil { - return nil, err + if col.IsJSONB { // check is jsonb first because it is also json + col.SQLType = schemas.SQLType{Name: schemas.Jsonb} + } else if col.IsJSON { + col.SQLType = schemas.SQLType{Name: schemas.Json} + } else { + var err error + col.SQLType, err = parser.getSQLTypeByType(field.Type) + if err != nil { + return nil, err + } } } if ctx.isUnsigned && col.SQLType.IsNumeric() && !strings.HasPrefix(col.SQLType.Name, "UNSIGNED") { diff --git a/tags/parser_test.go b/tags/parser_test.go index 434cfc07..be6ea6fe 100644 --- a/tags/parser_test.go +++ b/tags/parser_test.go @@ -577,7 +577,7 @@ func TestParseWithJSONB(t *testing.T) { assert.EqualValues(t, "struct_with_jsonb", table.Name) assert.EqualValues(t, 1, len(table.Columns())) assert.EqualValues(t, "default1", table.Columns()[0].Name) - assert.True(t, table.Columns()[0].IsJSON) + assert.True(t, table.Columns()[0].IsJSONB) } func TestParseWithSQLType(t *testing.T) { @@ -617,3 +617,53 @@ func TestParseWithSQLType(t *testing.T) { assert.EqualValues(t, "DATETIME", table.Columns()[3].SQLType.Name) assert.EqualValues(t, "UUID", table.Columns()[4].SQLType.Name) } + +func TestParseWithJSONLongText(t *testing.T) { + parser := NewParser( + "db", + dialects.QueryDialect("mysql"), + names.GonicMapper{ + "JSON": true, + }, + names.GonicMapper{ + "JSON": true, + }, + caches.NewManager(), + ) + + type StructWithJSONLongText struct { + Col1 string `db:"LongText json"` + } + + table, err := parser.Parse(reflect.ValueOf(new(StructWithJSONLongText))) + assert.NoError(t, err) + assert.EqualValues(t, "struct_with_json_long_text", table.Name) + assert.EqualValues(t, 1, len(table.Columns())) + assert.EqualValues(t, "col1", table.Columns()[0].Name) + assert.EqualValues(t, "LONGTEXT", table.Columns()[0].SQLType.Name) + assert.EqualValues(t, true, table.Columns()[0].IsJSON) + + type StructWithJSONLongText2 struct { + Col1 string `db:"json"` + } + + table, err = parser.Parse(reflect.ValueOf(new(StructWithJSONLongText2))) + assert.NoError(t, err) + assert.EqualValues(t, "struct_with_json_long_text2", table.Name) + assert.EqualValues(t, 1, len(table.Columns())) + assert.EqualValues(t, "col1", table.Columns()[0].Name) + assert.EqualValues(t, "JSON", table.Columns()[0].SQLType.Name) + assert.EqualValues(t, true, table.Columns()[0].IsJSON) + + type StructWithJSONLongText3 struct { + Col1 string `db:"jsonb"` + } + + table, err = parser.Parse(reflect.ValueOf(new(StructWithJSONLongText3))) + assert.NoError(t, err) + assert.EqualValues(t, "struct_with_json_long_text3", table.Name) + assert.EqualValues(t, 1, len(table.Columns())) + assert.EqualValues(t, "col1", table.Columns()[0].Name) + assert.EqualValues(t, "JSONB", table.Columns()[0].SQLType.Name) + assert.EqualValues(t, true, table.Columns()[0].IsJSONB) +} diff --git a/tags/tag.go b/tags/tag.go index 55f0b7c7..cfe35c8b 100644 --- a/tags/tag.go +++ b/tags/tag.go @@ -124,10 +124,16 @@ var defaultTagHandlers = map[string]Handler{ "EXTENDS": ExtendsTagHandler, "UNSIGNED": UnsignedTagHandler, "COLLATE": CollateTagHandler, + "JSON": JSONTagHandler, + "JSONB": JSONBTagHandler, } func init() { for k := range schemas.SqlTypes { + // don't override default tag handlers + if _, ok := defaultTagHandlers[k]; ok { + continue + } defaultTagHandlers[k] = SQLTypeTagHandler } } @@ -293,12 +299,20 @@ func CollateTagHandler(ctx *Context) error { return nil } +func JSONTagHandler(ctx *Context) error { + ctx.col.IsJSON = true + return nil +} + +func JSONBTagHandler(ctx *Context) error { + ctx.col.IsJSONB = true + ctx.col.IsJSON = true // jsonb is also json + return nil +} + // SQLTypeTagHandler describes SQL Type tag handler func SQLTypeTagHandler(ctx *Context) error { ctx.col.SQLType = schemas.SQLType{Name: ctx.tagUname} - if ctx.tagUname == "JSON" || ctx.tagUname == "JSONB" { - ctx.col.IsJSON = true - } if len(ctx.params) == 0 { return nil } diff --git a/tests/schema_test.go b/tests/schema_test.go index 9c43d982..f2487175 100644 --- a/tests/schema_test.go +++ b/tests/schema_test.go @@ -752,20 +752,18 @@ func getKeysFromMap(m map[string]*schemas.Index) []string { return ss } - type SyncTestUser struct { - Id int64 `xorm:"pk autoincr 'id' comment('primary key 1')"` - Name string `xorm:"'name' notnull comment('nickname')" json:"name"` + Id int64 `xorm:"pk autoincr 'id' comment('primary key 1')"` + Name string `xorm:"'name' notnull comment('nickname')" json:"name"` } func (m *SyncTestUser) TableName() string { return "sync_test_user" } - type SyncTestUser2 struct { - Id int64 `xorm:"pk autoincr 'id' comment('primary key 2')"` - Name string `xorm:"'name' notnull comment('nickname')" json:"name"` + Id int64 `xorm:"pk autoincr 'id' comment('primary key 2')"` + Name string `xorm:"'name' notnull comment('nickname')" json:"name"` } func (m *SyncTestUser2) TableName() string { @@ -789,5 +787,36 @@ func TestSync2_3(t *testing.T) { assert.EqualValues(t, tables[0].GetColumn("id").Comment, tableInfo.GetColumn("id").Comment) } - -} \ No newline at end of file +} + +func TestSyncJSON(t *testing.T) { + type SyncTestJSON struct { + Id int64 + Value string `xorm:"LONGTEXT JSON 'value' comment('json value')"` + } + + assert.NoError(t, PrepareEngine()) + assertSync(t, new(SyncTestJSON)) + + assert.NoError(t, testEngine.Sync(new(SyncTestJSON))) + tables, err := testEngine.DBMetas() + assert.NoError(t, err) + + tableInfo, err := testEngine.TableInfo(new(SyncTestJSON)) + assert.NoError(t, err) + + assert.EqualValues(t, tables[0].GetColumn("id").IsAutoIncrement, tableInfo.GetColumn("id").IsAutoIncrement) + assert.EqualValues(t, tables[0].GetColumn("id").Name, tableInfo.GetColumn("id").Name) + if testEngine.Dialect().URI().DBType == schemas.MYSQL { + assert.EqualValues(t, tables[0].GetColumn("id").SQLType.Name, tableInfo.GetColumn("id").SQLType.Name) + } + assert.EqualValues(t, tables[0].GetColumn("id").Nullable, tableInfo.GetColumn("id").Nullable) + + assert.EqualValues(t, tables[0].GetColumn("value").IsAutoIncrement, tableInfo.GetColumn("value").IsAutoIncrement) + assert.EqualValues(t, tables[0].GetColumn("value").Name, tableInfo.GetColumn("value").Name) + assert.EqualValues(t, tables[0].GetColumn("value").Nullable, tableInfo.GetColumn("value").Nullable) + + if testEngine.Dialect().URI().DBType == schemas.MYSQL { + assert.EqualValues(t, tables[0].GetColumn("value").SQLType.Name, tableInfo.GetColumn("value").SQLType.Name) + } +}