Skip to content

Commit

Permalink
dev: misc update (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
keroxp authored Jan 11, 2023
1 parent decb200 commit 82d9086
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 79 deletions.
68 changes: 68 additions & 0 deletions model/testmodel/testmodel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package testmodel

type MultiplePrimaryKey struct {
Pk1 string `exql:"column:pk1;primary"`
Pk2 string `exql:"column:pk2;primary"`
Other int `exql:"column:other"`
}

func (*MultiplePrimaryKey) TableName() string {
return "dummy"
}

type NoTag struct {
}

func (*NoTag) TableName() string {
return "dummy"
}

type BadTableName struct {
Id int `exql:"column:id;primary;auto_increment"`
}

func (BadTableName) TableName() string {
return ""
}

type NoPrimaryKey struct {
Id int `exql:"column:id;auto_increment"`
}

func (NoPrimaryKey) TableName() string {
return ""
}

type NoColumnTag struct {
Id int `exql:"primary;auto_increment"`
}

func (NoColumnTag) TableName() string {
return ""
}

type BadTag struct {
Id int `exql:"a;a:1"`
}

func (BadTag) TableName() string {
return ""
}

type NoAutoIncrementKey struct {
Id int `exql:"column:id;primary"`
Name string `exql:"column:name"`
}

func (s *NoAutoIncrementKey) TableName() string {
return "sampleNoAutoIncrementKey"
}

type PrimaryUint64 struct {
Id uint64 `exql:"column:id;primary;auto_increment"`
Name string `exql:"column:name"`
}

func (s *PrimaryUint64) TableName() string {
return "samplePrimaryUint64"
}
14 changes: 10 additions & 4 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ func Where(str string, args ...any) q.Condition {
type ModelMetadata struct {
TableName string
AutoIncrementField *reflect.Value
Values q.KeyIterator
PrimaryKeyColumns []string
PrimaryKeyValues []any
Values q.KeyIterator[any]
}

func QueryForInsert(modelPtr Model) (q.Query, *reflect.Value, error) {
Expand Down Expand Up @@ -65,7 +67,8 @@ func AggregateModelMetadata(modelPtr Model) (*ModelMetadata, error) {
// *User -> User
objType = objType.Elem()
exqlTagCount := 0
var primaryKeyFields []*reflect.Value
var primaryKeyColumns []string
var primaryKeyValues []any
var autoIncrementField *reflect.Value
for i := 0; i < objType.NumField(); i++ {
f := objType.Field(i)
Expand All @@ -81,7 +84,8 @@ func AggregateModelMetadata(modelPtr Model) (*ModelMetadata, error) {
exqlTagCount++
if _, primary := tags["primary"]; primary {
primaryKeyField := objValue.Elem().Field(i)
primaryKeyFields = append(primaryKeyFields, &primaryKeyField)
primaryKeyColumns = append(primaryKeyColumns, colName)
primaryKeyValues = append(primaryKeyValues, primaryKeyField.Interface())
}
if _, autoIncrement := tags["auto_increment"]; autoIncrement {
field := objValue.Elem().Field(i)
Expand All @@ -96,7 +100,7 @@ func AggregateModelMetadata(modelPtr Model) (*ModelMetadata, error) {
return nil, xerrors.Errorf("obj doesn't have exql tags in any fields")
}

if len(primaryKeyFields) == 0 {
if len(primaryKeyColumns) == 0 {
return nil, xerrors.Errorf("table has no primary key")
}

Expand All @@ -107,6 +111,8 @@ func AggregateModelMetadata(modelPtr Model) (*ModelMetadata, error) {
return &ModelMetadata{
TableName: tableName,
AutoIncrementField: autoIncrementField,
PrimaryKeyColumns: primaryKeyColumns,
PrimaryKeyValues: primaryKeyValues,
Values: q.NewKeyIterator(data),
}, nil
}
Expand Down
30 changes: 15 additions & 15 deletions query/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,54 @@ import (
"golang.org/x/xerrors"
)

type keyIterator struct {
type keyIterator[T any] struct {
keys []string
values []any
values []T
}

type KeyIterator interface {
Get(i int) (string, any)
type KeyIterator[T any] interface {
Get(i int) (string, T)
Keys() []string
Values() []any
Values() []T
Size() int
Map() map[string]any
Map() map[string]T
}

func NewKeyIterator(data map[string]any) KeyIterator {
func NewKeyIterator[T any](data map[string]T) KeyIterator[T] {
var keys []string
for k := range data {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
return strings.Compare(keys[i], keys[j]) < 0
})
var values []any
var values []T
for _, v := range keys {
values = append(values, data[v])
}
return &keyIterator{keys: keys, values: values}
return &keyIterator[T]{keys: keys, values: values}
}

func (e *keyIterator) Get(i int) (string, any) {
func (e *keyIterator[T]) Get(i int) (string, T) {
k := e.keys[i]
v := e.values[i]
return k, v
}

func (e *keyIterator) Size() int {
func (e *keyIterator[T]) Size() int {
return len(e.keys)
}

func (k *keyIterator) Keys() []string {
func (k *keyIterator[T]) Keys() []string {
return k.keys
}

func (k *keyIterator) Values() []any {
func (k *keyIterator[T]) Values() []T {
return k.values
}

func (k *keyIterator) Map() map[string]any {
res := map[string]any{}
func (k *keyIterator[T]) Map() map[string]T {
res := map[string]T{}
for i := 0; i < k.Size(); i++ {
res[k.keys[i]] = k.values[i]
}
Expand Down
33 changes: 25 additions & 8 deletions query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/loilo-inc/exql/v2"
"github.com/loilo-inc/exql/v2/model"
"github.com/loilo-inc/exql/v2/model/testmodel"
"github.com/stretchr/testify/assert"
"github.com/volatiletech/null"
)
Expand Down Expand Up @@ -65,9 +66,26 @@ func TestAggregateModelMetadata(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "users", m.TableName)
assert.NotNil(t, m.AutoIncrementField)
assert.ElementsMatch(t, []string{"id"}, m.PrimaryKeyColumns)
assert.ElementsMatch(t, []any{int64(0)}, m.PrimaryKeyValues)
assert.ElementsMatch(t, []string{"first_name", "last_name"}, m.Values.Keys())
assert.ElementsMatch(t, []any{null.StringFrom("first"), null.StringFrom("name")}, m.Values.Values())
})
t.Run("multiple primary key", func(t *testing.T) {
data := &testmodel.MultiplePrimaryKey{
Pk1: "val1",
Pk2: "val2",
Other: 1,
}
md, err := exql.AggregateModelMetadata(data)
assert.NoError(t, err)
assert.Equal(t, data.TableName(), md.TableName)
assert.Nil(t, md.AutoIncrementField)
assert.ElementsMatch(t, []string{"pk1", "pk2"}, md.PrimaryKeyColumns)
assert.ElementsMatch(t, []any{"val1", "val2"}, md.PrimaryKeyValues)
assert.ElementsMatch(t, []string{"pk1", "pk2", "other"}, md.Values.Keys())
assert.ElementsMatch(t, []any{"val1", "val2", 1}, md.Values.Values())
})
assertInvalid := func(t *testing.T, m exql.Model, e string) {
s, f, err := exql.QueryForInsert(m)
assert.Nil(t, s)
Expand All @@ -82,20 +100,19 @@ func TestAggregateModelMetadata(t *testing.T) {
assertInvalid(t, user, "object must be pointer of struct")
})
t.Run("should error if TableName() doesn't return string", func(t *testing.T) {
var sam sampleBadTableName
assertInvalid(t, &sam, "empty table name")
assertInvalid(t, &testmodel.BadTableName{}, "empty table name")
})
t.Run("should error if field doesn't have column tag", func(t *testing.T) {
var sam sampleNoColumnTag
assertInvalid(t, &sam, "column tag is not set")
assertInvalid(t, &testmodel.NoColumnTag{}, "column tag is not set")
})
t.Run("should error if field tag is invalid", func(t *testing.T) {
var sam sampleBadTag
assertInvalid(t, &sam, "duplicated tag: a")
assertInvalid(t, &testmodel.BadTag{}, "duplicated tag: a")
})
t.Run("should error if dest has no primary key tag", func(t *testing.T) {
var sam sampleNoPrimaryKey
assertInvalid(t, &sam, "table has no primary key")
assertInvalid(t, &testmodel.NoPrimaryKey{}, "table has no primary key")
})
t.Run("shoud error if no exql tags found", func(t *testing.T) {
assertInvalid(t, &testmodel.NoTag{}, "obj doesn't have exql tags in any fields")
})
}

Expand Down
55 changes: 3 additions & 52 deletions saver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,61 +12,12 @@ import (
"github.com/loilo-inc/exql/v2/mocks/mock_exql"
"github.com/loilo-inc/exql/v2/mocks/mock_query"
"github.com/loilo-inc/exql/v2/model"
"github.com/loilo-inc/exql/v2/model/testmodel"
q "github.com/loilo-inc/exql/v2/query"
"github.com/stretchr/testify/assert"
"github.com/volatiletech/null"
)

type sampleBadTableName struct {
Id int `exql:"column:id;primary;auto_increment"`
}

func (sampleBadTableName) TableName() string {
return ""
}

type sampleNoPrimaryKey struct {
Id int `exql:"column:id;auto_increment"`
}

func (sampleNoPrimaryKey) TableName() string {
return ""
}

type sampleNoColumnTag struct {
Id int `exql:"primary;auto_increment"`
}

func (sampleNoColumnTag) TableName() string {
return ""
}

type sampleBadTag struct {
Id int `exql:"a;a:1"`
}

func (sampleBadTag) TableName() string {
return ""
}

type sampleNoAutoIncrementKey struct {
Id int `exql:"column:id;primary"`
Name string `exql:"column:name"`
}

func (s *sampleNoAutoIncrementKey) TableName() string {
return "sampleNoAutoIncrementKey"
}

type samplePrimaryUint64 struct {
Id uint64 `exql:"column:id;primary;auto_increment"`
Name string `exql:"column:name"`
}

func (s *samplePrimaryUint64) TableName() string {
return "samplePrimaryUint64"
}

func TestSaver_Insert(t *testing.T) {
d := testDb()
m := exql.NewMapper()
Expand Down Expand Up @@ -128,7 +79,7 @@ func TestSaver_Insert(t *testing.T) {
db, mock, _ := sqlmock.New()
mock.ExpectExec("INSERT INTO `samplePrimaryUint64`").WillReturnResult(sqlmock.NewResult(11, 1))
s := exql.NewSaver(db)
user := &samplePrimaryUint64{}
user := &testmodel.PrimaryUint64{}
_, err := s.Insert(user)
assert.NoError(t, err)
assert.Equal(t, uint64(11), user.Id)
Expand All @@ -137,7 +88,7 @@ func TestSaver_Insert(t *testing.T) {
db, mock, _ := sqlmock.New()
mock.ExpectExec("INSERT INTO `sampleNoAutoIncrementKey`").WillReturnResult(sqlmock.NewResult(11, 1))
s := exql.NewSaver(db)
user := &sampleNoAutoIncrementKey{
user := &testmodel.NoAutoIncrementKey{
Id: 1,
}
_, err := s.Insert(user)
Expand Down

0 comments on commit 82d9086

Please sign in to comment.