From 657744efb16d473360942d45fd7ea86cc23f84a9 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Fri, 8 Apr 2016 21:53:27 +0800 Subject: [PATCH] orm: add json & jsonb type support --- orm/cmd_utils.go | 14 +++++++ orm/db.go | 14 +++++-- orm/db_postgres.go | 2 + orm/models_fields.go | 88 +++++++++++++++++++++++++++++++++++++++++++- orm/models_info_f.go | 13 +++++-- 5 files changed, 124 insertions(+), 7 deletions(-) diff --git a/orm/cmd_utils.go b/orm/cmd_utils.go index 13f35722..51e9b8d2 100644 --- a/orm/cmd_utils.go +++ b/orm/cmd_utils.go @@ -90,6 +90,18 @@ checkColumn: } else { col = fmt.Sprintf(s, fi.digits, fi.decimals) } + case TypeJsonField: + if al.Driver != DRPostgres { + fieldType = TypeCharField + goto checkColumn + } + col = T["json"] + case TypeJsonbField: + if al.Driver != DRPostgres { + fieldType = TypeCharField + goto checkColumn + } + col = T["jsonb"] case RelForeignKey, RelOneToOne: fieldType = fi.relModelInfo.fields.pk.fieldType fieldSize = fi.relModelInfo.fields.pk.size @@ -278,6 +290,8 @@ func getColumnDefault(fi *fieldInfo) string { case TypeBooleanField: t = " DEFAULT %s " d = "FALSE" + case TypeJsonField, TypeJsonbField: + d = "{}" } if fi.colDefault { diff --git a/orm/db.go b/orm/db.go index 04cdc30a..0ff97cda 100644 --- a/orm/db.go +++ b/orm/db.go @@ -141,7 +141,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val } else { value = field.Bool() } - case TypeCharField, TypeTextField: + case TypeCharField, TypeTextField, TypeJsonField, TypeJsonbField: if ns, ok := field.Interface().(sql.NullString); ok { value = nil if ns.Valid { @@ -247,6 +247,14 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val field.Set(reflect.ValueOf(tnow.In(DefaultTimeLoc))) } } + case TypeJsonField, TypeJsonbField: + if s, ok := value.(string); (ok && len(s) == 0) || value == nil { + if fi.colDefault && fi.initial.Exist() { + value = fi.initial.String() + } else { + value = nil + } + } } } return value, nil @@ -1093,7 +1101,7 @@ setValue: } value = b } - case fieldType == TypeCharField || fieldType == TypeTextField: + case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJsonField || fieldType == TypeJsonbField: if str == nil { value = ToStr(val) } else { @@ -1239,7 +1247,7 @@ setValue: field.SetBool(value.(bool)) } } - case fieldType == TypeCharField || fieldType == TypeTextField: + case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJsonField || fieldType == TypeJsonbField: if isNative { if ns, ok := field.Interface().(sql.NullString); ok { if value == nil { diff --git a/orm/db_postgres.go b/orm/db_postgres.go index 8fbcb88d..e972c4a2 100644 --- a/orm/db_postgres.go +++ b/orm/db_postgres.go @@ -56,6 +56,8 @@ var postgresTypes = map[string]string{ "uint64": `bigint CHECK("%COL%" >= 0)`, "float64": "double precision", "float64-decimal": "numeric(%d, %d)", + "json": "json", + "jsonb": "jsonb", } // postgresql dbBaser. diff --git a/orm/models_fields.go b/orm/models_fields.go index 1bfbfb2f..a49cde4d 100644 --- a/orm/models_fields.go +++ b/orm/models_fields.go @@ -38,6 +38,8 @@ const ( TypePositiveBigIntegerField TypeFloatField TypeDecimalField + TypeJsonField + TypeJsonbField RelForeignKey RelOneToOne RelManyToMany @@ -49,7 +51,7 @@ const ( const ( IsIntegerField = ^-TypePositiveBigIntegerField >> 5 << 6 IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 9 << 10 - IsRelField = ^-RelReverseMany >> 15 << 16 + IsRelField = ^-RelReverseMany >> 17 << 18 IsFieldType = ^-RelReverseMany<<1 + 1 ) @@ -681,3 +683,87 @@ func (e *TextField) RawValue() interface{} { // verify TextField implement Fielder var _ Fielder = new(TextField) + +// JsonField postgres json field. +type JsonField string + +// Value return JsonField value +func (j JsonField) Value() string { + return string(j) +} + +// Set the JsonField value +func (j *JsonField) Set(d string) { + *j = JsonField(d) +} + +// String convert JsonField to string +func (j *JsonField) String() string { + return j.Value() +} + +// FieldType return enum type +func (j *JsonField) FieldType() int { + return TypeJsonField +} + +// SetRaw convert interface string to string +func (j *JsonField) SetRaw(value interface{}) error { + switch d := value.(type) { + case string: + j.Set(d) + default: + return fmt.Errorf(" unknown value `%s`", value) + } + return nil +} + +// RawValue return JsonField value +func (j *JsonField) RawValue() interface{} { + return j.Value() +} + +// verify JsonField implement Fielder +var _ Fielder = new(JsonField) + +// JsonbField postgres json field. +type JsonbField string + +// Value return JsonbField value +func (j JsonbField) Value() string { + return string(j) +} + +// Set the JsonbField value +func (j *JsonbField) Set(d string) { + *j = JsonbField(d) +} + +// String convert JsonbField to string +func (j *JsonbField) String() string { + return j.Value() +} + +// FieldType return enum type +func (j *JsonbField) FieldType() int { + return TypeJsonbField +} + +// SetRaw convert interface string to string +func (j *JsonbField) SetRaw(value interface{}) error { + switch d := value.(type) { + case string: + j.Set(d) + default: + return fmt.Errorf(" unknown value `%s`", value) + } + return nil +} + +// RawValue return JsonbField value +func (j *JsonbField) RawValue() interface{} { + return j.Value() +} + +// verify JsonbField implement Fielder +var _ Fielder = new(JsonbField) diff --git a/orm/models_info_f.go b/orm/models_info_f.go index 20a7c9d6..1d4d267e 100644 --- a/orm/models_info_f.go +++ b/orm/models_info_f.go @@ -239,8 +239,15 @@ checkType: if err != nil { goto end } - if fieldType == TypeCharField && tags["type"] == "text" { - fieldType = TypeTextField + if fieldType == TypeCharField { + switch tags["type"] { + case "text": + fieldType = TypeTextField + case "json": + fieldType = TypeJsonField + case "jsonb": + fieldType = TypeJsonbField + } } if fieldType == TypeFloatField && (digits != "" || decimals != "") { fieldType = TypeDecimalField @@ -342,7 +349,7 @@ checkType: switch fieldType { case TypeBooleanField: - case TypeCharField: + case TypeCharField, TypeJsonField, TypeJsonbField: if size != "" { v, e := StrTo(size).Int32() if e != nil {