Skip to content

Commit cb8acd2

Browse files
authored
Optimistic DB Insert and Update (go-rel#33)
* wip changing changes signature * wip: implement apply on basic modifier * wip: implementation on map, now panics instead of returning errors * removed error return from apply changes * fix test * removed StaleIDs * removed AssocChanges * refactored changes as modification * apply structset if it's to another struct * optimistic inserts * fix test * renamed ChangeFragment to SetFragment * optimistic update * apply has many for map * simplify InsertAll api * wip optimistic have save many * optimistic save has many * fix structset * try fix timezone * fix ordering when id increment is negative * simplify modifcation struct * adjust adapter * sanity test * fix tests * try reuse repository logic * fix postgres adapter * use timestamptz * fix time location issue * try * upgrade * fix timezone * more fix * removed todo, current insert api doesn't allow that op * use affected rows to determine update and delete error * renamed NoResultError to NotFoundError to fits better in the context of update and delete * hack coverage * fix * improve coverage * improve coverage * add reload modifier * refactor applyAssoc * refactor duplicate assertion * more test * reuse ChangeIncOp for decrement * refactor SetValue * refactor applyValue
1 parent fe0440f commit cb8acd2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2135
-1830
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ env:
22
global:
33
- CC_TEST_REPORTER_ID=045e6c8f64f873901bacc868224b418d9fc72dd73c40feb1af50faf3e96de15d
44
- MYSQL_DATABASE=root@(127.0.0.1:3306)/rel_test
5-
- POSTGRESQL_DATABASE=postgres://postgres@localhost/rel_test?sslmode=disable
5+
- POSTGRESQL_DATABASE=postgres://postgres@localhost/rel_test
66

77
language: go
88
go:

Gopkg.lock

+41-17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

adapter.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ package rel
44
type Adapter interface {
55
Aggregate(query Query, mode string, field string, loggers ...Logger) (int, error)
66
Query(query Query, loggers ...Logger) (Cursor, error)
7-
Insert(query Query, changes Changes, loggers ...Logger) (interface{}, error)
8-
InsertAll(query Query, fields []string, changes []Changes, loggers ...Logger) ([]interface{}, error)
9-
Update(query Query, changes Changes, loggers ...Logger) error
10-
Delete(query Query, loggers ...Logger) error
7+
Insert(query Query, modifies map[string]Modify, loggers ...Logger) (interface{}, error)
8+
InsertAll(query Query, fields []string, bulkModifies []map[string]Modify, loggers ...Logger) ([]interface{}, error)
9+
Update(query Query, modifies map[string]Modify, loggers ...Logger) (int, error)
10+
Delete(query Query, loggers ...Logger) (int, error)
1111

1212
Begin() (Adapter, error)
1313
Commit() error

adapter/mysql/mysql_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func init() {
2525
_, _, err = adapter.Exec(`CREATE TABLE users (
2626
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
2727
name VARCHAR(30) NOT NULL DEFAULT '',
28-
gender VARCHAR(10) NOT NULL DEFAULT 'male',
28+
gender VARCHAR(10) NOT NULL DEFAULT '',
2929
age INT NOT NULL DEFAULT 0,
3030
note varchar(50),
3131
created_at DATETIME,
@@ -124,12 +124,12 @@ func TestAdapter_specs(t *testing.T) {
124124
// defer adapter.Close()
125125

126126
// fields := []string{"notexist"}
127-
// allchanges := []map[string]interface{}{
127+
// modifications := []map[string]interface{}{
128128
// {"notexist": "12"},
129129
// {"notexist": "13"},
130130
// }
131131

132-
// _, err = adapter.InsertAll(rel.Repo{}.From("users"), fields, allchanges)
132+
// _, err = adapter.InsertAll(rel.Repo{}.From("users"), fields, modifications)
133133

134134
// assert.NotNil(t, err)
135135
// }

adapter/postgres/postgres.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ func Open(dsn string) (*Adapter, error) {
4848
}
4949

5050
// Insert inserts a record to database and returns its id.
51-
func (adapter *Adapter) Insert(query rel.Query, changes rel.Changes, loggers ...rel.Logger) (interface{}, error) {
51+
func (adapter *Adapter) Insert(query rel.Query, modifies map[string]rel.Modify, loggers ...rel.Logger) (interface{}, error) {
5252
var (
5353
id int64
54-
statement, args = sql.NewBuilder(adapter.Config).Returning("id").Insert(query.Table, changes)
54+
statement, args = sql.NewBuilder(adapter.Config).Returning("id").Insert(query.Table, modifies)
5555
rows, err = adapter.query(statement, args, loggers)
5656
)
5757

@@ -64,10 +64,10 @@ func (adapter *Adapter) Insert(query rel.Query, changes rel.Changes, loggers ...
6464
}
6565

6666
// InsertAll inserts multiple records to database and returns its ids.
67-
func (adapter *Adapter) InsertAll(query rel.Query, fields []string, allchanges []rel.Changes, loggers ...rel.Logger) ([]interface{}, error) {
67+
func (adapter *Adapter) InsertAll(query rel.Query, fields []string, bulkModifies []map[string]rel.Modify, loggers ...rel.Logger) ([]interface{}, error) {
6868
var (
6969
ids []interface{}
70-
statement, args = sql.NewBuilder(adapter.Config).Returning("id").InsertAll(query.Table, fields, allchanges)
70+
statement, args = sql.NewBuilder(adapter.Config).Returning("id").InsertAll(query.Table, fields, bulkModifies)
7171
rows, err = adapter.query(statement, args, loggers)
7272
)
7373

adapter/postgres/postgres_test.go

+14-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package postgres
33
import (
44
"os"
55
"testing"
6+
"time"
67

78
"github.com/Fs02/go-paranoid"
89
"github.com/Fs02/rel"
@@ -27,11 +28,11 @@ func init() {
2728
id SERIAL NOT NULL PRIMARY KEY,
2829
slug VARCHAR(30) DEFAULT NULL,
2930
name VARCHAR(30) NOT NULL DEFAULT '',
30-
gender VARCHAR(10) NOT NULL DEFAULT 'male',
31+
gender VARCHAR(10) NOT NULL DEFAULT '',
3132
age INT NOT NULL DEFAULT 0,
3233
note varchar(50),
33-
created_at TIMESTAMP,
34-
updated_at TIMESTAMP,
34+
created_at TIMESTAMPTZ,
35+
updated_at TIMESTAMPTZ,
3536
UNIQUE(slug)
3637
);`, nil)
3738
paranoid.Panic(err, "failed creating users table")
@@ -40,8 +41,8 @@ func init() {
4041
id SERIAL NOT NULL PRIMARY KEY,
4142
user_id INTEGER REFERENCES users(id),
4243
name VARCHAR(60) NOT NULL DEFAULT '',
43-
created_at TIMESTAMP,
44-
updated_at TIMESTAMP
44+
created_at TIMESTAMPTZ,
45+
updated_at TIMESTAMPTZ
4546
);`, nil)
4647
paranoid.Panic(err, "failed creating addresses table")
4748

@@ -52,14 +53,18 @@ func init() {
5253
score INTEGER DEFAULT 0 CHECK (score>=0 AND score<=100)
5354
);`, nil)
5455
paranoid.Panic(err, "failed creating extras table")
56+
57+
// hack to make sure location it has the same location object as returned by pq driver.
58+
time.Local, err = time.LoadLocation("Asia/Jakarta")
59+
paranoid.Panic(err, "failed loading time location")
5560
}
5661

5762
func dsn() string {
5863
if os.Getenv("POSTGRESQL_DATABASE") != "" {
59-
return os.Getenv("POSTGRESQL_DATABASE")
64+
return os.Getenv("POSTGRESQL_DATABASE") + "?sslmode=disable&timezone=Asia/Jakarta"
6065
}
6166

62-
return "postgres://rel@localhost:9920/rel_test?sslmode=disable"
67+
return "postgres://rel@localhost:9920/rel_test?sslmode=disable&timezone=Asia/Jakarta"
6368
}
6469

6570
func TestAdapter_specs(t *testing.T) {
@@ -127,12 +132,12 @@ func TestAdapter_specs(t *testing.T) {
127132
// defer adapter.Close()
128133

129134
// fields := []string{"notexist"}
130-
// allchanges := []map[string]interface{}{
135+
// modifications := []map[string]interface{}{
131136
// {"notexist": "12"},
132137
// {"notexist": "13"},
133138
// }
134139

135-
// _, err = adapter.InsertAll(rel.Repo{}.From("users"), fields, allchanges)
140+
// _, err = adapter.InsertAll(rel.Repo{}.From("users"), fields, modifications)
136141

137142
// assert.NotNil(t, err)
138143
// }

adapter/specs/aggregate.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ func Aggregate(t *testing.T, repo rel.Repository) {
4848
}
4949

5050
for _, query := range tests {
51-
statement, _ := builder.Find(query.Select("count(id) AS count"))
52-
53-
t.Run("Aggregate|"+statement, func(t *testing.T) {
51+
t.Run("Aggregate", func(t *testing.T) {
5452
count, err := repo.Aggregate(query, "count", "id")
5553
assert.Nil(t, err)
5654
assert.True(t, count >= 0)

adapter/specs/delete.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func Delete(t *testing.T, repo rel.Repository) {
1818
assert.NotEqual(t, 0, user.ID)
1919

2020
assert.Nil(t, repo.Delete(&user))
21-
assert.Equal(t, rel.NoResultError{}, repo.Find(&user, where.Eq("id", user.ID)))
21+
assert.Equal(t, rel.NotFoundError{}, repo.Find(&user, where.Eq("id", user.ID)))
2222
}
2323

2424
// DeleteAll tests delete specifications.
@@ -43,8 +43,7 @@ func DeleteAll(t *testing.T, repo rel.Repository) {
4343
}
4444

4545
for _, query := range tests {
46-
statement, _ := builder.Delete(query.Table, query.WhereQuery)
47-
t.Run("Delete|"+statement, func(t *testing.T) {
46+
t.Run("Delete", func(t *testing.T) {
4847
var result []User
4948
assert.Nil(t, repo.FindAll(&result, query))
5049
assert.NotEqual(t, 0, len(result))

adapter/specs/insert.go

+46-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package specs
22

33
import (
4-
"reflect"
54
"testing"
65

76
"github.com/Fs02/rel"
@@ -157,17 +156,26 @@ func Inserts(t *testing.T, repo rel.Repository) {
157156
}
158157

159158
for _, record := range tests {
160-
var (
161-
changes = rel.BuildChanges(rel.NewStructset(record, false))
162-
statement, _ = builder.Insert("collection", changes)
163-
)
164-
165-
t.Run("Insert|"+statement, func(t *testing.T) {
159+
t.Run("Insert", func(t *testing.T) {
166160
assert.Nil(t, repo.Insert(record))
161+
assertRecord(t, repo, record)
167162
})
168163
}
169164
}
170165

166+
func assertRecord(t *testing.T, repo rel.Repository, record interface{}) {
167+
switch v := record.(type) {
168+
case *User:
169+
var found User
170+
repo.MustFind(&found, where.Eq("id", v.ID))
171+
assert.Equal(t, found, *v)
172+
case *Address:
173+
var found Address
174+
repo.MustFind(&found, where.Eq("id", v.ID))
175+
assert.Equal(t, found, *v)
176+
}
177+
}
178+
171179
// InsertAll tests insert multiple specifications.
172180
func InsertAll(t *testing.T, repo rel.Repository) {
173181
var (
@@ -178,26 +186,48 @@ func InsertAll(t *testing.T, repo rel.Repository) {
178186
repo.MustInsert(&user)
179187

180188
tests := []interface{}{
181-
// &[]User{{}},
189+
&[]User{{}},
182190
&[]User{{Name: "insert", Age: 100}},
183191
&[]User{{Name: "insert", Age: 100, Note: &note}},
184192
&[]User{{Note: &note}},
185-
// &[]Address{{}},
193+
&[]User{{Name: "insert", Age: 100}, {Name: "insert too"}},
194+
&[]Address{{}},
186195
&[]Address{{Name: "work"}},
187196
&[]Address{{UserID: &user.ID}},
188197
&[]Address{{Name: "work", UserID: &user.ID}},
198+
&[]Address{{Name: "work"}, {Name: "home"}},
189199
}
190200

191201
for _, record := range tests {
192-
// var (
193-
// changes = rel.BuildChanges(rel.Struct(record))
194-
// statement, _ = builder.Insert("collection", changes)
195-
// )
196-
197202
t.Run("InsertAll", func(t *testing.T) {
198-
// multiple insert
199203
assert.Nil(t, repo.InsertAll(record))
200-
assert.Equal(t, 1, reflect.ValueOf(record).Elem().Len())
204+
205+
switch v := record.(type) {
206+
case *[]User:
207+
var (
208+
found []User
209+
ids = make([]int, len(*v))
210+
)
211+
212+
for i := range *v {
213+
ids[i] = int((*v)[i].ID)
214+
}
215+
216+
repo.MustFindAll(&found, where.InInt("id", ids))
217+
assert.Equal(t, found, *v)
218+
case *[]Address:
219+
var (
220+
found []Address
221+
ids = make([]int, len(*v))
222+
)
223+
224+
for i := range *v {
225+
ids[i] = int((*v)[i].ID)
226+
}
227+
228+
repo.MustFindAll(&found, where.InInt("id", ids))
229+
assert.Equal(t, found, *v)
230+
}
201231
})
202232
}
203233
}

0 commit comments

Comments
 (0)