diff --git a/go.sum b/go.sum index 985f0b4..d4582ff 100644 --- a/go.sum +++ b/go.sum @@ -2,18 +2,24 @@ github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBK github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/ditointernet/go-assert v0.0.0-20200120164340-9e13125a7018 h1:QsFkVafcKOaZoAB4WcyUHdkPbwh+VYwZgYJb/rU6EIM= github.com/ditointernet/go-assert v0.0.0-20200120164340-9e13125a7018/go.mod h1:5C3SWkut69TSdkerzRDxXMRM5x73PGWNcRLe/xKjXhs= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= 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.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= @@ -24,6 +30,7 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -31,5 +38,6 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/kiss_orm.go b/kiss_orm.go index 61ea0d8..0aef518 100644 --- a/kiss_orm.go +++ b/kiss_orm.go @@ -2,6 +2,7 @@ package kissorm import ( "context" + "database/sql" "fmt" "reflect" @@ -15,9 +16,14 @@ type ORMProvider interface { Insert(ctx context.Context, items ...interface{}) error Delete(ctx context.Context, ids ...interface{}) error Update(ctx context.Context, intems ...interface{}) error + Query(ctx context.Context, query string, params ...interface{}) (Iterator, error) + QueryNext(ctx context.Context, rawIt Iterator, item interface{}) (done bool, err error) } -type Iterator interface{} +// Iterator ... +type Iterator interface { + Close() error +} // Client ... type Client struct { @@ -61,7 +67,10 @@ func (c Client) Find( params ...interface{}, ) error { it := c.db.Raw(query, params...) - it.Scan(item) + if it.Error != nil { + return it.Error + } + it = it.Scan(item) return it.Error } @@ -73,7 +82,11 @@ func (c Client) Query( params ...interface{}, ) (Iterator, error) { it := c.db.Raw(query, params...) - return it, it.Error + if it.Error != nil { + return nil, it.Error + } + + return it.Rows() } // QueryNext parses the next row of a query @@ -83,13 +96,18 @@ func (c Client) QueryNext( ctx context.Context, rawIt Iterator, item interface{}, -) error { - it, ok := rawIt.(*gorm.DB) +) (done bool, err error) { + rows, ok := rawIt.(*sql.Rows) if !ok { - return fmt.Errorf("invalid iterator received on QueryNext()") + return false, fmt.Errorf("invalid iterator received on QueryNext()") } - it.Scan(item) - return it.Error + + if !rows.Next() { + rows.Close() + return true, rows.Err() + } + + return false, c.db.ScanRows(rows, item) } // GetByID recovers a single entity from the database by the ID field. @@ -99,7 +117,10 @@ func (c Client) GetByID( id interface{}, ) error { it := c.db.Raw(fmt.Sprintf("select * from %s where id = ?", c.tableName), id) - it.Scan(item) + if it.Error != nil { + return it.Error + } + it = it.Scan(item) return it.Error } diff --git a/kiss_orm_test.go b/kiss_orm_test.go index a895fcf..a75b60c 100644 --- a/kiss_orm_test.go +++ b/kiss_orm_test.go @@ -33,7 +33,7 @@ func TestFind(t *testing.T) { } u := User{} err := c.Find(ctx, &u, `SELECT * FROM users WHERE id=1;`) - assert.Equal(t, err, nil) + assert.NotEqual(t, nil, err) assert.Equal(t, User{}, u) }) @@ -76,7 +76,7 @@ func TestGetByID(t *testing.T) { } u := User{} err := c.GetByID(ctx, &u, 999) - assert.Equal(t, err, nil) + assert.NotEqual(t, nil, err) assert.Equal(t, User{}, u) }) @@ -319,6 +319,102 @@ func TestStructToMap(t *testing.T) { }) } +func TestQuery(t *testing.T) { + t.Run("should execute query one correctly", func(t *testing.T) { + err := createTable() + if err != nil { + t.Fatal("could not create test table!") + } + + db := connectDB(t) + defer db.Close() + + ctx := context.Background() + c := Client{ + db: db, + tableName: "users", + } + + _ = c.Insert(ctx, &User{Name: "User1"}) + + it, err := c.Query(ctx, `select * from users where name = ?;`, "User1") + assert.Equal(t, nil, err) + + u := User{} + _, err = c.QueryNext(ctx, it, &u) + it.Close() + + assert.Equal(t, nil, err) + assert.NotEqual(t, 0, u.ID) + assert.Equal(t, "User1", u.Name) + }) + + t.Run("should execute query many correctly", func(t *testing.T) { + err := createTable() + if err != nil { + t.Fatal("could not create test table!") + } + + db := connectDB(t) + defer db.Close() + + ctx := context.Background() + c := Client{ + db: db, + tableName: "users", + } + + _ = c.Insert(ctx, &User{Name: "User1"}) + _ = c.Insert(ctx, &User{Name: "User2"}) + _ = c.Insert(ctx, &User{Name: "User3"}) + + it, err := c.Query(ctx, `select * from users where name in (?,?);`, "User1", "User3") + assert.Equal(t, nil, err) + + // var results []User + u := User{} + u2 := User{} + u3 := User{} + done, err := c.QueryNext(ctx, it, &u) + assert.Equal(t, false, done) + assert.Equal(t, nil, err) + + done, err = c.QueryNext(ctx, it, &u2) + assert.Equal(t, false, done) + assert.Equal(t, nil, err) + + done, err = c.QueryNext(ctx, it, &u3) + assert.Equal(t, true, done) + assert.Equal(t, nil, err) + + assert.NotEqual(t, 0, u.ID) + assert.Equal(t, "User1", u.Name) + assert.NotEqual(t, 0, u2.ID) + assert.Equal(t, "User3", u2.Name) + }) + + t.Run("should return error for an invalid iterator", func(t *testing.T) { + err := createTable() + if err != nil { + t.Fatal("could not create test table!") + } + + db := connectDB(t) + defer db.Close() + + ctx := context.Background() + c := Client{ + db: db, + tableName: "users", + } + + u := User{} + _, err = c.QueryNext(ctx, Iterator(nil), &u) + + assert.NotEqual(t, nil, err) + }) +} + func createTable() error { db, err := gorm.Open("sqlite3", "/tmp/test.db") if err != nil {