diff --git a/automation/types/session.go b/automation/types/session.go index 23923361c..1091f348e 100644 --- a/automation/types/session.go +++ b/automation/types/session.go @@ -5,6 +5,7 @@ import ( "database/sql/driver" "encoding/json" "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "sync" "time" @@ -193,25 +194,8 @@ func (s *Session) CopyRuntimeStacktrace() { } } -func (set *Stacktrace) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *set = Stacktrace{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, set); err != nil { - return fmt.Errorf("cannot scan '%v' into Stacktrace: %w", string(b), err) - } - } - - return nil -} - -// Scan on WorkflowStepSet gracefully handles conversion from NULL -func (set Stacktrace) Value() (driver.Value, error) { - return json.Marshal(set) -} +func (set *Stacktrace) Scan(src any) error { return sql.ParseJSON(src, set) } +func (set Stacktrace) Value() (driver.Value, error) { return json.Marshal(set) } func (set Stacktrace) String() (str string) { for i, f := range set { diff --git a/automation/types/step.go b/automation/types/step.go index 3c60d5efb..6e83642d3 100644 --- a/automation/types/step.go +++ b/automation/types/step.go @@ -4,7 +4,7 @@ import ( "context" "database/sql/driver" "encoding/json" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "github.com/cortezaproject/corteza-server/pkg/expr" ) @@ -95,25 +95,8 @@ func (vv WorkflowStepSet) HasDeferred() bool { return false } -// Scan on WorkflowStepSet gracefully handles conversion from NULL -func (vv WorkflowStepSet) Value() (driver.Value, error) { - return json.Marshal(vv) -} - -func (vv *WorkflowStepSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = WorkflowStepSet{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into WorkflowStepSet: %w", string(b), err) - } - } - - return nil -} +func (vv *WorkflowStepSet) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv WorkflowStepSet) Value() (driver.Value, error) { return json.Marshal(vv) } func (t WorkflowPath) GetExpr() string { return t.Expr } func (t *WorkflowPath) SetEval(eval expr.Evaluable) { t.eval = eval } @@ -124,22 +107,5 @@ func (t WorkflowPath) Test(ctx context.Context, scope *expr.Vars) (bool, error) return t.eval.Test(ctx, scope) } -func (vv *WorkflowPathSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = WorkflowPathSet{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into WorkflowPathSet: %w", string(b), err) - } - } - - return nil -} - -// Scan on WorkflowPathSet gracefully handles conversion from NULL -func (vv WorkflowPathSet) Value() (driver.Value, error) { - return json.Marshal(vv) -} +func (vv *WorkflowPathSet) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv WorkflowPathSet) Value() (driver.Value, error) { return json.Marshal(vv) } diff --git a/automation/types/trigger.go b/automation/types/trigger.go index 890203e84..77ec77ba1 100644 --- a/automation/types/trigger.go +++ b/automation/types/trigger.go @@ -3,9 +3,9 @@ package types import ( "database/sql/driver" "encoding/json" - "fmt" "github.com/cortezaproject/corteza-server/pkg/expr" "github.com/cortezaproject/corteza-server/pkg/filter" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" ) @@ -89,49 +89,11 @@ func ParseTriggerConstraintSet(ss []string) (p TriggerConstraintSet, err error) return p, parseStringsInput(ss, &p) } -func (vv *TriggerConstraintSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = TriggerConstraintSet{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into TriggerConstraintSet: %w", string(b), err) - } - } +func (vv *TriggerConstraintSet) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv TriggerConstraintSet) Value() (driver.Value, error) { return json.Marshal(vv) } - return nil -} - -func (vv *TriggerMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = TriggerMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into TriggerMeta: %w", string(b), err) - } - } - - return nil -} - -// Scan on TriggerMeta gracefully handles conversion from NULL -func (vv *TriggerMeta) Value() (driver.Value, error) { - if vv == nil { - return []byte("null"), nil - } - - return json.Marshal(vv) -} - -// Scan on TriggerConstraintSet gracefully handles conversion from NULL -func (vv TriggerConstraintSet) Value() (driver.Value, error) { - return json.Marshal(vv) -} +func (vv *TriggerMeta) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv *TriggerMeta) Value() (driver.Value, error) { return json.Marshal(vv) } func (set TriggerSet) FilterByWorkflowID(workflowID uint64) (vv TriggerSet) { // Make sure we never return nil diff --git a/automation/types/workflow.go b/automation/types/workflow.go index c86e4e39e..c2bee2346 100644 --- a/automation/types/workflow.go +++ b/automation/types/workflow.go @@ -4,6 +4,7 @@ import ( "database/sql/driver" "encoding/json" "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/expr" @@ -137,53 +138,15 @@ func (r Workflow) Dict() map[string]interface{} { } } -func (vv *WorkflowMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = WorkflowMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into WorkflowMeta: %w", string(b), err) - } - } - - return nil -} - -// Scan on WorkflowMeta gracefully handles conversion from NULL -func (vv *WorkflowMeta) Value() (driver.Value, error) { - if vv == nil { - return []byte("null"), nil - } - - return json.Marshal(vv) -} - -// Scan on WorkflowStepSet gracefully handles conversion from NULL -func (set WorkflowIssueSet) Value() (driver.Value, error) { - return json.Marshal(set) -} +func (vv *WorkflowMeta) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv *WorkflowMeta) Value() (driver.Value, error) { return json.Marshal(vv) } func (issue *WorkflowIssue) String() string { return fmt.Sprintf("%s [%v]", issue.Description, issue.Culprit) } -func (set *WorkflowIssueSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *set = WorkflowIssueSet{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, set); err != nil { - return fmt.Errorf("cannot scan '%v' into WorkflowIssueSet: %w", string(b), err) - } - } - - return nil -} +func (set *WorkflowIssueSet) Scan(src any) error { return sql.ParseJSON(src, set) } +func (set WorkflowIssueSet) Value() (driver.Value, error) { return json.Marshal(set) } func (set WorkflowIssueSet) Error() string { switch len(set) { diff --git a/compose/types/attachment.go b/compose/types/attachment.go index ddb62db07..180de2e91 100644 --- a/compose/types/attachment.go +++ b/compose/types/attachment.go @@ -3,11 +3,10 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - - "github.com/pkg/errors" ) type ( @@ -99,20 +98,5 @@ func (a *Attachment) imageMeta(in *AttachmentFileMeta, width, height int, animat } } -func (meta *AttachmentMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *meta = AttachmentMeta{} - case []uint8: - if err := json.Unmarshal(value.([]byte), meta); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into attachmentMeta", value) - } - } - - return nil -} - -func (meta AttachmentMeta) Value() (driver.Value, error) { - return json.Marshal(meta) -} +func (meta *AttachmentMeta) Scan(src any) error { return sql.ParseJSON(src, meta) } +func (meta AttachmentMeta) Value() (driver.Value, error) { return json.Marshal(meta) } diff --git a/compose/types/chart.go b/compose/types/chart.go index 1805ca84b..6de4af8a7 100644 --- a/compose/types/chart.go +++ b/compose/types/chart.go @@ -4,13 +4,13 @@ import ( "database/sql/driver" "encoding/json" "github.com/cortezaproject/corteza-server/pkg/locale" + "github.com/cortezaproject/corteza-server/pkg/sql" "github.com/spf13/cast" "strconv" "strings" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" ) type ( @@ -171,24 +171,8 @@ func (set ChartSet) FindByHandle(handle string) *Chart { return nil } -func (cc *ChartConfig) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *cc = ChartConfig{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, cc); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into ChartConfig", string(b)) - } - } - - return nil -} - -func (cc ChartConfig) Value() (driver.Value, error) { - return json.Marshal(cc) -} +func (cc *ChartConfig) Scan(src any) error { return sql.ParseJSON(src, cc) } +func (cc ChartConfig) Value() (driver.Value, error) { return json.Marshal(cc) } func (r *ChartConfigReport) WalkMetrics(fn func(string, map[string]interface{})) { for m := range r.Metrics { diff --git a/compose/types/module_field.go b/compose/types/module_field.go index 9925ce263..70a695367 100644 --- a/compose/types/module_field.go +++ b/compose/types/module_field.go @@ -426,27 +426,11 @@ func (set ModuleFieldSet) Clone() (out ModuleFieldSet) { return out } -func (set *ModuleFieldSet) Scan(src interface{}) error { - if data, ok := src.([]byte); ok { - return json.Unmarshal(data, set) - } - return nil -} +func (set *ModuleFieldSet) Scan(src any) error { return sql.ParseJSON(src, set) } +func (set ModuleFieldSet) Value() (driver.Value, error) { return json.Marshal(set) } -func (set ModuleFieldSet) Value() (driver.Value, error) { - return json.Marshal(set) -} - -func (set *EncodingStrategy) Scan(src interface{}) error { - if data, ok := src.([]byte); ok { - return json.Unmarshal(data, set) - } - return nil -} - -func (set EncodingStrategy) Value() (driver.Value, error) { - return json.Marshal(set) -} +func (set *EncodingStrategy) Scan(src any) error { return sql.ParseJSON(src, set) } +func (set EncodingStrategy) Value() (driver.Value, error) { return json.Marshal(set) } func (set ModuleFieldSet) Names() (names []string) { names = make([]string, len(set)) diff --git a/compose/types/module_field_expr.go b/compose/types/module_field_expr.go index 2a98e7fff..d55d08d13 100644 --- a/compose/types/module_field_expr.go +++ b/compose/types/module_field_expr.go @@ -3,7 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" ) type ( @@ -26,21 +26,5 @@ type ( } ) -func (opt *ModuleFieldExpr) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *opt = ModuleFieldExpr{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, opt); err != nil { - return fmt.Errorf("cannot scan '%v' into ModuleFieldExpr: %v", string(b), err) - } - } - - return nil -} - -func (opt ModuleFieldExpr) Value() (driver.Value, error) { - return json.Marshal(opt) -} +func (opt *ModuleFieldExpr) Scan(src any) error { return sql.ParseJSON(src, opt) } +func (opt ModuleFieldExpr) Value() (driver.Value, error) { return json.Marshal(opt) } diff --git a/compose/types/module_field_options.go b/compose/types/module_field_options.go index cf110f611..e47178aeb 100644 --- a/compose/types/module_field_options.go +++ b/compose/types/module_field_options.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" discovery "github.com/cortezaproject/corteza-server/discovery/types" - "github.com/pkg/errors" + "github.com/cortezaproject/corteza-server/pkg/sql" "github.com/spf13/cast" "strconv" ) @@ -43,24 +43,8 @@ const ( moduleFieldNumberOptionPrecisionMax uint = 6 ) -func (opt *ModuleFieldOptions) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *opt = ModuleFieldOptions{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, opt); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into ModuleFieldOptions", string(b)) - } - } - - return nil -} - -func (opt ModuleFieldOptions) Value() (driver.Value, error) { - return json.Marshal(opt) -} +func (opt *ModuleFieldOptions) Scan(src any) error { return sql.ParseJSON(src, opt) } +func (opt ModuleFieldOptions) Value() (driver.Value, error) { return json.Marshal(opt) } // Bool returns option value for key as boolean true or false // diff --git a/compose/types/namespace.go b/compose/types/namespace.go index bd4f09ac9..a6e05924a 100644 --- a/compose/types/namespace.go +++ b/compose/types/namespace.go @@ -4,7 +4,7 @@ import ( "database/sql/driver" "encoding/json" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" ) @@ -87,21 +87,5 @@ func (set NamespaceSet) FindByHandle(handle string) *Namespace { return nil } -func (nm *NamespaceMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *nm = NamespaceMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, nm); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into NamespaceMeta", string(b)) - } - } - - return nil -} - -func (nm NamespaceMeta) Value() (driver.Value, error) { - return json.Marshal(nm) -} +func (nm *NamespaceMeta) Scan(src any) error { return sql.ParseJSON(src, nm) } +func (nm NamespaceMeta) Value() (driver.Value, error) { return json.Marshal(nm) } diff --git a/compose/types/page.go b/compose/types/page.go index 6e20a5b66..3894855ce 100644 --- a/compose/types/page.go +++ b/compose/types/page.go @@ -3,6 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "strconv" "strings" "time" @@ -10,8 +11,6 @@ import ( "github.com/cortezaproject/corteza-server/pkg/filter" "github.com/cortezaproject/corteza-server/pkg/locale" "github.com/spf13/cast" - - "github.com/pkg/errors" ) type ( @@ -331,24 +330,8 @@ func (set PageSet) FindByHandle(handle string) *Page { return nil } -func (bb *PageBlocks) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *bb = PageBlocks{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, bb); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into PageBlocks", string(b)) - } - } - - return nil -} - -func (bb PageBlocks) Value() (driver.Value, error) { - return json.Marshal(bb) -} +func (bb *PageBlocks) Scan(src any) error { return sql.ParseJSON(src, bb) } +func (bb PageBlocks) Value() (driver.Value, error) { return json.Marshal(bb) } // Helper to extract old encoding to new one func (b *PageBlock) UnmarshalJSON(data []byte) (err error) { @@ -412,24 +395,9 @@ func (set PageSet) RecursiveWalk(parent *Page, fn func(c *Page, parent *Page) er return } -func (bb *PageConfig) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *bb = PageConfig{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, bb); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into PageConfig", string(b)) - } - } - - return nil -} - +func (bb *PageConfig) Scan(src any) error { return sql.ParseJSON(src, bb) } func (bb PageConfig) Value() (driver.Value, error) { // We're not saving button config to the DB; no need for it bb.Buttons = nil - return json.Marshal(bb) } diff --git a/compose/types/record_value.go b/compose/types/record_value.go index 1c2eb33a5..50841406c 100644 --- a/compose/types/record_value.go +++ b/compose/types/record_value.go @@ -4,13 +4,13 @@ import ( "database/sql/driver" "encoding/json" "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "strconv" "strings" "time" "github.com/cortezaproject/corteza-server/pkg/expr" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" "github.com/spf13/cast" ) @@ -317,23 +317,8 @@ func (set RecordValueSet) merge(new RecordValueSet) (out RecordValueSet) { return out } -func (set *RecordValueSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *set = RecordValueSet{} - case []uint8: - if err := json.Unmarshal(value.([]byte), set); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into RecordValueSet", value) - } - } - - return nil -} - -func (set RecordValueSet) Value() (driver.Value, error) { - return json.Marshal(set) -} +func (set *RecordValueSet) Scan(src any) error { return sql.ParseJSON(src, set) } +func (set RecordValueSet) Value() (driver.Value, error) { return json.Marshal(set) } // Simple RVS as string output utility fn that // can help with debugging diff --git a/federation/types/module_field.go b/federation/types/module_field.go index de71d70e9..827979e69 100644 --- a/federation/types/module_field.go +++ b/federation/types/module_field.go @@ -3,8 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" - "errors" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "strings" ) @@ -32,19 +31,5 @@ func (list ModuleFieldSet) HasField(name string) (bool, error) { return false, nil } -func (list ModuleFieldSet) Value() (driver.Value, error) { - return json.Marshal(list) -} - -func (list *ModuleFieldSet) Scan(value interface{}) error { - switch value.(type) { - case nil: - *list = ModuleFieldSet{} - case []uint8: - if err := json.Unmarshal(value.([]byte), list); err != nil { - return errors.New(fmt.Sprintf("cannot scan '%v' into ModuleFieldSet", value)) - } - } - - return nil -} +func (list *ModuleFieldSet) Scan(src any) error { return sql.ParseJSON(src, list) } +func (list ModuleFieldSet) Value() (driver.Value, error) { return json.Marshal(list) } diff --git a/federation/types/module_field_mapping.go b/federation/types/module_field_mapping.go index 72afab6c3..ef01b0b50 100644 --- a/federation/types/module_field_mapping.go +++ b/federation/types/module_field_mapping.go @@ -3,8 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" - "errors" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" ) const ( @@ -43,19 +42,5 @@ func (list *ModuleFieldMappingSet) FindByName(name string, findType ModuleFieldM return nil, nil } -func (list ModuleFieldMappingSet) Value() (driver.Value, error) { - return json.Marshal(list) -} - -func (list *ModuleFieldMappingSet) Scan(value interface{}) error { - switch value.(type) { - case nil: - *list = ModuleFieldMappingSet{} - case []uint8: - if err := json.Unmarshal(value.([]byte), list); err != nil { - return errors.New(fmt.Sprintf("cannot scan '%v' into ModuleFieldMappingSet", value)) - } - } - - return nil -} +func (list *ModuleFieldMappingSet) Scan(src any) error { return sql.ParseJSON(src, list) } +func (list ModuleFieldMappingSet) Value() (driver.Value, error) { return json.Marshal(list) } diff --git a/pkg/actionlog/types.go b/pkg/actionlog/types.go index 6f872cd73..625039b7c 100644 --- a/pkg/actionlog/types.go +++ b/pkg/actionlog/types.go @@ -3,11 +3,11 @@ package actionlog import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "strconv" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" ) type ( @@ -236,21 +236,5 @@ func NewSeverity(s string) Severity { return Debug } -func (m *Meta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *m = Meta{} - case []uint8: - aux := value.([]byte) - if err := json.Unmarshal(aux, m); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into Meta", string(aux)) - } - } - - return nil -} - -func (m Meta) Value() (driver.Value, error) { - return json.Marshal(m) -} +func (m *Meta) Scan(src any) error { return sql.ParseJSON(src, m) } +func (m Meta) Value() (driver.Value, error) { return json.Marshal(m) } diff --git a/pkg/expr/vars.go b/pkg/expr/vars.go index 9d9a247be..a76ca7f8f 100644 --- a/pkg/expr/vars.go +++ b/pkg/expr/vars.go @@ -5,6 +5,7 @@ import ( "database/sql/driver" "encoding/json" "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "reflect" "strings" @@ -248,20 +249,7 @@ func (t *Vars) Decode(dst interface{}) (err error) { return } -func (t *Vars) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *t = Vars{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, t); err != nil { - return fmt.Errorf("cannot scan '%v' into %T: %w", string(b), t, err) - } - } - - return nil -} +func (t *Vars) Scan(src any) error { return sql.ParseJSON(src, t) } func (t *Vars) Value() (driver.Value, error) { if t != nil { diff --git a/pkg/geolocation/geolocation.go b/pkg/geolocation/geolocation.go index 4a9375b95..2410ab81b 100644 --- a/pkg/geolocation/geolocation.go +++ b/pkg/geolocation/geolocation.go @@ -3,6 +3,7 @@ package geolocation import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" ) type ( @@ -30,13 +31,5 @@ func Parse(ss []string) (m Full, err error) { return } -func (set *Full) Scan(src interface{}) error { - if data, ok := src.([]byte); ok { - return json.Unmarshal(data, set) - } - return nil -} - -func (set Full) Value() (driver.Value, error) { - return json.Marshal(set) -} +func (set *Full) Scan(src any) error { return sql.ParseJSON(src, set) } +func (set Full) Value() (driver.Value, error) { return json.Marshal(set) } diff --git a/pkg/messagebus/types/queue.go b/pkg/messagebus/types/queue.go index d9024d382..ce904dae6 100644 --- a/pkg/messagebus/types/queue.go +++ b/pkg/messagebus/types/queue.go @@ -3,7 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" @@ -75,9 +75,8 @@ func (h *QueueMeta) UnmarshalJSON(s []byte) error { return nil } -func (m QueueMeta) Value() (driver.Value, error) { - return json.Marshal(m) -} +func (m *QueueMeta) Scan(src any) error { return sql.ParseJSON(src, m) } +func (m QueueMeta) Value() (driver.Value, error) { return json.Marshal(m) } func (m QueueMeta) MarshalJSON() ([]byte, error) { @@ -95,19 +94,6 @@ func (m QueueMeta) MarshalJSON() ([]byte, error) { }) } -func (m *QueueMeta) Scan(value interface{}) error { - switch value.(type) { - case nil: - *m = QueueMeta{} - case []uint8: - if err := json.Unmarshal(value.([]byte), m); err != nil { - return fmt.Errorf("cannot scan '%v' into QueueMeta", value) - } - } - - return nil -} - func (s *Queue) CanDispatch() bool { return s.Meta.DispatchEvents } diff --git a/pkg/sql/json.go b/pkg/sql/json.go index 2c2ebd0f0..0ee5a05ea 100644 --- a/pkg/sql/json.go +++ b/pkg/sql/json.go @@ -5,7 +5,7 @@ import ( "fmt" ) -func ParseJSON(raw any, dest any) (error) { +func ParseJSON(raw any, dest any) error { var ( data []byte ) diff --git a/system/types/apigw_filter.go b/system/types/apigw_filter.go index 020a44a02..0447b583d 100644 --- a/system/types/apigw_filter.go +++ b/system/types/apigw_filter.go @@ -3,7 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" @@ -46,21 +46,5 @@ type ( } ) -func (vv *ApigwFilterParams) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = ApigwFilterParams{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into ApigwFilterParams: %w", string(b), err) - } - } - - return nil -} - -func (vv ApigwFilterParams) Value() (driver.Value, error) { - return json.Marshal(vv) -} +func (vv *ApigwFilterParams) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv ApigwFilterParams) Value() (driver.Value, error) { return json.Marshal(vv) } diff --git a/system/types/apigw_route.go b/system/types/apigw_route.go index 19abf0381..da2e8e501 100644 --- a/system/types/apigw_route.go +++ b/system/types/apigw_route.go @@ -3,10 +3,10 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" ) type ( @@ -49,21 +49,5 @@ type ( } ) -func (cc *ApigwRouteMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *cc = ApigwRouteMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, cc); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into ApigwRouteMeta", string(b)) - } - } - - return nil -} - -func (cc ApigwRouteMeta) Value() (driver.Value, error) { - return json.Marshal(cc) -} +func (cc *ApigwRouteMeta) Scan(src any) error { return sql.ParseJSON(src, cc) } +func (cc ApigwRouteMeta) Value() (driver.Value, error) { return json.Marshal(cc) } diff --git a/system/types/applications.go b/system/types/applications.go index 1b3ba56e5..c22fa10c7 100644 --- a/system/types/applications.go +++ b/system/types/applications.go @@ -3,11 +3,10 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - - "github.com/pkg/errors" ) type ( @@ -77,23 +76,8 @@ func (a *Application) Valid() bool { return a.ID > 0 && a.DeletedAt == nil } -func (au *ApplicationUnify) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - au = nil - case []uint8: - if err := json.Unmarshal(value.([]byte), au); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into ApplicationUnify", value) - } - } - - return nil -} - -func (au ApplicationUnify) Value() (driver.Value, error) { - return json.Marshal(au) -} +func (au *ApplicationUnify) Scan(src any) error { return sql.ParseJSON(src, au) } +func (au ApplicationUnify) Value() (driver.Value, error) { return json.Marshal(au) } // // // These will get generated later on diff --git a/system/types/attachment.go b/system/types/attachment.go index 9057118b6..ee45daf1a 100644 --- a/system/types/attachment.go +++ b/system/types/attachment.go @@ -3,11 +3,10 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - - "github.com/pkg/errors" ) type ( @@ -91,20 +90,8 @@ func (a *Attachment) imageMeta(in *AttachmentFileMeta, width, height int, animat } } -func (meta *AttachmentMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *meta = AttachmentMeta{} - case []uint8: - if err := json.Unmarshal(value.([]byte), meta); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into attachmentMeta", value) - } - } - - return nil -} - +func (meta *AttachmentMeta) Scan(src any) error { return sql.ParseJSON(src, meta) } func (meta AttachmentMeta) Value() (driver.Value, error) { + return json.Marshal(meta) } diff --git a/system/types/auth_client.go b/system/types/auth_client.go index 811909770..bfff9d4c7 100644 --- a/system/types/auth_client.go +++ b/system/types/auth_client.go @@ -4,6 +4,7 @@ import ( "database/sql/driver" "encoding/json" "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" @@ -173,50 +174,8 @@ func (r *AuthClient) Verify() error { return nil } -func (vv *AuthClientMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = AuthClientMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into AuthClientMeta: %w", string(b), err) - } - } +func (vv *AuthClientMeta) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv *AuthClientMeta) Value() (driver.Value, error) { return json.Marshal(vv) } - return nil -} - -// Scan on AuthClientMeta gracefully handles conversion from NULL -func (vv *AuthClientMeta) Value() (driver.Value, error) { - if vv == nil { - return []byte("null"), nil - } - - return json.Marshal(vv) -} - -func (vv *AuthClientSecurity) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = AuthClientSecurity{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into AuthClientSecurity: %w", string(b), err) - } - } - - return nil -} - -// Scan on AuthClientSecurity gracefully handles conversion from NULL -func (vv *AuthClientSecurity) Value() (driver.Value, error) { - if vv == nil { - return []byte("null"), nil - } - - return json.Marshal(vv) -} +func (vv *AuthClientSecurity) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv *AuthClientSecurity) Value() (driver.Value, error) { return json.Marshal(vv) } diff --git a/system/types/dal_connection.go b/system/types/dal_connection.go index 256edb3db..436608a66 100644 --- a/system/types/dal_connection.go +++ b/system/types/dal_connection.go @@ -3,13 +3,13 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/dal" "github.com/cortezaproject/corteza-server/pkg/dal/capabilities" "github.com/cortezaproject/corteza-server/pkg/filter" "github.com/cortezaproject/corteza-server/pkg/geolocation" - "github.com/pkg/errors" ) type ( @@ -109,40 +109,8 @@ func ParseConnectionCapabilities(ss []string) (m ConnectionCapabilities, err err return } -func (nm *ConnectionConfig) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *nm = ConnectionConfig{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, nm); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into ConnectionConfig", string(b)) - } - } +func (nm *ConnectionConfig) Scan(src any) error { return sql.ParseJSON(src, nm) } +func (nm ConnectionConfig) Value() (driver.Value, error) { return json.Marshal(nm) } - return nil -} - -func (nm ConnectionConfig) Value() (driver.Value, error) { - return json.Marshal(nm) -} - -func (nm *ConnectionCapabilities) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *nm = ConnectionCapabilities{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, nm); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into ConnectionCapabilities", string(b)) - } - } - - return nil -} - -func (nm ConnectionCapabilities) Value() (driver.Value, error) { - return json.Marshal(nm) -} +func (nm *ConnectionCapabilities) Scan(src any) error { return sql.ParseJSON(src, nm) } +func (nm ConnectionCapabilities) Value() (driver.Value, error) { return json.Marshal(nm) } diff --git a/system/types/dal_sensitivity_level.go b/system/types/dal_sensitivity_level.go index 5ae5c0355..422d1e34a 100644 --- a/system/types/dal_sensitivity_level.go +++ b/system/types/dal_sensitivity_level.go @@ -3,10 +3,10 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" ) type ( @@ -57,24 +57,8 @@ func ParseDalSensitivityLevelMeta(ss []string) (m DalSensitivityLevelMeta, err e return } -func (nm *DalSensitivityLevelMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *nm = DalSensitivityLevelMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, nm); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into DalSensitivityLevelMeta", string(b)) - } - } - - return nil -} - -func (nm DalSensitivityLevelMeta) Value() (driver.Value, error) { - return json.Marshal(nm) -} +func (nm *DalSensitivityLevelMeta) Scan(src any) error { return sql.ParseJSON(src, nm) } +func (nm DalSensitivityLevelMeta) Value() (driver.Value, error) { return json.Marshal(nm) } func (ss DalSensitivityLevelSet) Len() int { return len(ss) } func (ss DalSensitivityLevelSet) Less(i, j int) bool { diff --git a/system/types/data_privacy.go b/system/types/data_privacy.go index 3fbc25378..b9553acab 100644 --- a/system/types/data_privacy.go +++ b/system/types/data_privacy.go @@ -3,10 +3,10 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" ) type ( @@ -171,21 +171,5 @@ func ParseDataPrivacyRequestPayload(ii []string) (out DataPrivacyRequestPayloadS return out, err } -func (bb *DataPrivacyRequestPayloadSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *bb = DataPrivacyRequestPayloadSet{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, bb); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into DataPrivacyRequestPayloadSet", string(b)) - } - } - - return nil -} - -func (bb DataPrivacyRequestPayloadSet) Value() (driver.Value, error) { - return json.Marshal(bb) -} +func (bb *DataPrivacyRequestPayloadSet) Scan(src any) error { return sql.ParseJSON(src, bb) } +func (bb DataPrivacyRequestPayloadSet) Value() (driver.Value, error) { return json.Marshal(bb) } diff --git a/system/types/queue.go b/system/types/queue.go index 41d3f0820..a2e7c6d95 100644 --- a/system/types/queue.go +++ b/system/types/queue.go @@ -3,8 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" - "errors" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" @@ -87,9 +86,8 @@ func (h *QueueMeta) UnmarshalJSON(s []byte) error { return nil } -func (m QueueMeta) Value() (driver.Value, error) { - return json.Marshal(m) -} +func (m *QueueMeta) Scan(src any) error { return sql.ParseJSON(src, m) } +func (m QueueMeta) Value() (driver.Value, error) { return json.Marshal(m) } func (m QueueMeta) MarshalJSON() ([]byte, error) { @@ -107,19 +105,6 @@ func (m QueueMeta) MarshalJSON() ([]byte, error) { }) } -func (m *QueueMeta) Scan(value interface{}) error { - switch value.(type) { - case nil: - *m = QueueMeta{} - case []uint8: - if err := json.Unmarshal(value.([]byte), m); err != nil { - return errors.New(fmt.Sprintf("cannot scan '%v' into QueueMeta", value)) - } - } - - return nil -} - func (s *Queue) CanDispatch() bool { return s.Meta.DispatchEvents } diff --git a/system/types/report.go b/system/types/report.go index ad464c134..97225a8ae 100644 --- a/system/types/report.go +++ b/system/types/report.go @@ -3,7 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" @@ -134,89 +134,18 @@ func (pp ReportBlockSet) ModelSteps() report.StepDefinitionSet { // Store stuff -func (vv *ReportMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = ReportMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into ReportMeta: %w", string(b), err) - } - } +func (vv *ReportMeta) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv *ReportMeta) Value() (driver.Value, error) { return json.Marshal(vv) } - return nil -} - -// Scan on ReportMeta gracefully handles conversion from NULL -func (vv *ReportMeta) Value() (driver.Value, error) { - if vv == nil { - return []byte("null"), nil - } - - return json.Marshal(vv) -} - -// Scan on ReportBlockSet gracefully handles conversion from NULL -func (vv ReportBlockSet) Value() (driver.Value, error) { - return json.Marshal(vv) -} - -func (vv *ReportBlockSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = ReportBlockSet{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into ReportBlockSet: %w", string(b), err) - } - } - - return nil -} +func (vv *ReportBlockSet) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv ReportBlockSet) Value() (driver.Value, error) { return json.Marshal(vv) } // Scan on ReportDataSourceSet gracefully handles conversion from NULL -func (vv ReportDataSourceSet) Value() (driver.Value, error) { - return json.Marshal(vv) -} +func (vv *ReportDataSourceSet) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv ReportDataSourceSet) Value() (driver.Value, error) { return json.Marshal(vv) } -func (vv *ReportDataSourceSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = ReportDataSourceSet{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into ReportDataSourceSet: %w", string(b), err) - } - } - - return nil -} - -// Scan on ReportScenarioSet gracefully handles conversion from NULL -func (vv ReportScenarioSet) Value() (driver.Value, error) { - return json.Marshal(vv) -} - -func (vv *ReportScenarioSet) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = ReportScenarioSet{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into ReportDataSourceSet: %w", string(b), err) - } - } - - return nil -} +func (vv *ReportScenarioSet) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv ReportScenarioSet) Value() (driver.Value, error) { return json.Marshal(vv) } // func (r *Report) decodeTranslations(tt locale.ResourceTranslationIndex) { // var aux *locale.ResourceTranslation diff --git a/system/types/resource_translation.go b/system/types/resource_translation.go index bb502cf80..ed6dfc18e 100644 --- a/system/types/resource_translation.go +++ b/system/types/resource_translation.go @@ -53,7 +53,7 @@ func (l Lang) Value() (driver.Value, error) { return l.String(), nil } -func (l *Lang) Scan(value interface{}) error { +func (l *Lang) Scan(value any) error { v := "" //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 diff --git a/system/types/role.go b/system/types/role.go index 5a15621c6..5b9c52d57 100644 --- a/system/types/role.go +++ b/system/types/role.go @@ -3,7 +3,7 @@ package types import ( "database/sql/driver" "encoding/json" - "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" @@ -101,26 +101,5 @@ func (set RoleSet) FindByHandle(handle string) *Role { return nil } -func (vv *RoleMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *vv = RoleMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, vv); err != nil { - return fmt.Errorf("cannot scan '%v' into RoleMeta: %w", string(b), err) - } - } - - return nil -} - -// Scan on RoleMeta gracefully handles conversion from NULL -func (vv *RoleMeta) Value() (driver.Value, error) { - if vv == nil { - return []byte("null"), nil - } - - return json.Marshal(vv) -} +func (vv *RoleMeta) Scan(src any) error { return sql.ParseJSON(src, vv) } +func (vv *RoleMeta) Value() (driver.Value, error) { return json.Marshal(vv) } diff --git a/system/types/template.go b/system/types/template.go index 59cf14c5c..57ab9e9c3 100644 --- a/system/types/template.go +++ b/system/types/template.go @@ -3,10 +3,10 @@ package types import ( "database/sql/driver" "encoding/json" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" ) type ( @@ -73,24 +73,8 @@ const ( DocumentTypePDF DocumentType = "application/pdf" ) -func (t *TemplateMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *t = TemplateMeta{} - case []uint8: - b := value.([]byte) - if err := json.Unmarshal(b, t); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into TemplateMeta", string(b)) - } - } - - return nil -} - -func (t TemplateMeta) Value() (driver.Value, error) { - return json.Marshal(t) -} +func (t *TemplateMeta) Scan(src any) error { return sql.ParseJSON(src, t) } +func (t TemplateMeta) Value() (driver.Value, error) { return json.Marshal(t) } func (t Template) Clone() *Template { c := &t diff --git a/system/types/user.go b/system/types/user.go index 626dd7e40..4a07e9974 100644 --- a/system/types/user.go +++ b/system/types/user.go @@ -4,11 +4,10 @@ import ( "database/sql/driver" "encoding/json" "fmt" + "github.com/cortezaproject/corteza-server/pkg/sql" "time" "github.com/cortezaproject/corteza-server/pkg/filter" - - "github.com/pkg/errors" ) type ( @@ -156,26 +155,5 @@ func (u *User) Clone() *User { } } -func (meta *UserMeta) Scan(value interface{}) error { - //lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8 - switch value.(type) { - case nil: - *meta = UserMeta{} - return nil - case []uint8: - if err := json.Unmarshal(value.([]byte), meta); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into User.Meta", value) - } - return nil - case string: - if err := json.Unmarshal([]byte(value.(string)), meta); err != nil { - return errors.Wrapf(err, "cannot scan '%v' into User.Meta", value) - } - return nil - } - return errors.Errorf("User.Meta: unknown type %T, expected []uint8", value) -} - -func (meta *UserMeta) Value() (driver.Value, error) { - return json.Marshal(meta) -} +func (meta *UserMeta) Scan(src any) error { return sql.ParseJSON(src, meta) } +func (meta *UserMeta) Value() (driver.Value, error) { return json.Marshal(meta) }