Skip to content
This repository has been archived by the owner on May 9, 2023. It is now read-only.

Commit

Permalink
feat: make it T
Browse files Browse the repository at this point in the history
  • Loading branch information
brokeyourbike committed Nov 9, 2022
1 parent c775a23 commit 047fdd3
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 0 deletions.
18 changes: 18 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module github.com/brokeyourbike/jsonarray

go 1.19

require (
gorm.io/driver/mysql v1.4.3
gorm.io/gorm v1.24.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
28 changes: 28 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k=
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs=
gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
107 changes: 107 additions & 0 deletions jsonarray.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package jsonarray

import (
"context"
"database/sql/driver"
"encoding/json"
"fmt"
"strings"

"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
)

// JSONArray defined JSON data type, need to implements driver.Valuer, sql.Scanner interface
type JSONArray[T any] []T

// Value return json value, implement driver.Valuer interface
func (m JSONArray[T]) Value() (driver.Value, error) {
if m == nil {
return nil, nil
}
ba, err := m.MarshalJSON()
return string(ba), err
}

// Scan scan value into Jsonb, implements sql.Scanner interface
func (m *JSONArray[T]) Scan(val interface{}) error {
if val == nil {
*m = make(JSONArray[T], 0)
return nil
}
var ba []byte
switch v := val.(type) {
case []byte:
ba = v
case string:
ba = []byte(v)
default:
return fmt.Errorf("unsupported type: %T", val)
}
t := []T{}
if err := json.Unmarshal(ba, &t); err != nil {
return fmt.Errorf("failed to unmarshal JSON value: %w", err)
}
*m = t
return nil
}

// MarshalJSON to output non base64 encoded []byte
func (m JSONArray[T]) MarshalJSON() ([]byte, error) {
if m == nil {
return []byte("null"), nil
}
t := ([]T)(m)

data, err := json.Marshal(t)
if err != nil {
return nil, fmt.Errorf("failed to marshal JSON value: %w", err)
}

return data, nil
}

// UnmarshalJSON to deserialize []byte
func (m *JSONArray[T]) UnmarshalJSON(b []byte) error {
t := []T{}

err := json.Unmarshal(b, &t)
if err != nil {
return fmt.Errorf("failed to unmarshal JSONB value: %w", err)
}

*m = JSONArray[T](t)
return nil
}

// GormDataType gorm common data type
func (m JSONArray[T]) GormDataType() string {
return "jsonarray"
}

// GormDBDataType gorm db data type
func (JSONArray[T]) GormDBDataType(db *gorm.DB, field *schema.Field) string {
switch db.Dialector.Name() {
case "sqlite":
return "JSON"
case "mysql":
return "JSON"
case "postgres":
return "JSONB"
case "sqlserver":
return "NVARCHAR(MAX)"
}
return ""
}

func (m JSONArray[T]) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
data, _ := m.MarshalJSON()
if db.Dialector.Name() == "mysql" {
if v, ok := db.Dialector.(*mysql.Dialector); ok && !strings.Contains(v.ServerVersion, "MariaDB") {
return gorm.Expr("CAST(? AS JSON)", string(data))
}
}
return gorm.Expr("?", string(data))
}
25 changes: 25 additions & 0 deletions jsonarray_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package jsonarray_test

import (
"testing"

"github.com/brokeyourbike/jsonarray"
"github.com/stretchr/testify/assert"
)

type Dummy struct {
Values []string
}

func TestJSONArray(t *testing.T) {
a1 := jsonarray.JSONArray[int]{1, 2, 3}
a1 = append(a1, 4)
assert.Len(t, a1, 4)

a2 := jsonarray.JSONArray[string]{"a", "b", "c"}
a2 = append(a2, "d")
assert.Len(t, a2, 4)

d := Dummy{Values: a2}
assert.Len(t, d.Values, 4)
}

0 comments on commit 047fdd3

Please sign in to comment.