mirror of https://github.com/VinGarcia/ksql.git
Deprecate Update() in favor of a better fn name: Patch()
parent
1c2421d1de
commit
7a57e38228
1
Makefile
1
Makefile
|
@ -19,6 +19,7 @@ lint: setup
|
|||
@make --no-print-directory -C benchmarks
|
||||
@echo "Golint & Go Vet found no problems on your code!"
|
||||
|
||||
gen: mock
|
||||
mock: setup
|
||||
$(GOBIN)/mockgen -package=exampleservice -source=contracts.go -destination=examples/example_service/mocks.go
|
||||
|
||||
|
|
12
README.md
12
README.md
|
@ -166,11 +166,11 @@ it with as little functions as possible, so don't expect many additions:
|
|||
```go
|
||||
// Provider describes the ksql public behavior
|
||||
//
|
||||
// The Insert, Update, Delete and QueryOne functions return ksql.ErrRecordNotFound
|
||||
// The Insert, Patch, Delete and QueryOne functions return ksql.ErrRecordNotFound
|
||||
// if no record was found or no rows were changed during the operation.
|
||||
type Provider interface {
|
||||
Insert(ctx context.Context, table Table, record interface{}) error
|
||||
Update(ctx context.Context, table Table, record interface{}) error
|
||||
Patch(ctx context.Context, table Table, record interface{}) error
|
||||
Delete(ctx context.Context, table Table, idOrRecord interface{}) error
|
||||
|
||||
Query(ctx context.Context, records interface{}, query string, params ...interface{}) error
|
||||
|
@ -301,12 +301,12 @@ func main() {
|
|||
|
||||
// Updating all fields from Cristina:
|
||||
cris.Name = "Cris"
|
||||
err = db.Update(ctx, UsersTable, cris)
|
||||
err = db.Patch(ctx, UsersTable, cris)
|
||||
|
||||
// Changing the age of Cristina but not touching any other fields:
|
||||
|
||||
// Partial update technique 1:
|
||||
err = db.Update(ctx, UsersTable, struct {
|
||||
err = db.Patch(ctx, UsersTable, struct {
|
||||
ID int `ksql:"id"`
|
||||
Age int `ksql:"age"`
|
||||
}{ID: cris.ID, Age: 28})
|
||||
|
@ -315,7 +315,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Partial update technique 2:
|
||||
err = db.Update(ctx, UsersTable, PartialUpdateUser{
|
||||
err = db.Patch(ctx, UsersTable, PartialUpdateUser{
|
||||
ID: cris.ID,
|
||||
Age: nullable.Int(28),
|
||||
})
|
||||
|
@ -347,7 +347,7 @@ func main() {
|
|||
return err
|
||||
}
|
||||
|
||||
err = db.Update(ctx, UsersTable, PartialUpdateUser{
|
||||
err = db.Patch(ctx, UsersTable, PartialUpdateUser{
|
||||
ID: cris2.ID,
|
||||
Age: nullable.Int(29),
|
||||
})
|
||||
|
|
|
@ -20,9 +20,12 @@ var ErrAbortIteration error = fmt.Errorf("ksql: abort iteration, should only be
|
|||
// if no record was found or no rows were changed during the operation.
|
||||
type Provider interface {
|
||||
Insert(ctx context.Context, table Table, record interface{}) error
|
||||
Update(ctx context.Context, table Table, record interface{}) error
|
||||
Patch(ctx context.Context, table Table, record interface{}) error
|
||||
Delete(ctx context.Context, table Table, idOrRecord interface{}) error
|
||||
|
||||
// Deprecated: use the Patch() method instead.
|
||||
Update(ctx context.Context, table Table, record interface{}) error
|
||||
|
||||
Query(ctx context.Context, records interface{}, query string, params ...interface{}) error
|
||||
QueryOne(ctx context.Context, record interface{}, query string, params ...interface{}) error
|
||||
QueryChunks(ctx context.Context, parser ChunkParser) error
|
||||
|
|
|
@ -111,12 +111,12 @@ func main() {
|
|||
|
||||
// Updating all fields from Cristina:
|
||||
cris.Name = "Cris"
|
||||
err = db.Update(ctx, UsersTable, cris)
|
||||
err = db.Patch(ctx, UsersTable, cris)
|
||||
|
||||
// Changing the age of Cristina but not touching any other fields:
|
||||
|
||||
// Partial update technique 1:
|
||||
err = db.Update(ctx, UsersTable, struct {
|
||||
err = db.Patch(ctx, UsersTable, struct {
|
||||
ID int `ksql:"id"`
|
||||
Age int `ksql:"age"`
|
||||
}{ID: cris.ID, Age: 28})
|
||||
|
@ -125,7 +125,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Partial update technique 2:
|
||||
err = db.Update(ctx, UsersTable, PartialUpdateUser{
|
||||
err = db.Patch(ctx, UsersTable, PartialUpdateUser{
|
||||
ID: cris.ID,
|
||||
Age: nullable.Int(28),
|
||||
})
|
||||
|
@ -157,7 +157,7 @@ func main() {
|
|||
return err
|
||||
}
|
||||
|
||||
err = db.Update(ctx, UsersTable, PartialUpdateUser{
|
||||
err = db.Patch(ctx, UsersTable, PartialUpdateUser{
|
||||
ID: cris2.ID,
|
||||
Age: nullable.Int(29),
|
||||
})
|
||||
|
|
|
@ -68,7 +68,7 @@ func (s Service) UpdateUserScore(ctx context.Context, uID int, scoreChange int)
|
|||
return err
|
||||
}
|
||||
|
||||
return s.db.Update(ctx, UsersTable, &UserEntity{
|
||||
return s.db.Patch(ctx, UsersTable, &UserEntity{
|
||||
ID: uID,
|
||||
Score: nullable.Int(scoreRow.Score + scoreChange),
|
||||
})
|
||||
|
|
|
@ -78,7 +78,7 @@ func TestCreateUser(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUpdateUserScore(t *testing.T) {
|
||||
t.Run("should call ksql.QueryOne() & Update() correctly", func(t *testing.T) {
|
||||
t.Run("should call ksql.QueryOne() & Patch() correctly", func(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
|
@ -102,7 +102,7 @@ func TestUpdateUserScore(t *testing.T) {
|
|||
"score": 42,
|
||||
})
|
||||
}),
|
||||
mockDB.EXPECT().Update(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
mockDB.EXPECT().Patch(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
DoAndReturn(func(ctx context.Context, table ksql.Table, records ...interface{}) error {
|
||||
users = append(users, records...)
|
||||
return nil
|
||||
|
|
|
@ -83,6 +83,20 @@ func (mr *MockProviderMockRecorder) Insert(ctx, table, record interface{}) *gomo
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockProvider)(nil).Insert), ctx, table, record)
|
||||
}
|
||||
|
||||
// Patch mocks base method.
|
||||
func (m *MockProvider) Patch(ctx context.Context, table ksql.Table, record interface{}) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Patch", ctx, table, record)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Patch indicates an expected call of Patch.
|
||||
func (mr *MockProviderMockRecorder) Patch(ctx, table, record interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Patch", reflect.TypeOf((*MockProvider)(nil).Patch), ctx, table, record)
|
||||
}
|
||||
|
||||
// Query mocks base method.
|
||||
func (m *MockProvider) Query(ctx context.Context, records interface{}, query string, params ...interface{}) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
14
ksql.go
14
ksql.go
|
@ -626,10 +626,24 @@ func normalizeIDsAsMap(idNames []string, idOrMap interface{}) (idMap map[string]
|
|||
// Update updates the given instances on the database by id.
|
||||
//
|
||||
// Partial updates are supported, i.e. it will ignore nil pointer attributes
|
||||
//
|
||||
// Deprecated: Use the Patch method instead
|
||||
func (c DB) Update(
|
||||
ctx context.Context,
|
||||
table Table,
|
||||
record interface{},
|
||||
) error {
|
||||
return c.Patch(ctx, table, record)
|
||||
}
|
||||
|
||||
// Patch applies a partial update (explained below) to the given instance on the database by id.
|
||||
//
|
||||
// Partial updates will ignore any nil pointer attributes from the struct, updating only
|
||||
// the non nil pointers and non pointer attributes.
|
||||
func (c DB) Patch(
|
||||
ctx context.Context,
|
||||
table Table,
|
||||
record interface{},
|
||||
) error {
|
||||
v := reflect.ValueOf(record)
|
||||
t := v.Type()
|
||||
|
|
36
mocks.go
36
mocks.go
|
@ -50,9 +50,11 @@ var _ Provider = Mock{}
|
|||
//
|
||||
type Mock struct {
|
||||
InsertFn func(ctx context.Context, table Table, record interface{}) error
|
||||
UpdateFn func(ctx context.Context, table Table, record interface{}) error
|
||||
PatchFn func(ctx context.Context, table Table, record interface{}) error
|
||||
DeleteFn func(ctx context.Context, table Table, idOrRecord interface{}) error
|
||||
|
||||
UpdateFn func(ctx context.Context, table Table, record interface{}) error
|
||||
|
||||
QueryFn func(ctx context.Context, records interface{}, query string, params ...interface{}) error
|
||||
QueryOneFn func(ctx context.Context, record interface{}, query string, params ...interface{}) error
|
||||
QueryChunksFn func(ctx context.Context, parser ChunkParser) error
|
||||
|
@ -91,13 +93,17 @@ func (m Mock) SetFallbackDatabase(db Provider) Mock {
|
|||
if m.InsertFn == nil {
|
||||
m.InsertFn = db.Insert
|
||||
}
|
||||
if m.UpdateFn == nil {
|
||||
m.UpdateFn = db.Update
|
||||
if m.PatchFn == nil {
|
||||
m.PatchFn = db.Patch
|
||||
}
|
||||
if m.DeleteFn == nil {
|
||||
m.DeleteFn = db.Delete
|
||||
}
|
||||
|
||||
if m.UpdateFn == nil {
|
||||
m.UpdateFn = db.Update
|
||||
}
|
||||
|
||||
if m.QueryFn == nil {
|
||||
m.QueryFn = db.Query
|
||||
}
|
||||
|
@ -128,14 +134,14 @@ func (m Mock) Insert(ctx context.Context, table Table, record interface{}) error
|
|||
return m.InsertFn(ctx, table, record)
|
||||
}
|
||||
|
||||
// Update mocks the behavior of the Update method.
|
||||
// If UpdateFn is set it will just call it returning the same return values.
|
||||
// If UpdateFn is unset it will panic with an appropriate error message.
|
||||
func (m Mock) Update(ctx context.Context, table Table, record interface{}) error {
|
||||
if m.UpdateFn == nil {
|
||||
panic(fmt.Errorf("ksql.Mock.Update(ctx, %v, %v) called but the ksql.Mock.UpdateFn() is not set", table, record))
|
||||
// Patch mocks the behavior of the Patch method.
|
||||
// If PatchFn is set it will just call it returning the same return values.
|
||||
// If PatchFn is unset it will panic with an appropriate error message.
|
||||
func (m Mock) Patch(ctx context.Context, table Table, record interface{}) error {
|
||||
if m.PatchFn == nil {
|
||||
panic(fmt.Errorf("ksql.Mock.Patch(ctx, %v, %v) called but the ksql.Mock.PatchFn() is not set", table, record))
|
||||
}
|
||||
return m.UpdateFn(ctx, table, record)
|
||||
return m.PatchFn(ctx, table, record)
|
||||
}
|
||||
|
||||
// Delete mocks the behavior of the Delete method.
|
||||
|
@ -148,6 +154,16 @@ func (m Mock) Delete(ctx context.Context, table Table, idOrRecord interface{}) e
|
|||
return m.DeleteFn(ctx, table, idOrRecord)
|
||||
}
|
||||
|
||||
// Update mocks the behavior of the Update method.
|
||||
// If UpdateFn is set it will just call it returning the same return values.
|
||||
// If UpdateFn is unset it will panic with an appropriate error message.
|
||||
func (m Mock) Update(ctx context.Context, table Table, record interface{}) error {
|
||||
if m.UpdateFn == nil {
|
||||
panic(fmt.Errorf("ksql.Mock.Update(ctx, %v, %v) called but the ksql.Mock.UpdateFn() is not set", table, record))
|
||||
}
|
||||
return m.UpdateFn(ctx, table, record)
|
||||
}
|
||||
|
||||
// Query mocks the behavior of the Query method.
|
||||
// If QueryFn is set it will just call it returning the same return values.
|
||||
// If QueryFn is unset it will panic with an appropriate error message.
|
||||
|
|
|
@ -34,6 +34,22 @@ func TestMock(t *testing.T) {
|
|||
tt.AssertErrContains(t, err, "ksql.Mock.Insert(", "ksql.Mock.InsertFn", "not set")
|
||||
})
|
||||
|
||||
t.Run("Patch should panic", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
mock := ksql.Mock{}
|
||||
panicPayload := tt.PanicHandler(func() {
|
||||
mock.Patch(ctx, UsersTable, &User{
|
||||
ID: 4242,
|
||||
Name: "fake-name",
|
||||
Age: 42,
|
||||
})
|
||||
})
|
||||
|
||||
err, ok := panicPayload.(error)
|
||||
tt.AssertEqual(t, ok, true)
|
||||
tt.AssertErrContains(t, err, "ksql.Mock.Patch(", "ksql.Mock.PatchFn", "not set")
|
||||
})
|
||||
|
||||
t.Run("Update should panic", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
mock := ksql.Mock{}
|
||||
|
@ -174,6 +190,37 @@ func TestMock(t *testing.T) {
|
|||
})
|
||||
})
|
||||
|
||||
t.Run("Patch", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
var capturedArgs struct {
|
||||
ctx context.Context
|
||||
table ksql.Table
|
||||
record interface{}
|
||||
}
|
||||
mock := ksql.Mock{
|
||||
PatchFn: func(ctx context.Context, table ksql.Table, record interface{}) error {
|
||||
capturedArgs.ctx = ctx
|
||||
capturedArgs.table = table
|
||||
capturedArgs.record = record
|
||||
return fmt.Errorf("fake-error")
|
||||
},
|
||||
}
|
||||
err := mock.Patch(ctx, UsersTable, &User{
|
||||
ID: 4242,
|
||||
Name: "fake-name",
|
||||
Age: 42,
|
||||
})
|
||||
|
||||
tt.AssertErrContains(t, err, "fake-error")
|
||||
tt.AssertEqual(t, capturedArgs.ctx, ctx)
|
||||
tt.AssertEqual(t, capturedArgs.table, UsersTable)
|
||||
tt.AssertEqual(t, capturedArgs.record, &User{
|
||||
ID: 4242,
|
||||
Name: "fake-name",
|
||||
Age: 42,
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Update", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
var capturedArgs struct {
|
||||
|
|
Loading…
Reference in New Issue