Skip to content

Commit deacccd

Browse files
committed
Merge with v3
2 parents a38072c + df86292 commit deacccd

28 files changed

+1756
-14
lines changed

.travis.yml

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
sudo: required
2-
dist: precise
32

43
notifications:
54
email: false
@@ -9,9 +8,10 @@ language: go
98
go:
109
- "1.7"
1110
- "1.8"
12-
# - "tip"
11+
# - "tip"
1312

1413
services:
14+
- docker
1515
- mongodb
1616
- mysql
1717
- postgresql
@@ -22,9 +22,15 @@ addons:
2222
sources:
2323
- mongodb-3.0-precise
2424
packages:
25+
- freetds-bin
2526
- mongodb-org-server
2627
- mongodb-org-shell
2728

29+
before_install:
30+
- docker pull microsoft/mssql-server-linux:ctp1-4
31+
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=my$Password' --name mssql -p 1433:1433 -d microsoft/mssql-server-linux:ctp1-4
32+
- docker ps -a
33+
2834
env:
2935
global:
3036
- MAKEFLAGS="-j4"

Makefile

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
SHELL := /bin/bash
22

3+
WAPPER ?= all
34
DB_HOST ?= 127.0.0.1
45

56
export DB_HOST
7+
export WRAPPER
68

79
benchmark-lib:
810
go test -v -benchtime=500ms -bench=. ./lib/...
@@ -20,12 +22,13 @@ test-internal:
2022

2123
test-libs: test-lib test-internal
2224

23-
test-adapters: test-adapter-postgresql test-adapter-mysql test-adapter-sqlite test-adapter-ql test-adapter-mongo
25+
test-adapters: test-adapter-postgresql test-adapter-mysql test-adapter-sqlite test-adapter-mssql test-adapter-ql test-adapter-mongo
2426

2527
reset-db:
2628
$(MAKE) -C postgresql reset-db && \
2729
$(MAKE) -C mysql reset-db && \
2830
$(MAKE) -C sqlite reset-db && \
31+
$(MAKE) -C mssql reset-db && \
2932
$(MAKE) -C ql reset-db && \
3033
$(MAKE) -C mongo reset-db
3134

README.md

+13-5
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ Go that provides a common interface to work with different data sources such as
1414
go get upper.io/db.v3
1515
```
1616

17-
## User documentation
17+
## The tour
1818

19-
This is the source code repository, check out our [release
20-
notes](https://github.com/upper/db/releases/tag/v3.0.0) and see examples and
21-
documentation at [upper.io/db.v3][1].
19+
![screen shot 2017-05-01 at 19 23 22](https://cloud.githubusercontent.com/assets/385670/25599675/b6fe9fea-2ea3-11e7-9f76-002931dfbbc1.png)
2220

23-
## Demo
21+
Take the [tour](https://tour.upper.io) to see real live examples in your
22+
browser.
23+
24+
## Live demos
2425

2526
You can run the following example on our [playground](https://demo.upper.io):
2627

@@ -87,6 +88,13 @@ go run _examples/booktown-books/main.go
8788
2016/08/10 08:42:48 "Practical PostgreSQL" (ID: 41472)
8889
```
8990

91+
## Documentation for users
92+
93+
This is the source code repository, check out our [release
94+
notes](https://github.com/upper/db/releases/tag/v3.0.0) and see examples and
95+
documentation at [upper.io/db.v3][1].
96+
97+
9098
## Changelog
9199

92100
See [CHANGELOG.md](https://github.com/upper/db/blob/master/CHANGELOG.md).

db_test.go

+72-3
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,20 @@ import (
3535
"gopkg.in/mgo.v2/bson"
3636
"upper.io/db.v3"
3737
"upper.io/db.v3/mongo"
38+
"upper.io/db.v3/mssql"
3839
"upper.io/db.v3/mysql"
3940
"upper.io/db.v3/postgresql"
4041
"upper.io/db.v3/ql"
4142
"upper.io/db.v3/sqlite"
4243
)
4344

4445
var wrappers = []string{
45-
sqlite.Adapter,
46+
mongo.Adapter,
47+
mssql.Adapter,
4648
mysql.Adapter,
4749
postgresql.Adapter,
48-
mongo.Adapter,
4950
ql.Adapter,
51+
sqlite.Adapter,
5052
}
5153

5254
const (
@@ -103,6 +105,12 @@ func init() {
103105
"timezone": "UTC",
104106
},
105107
},
108+
`mssql`: &mssql.ConnectionURL{
109+
Database: `upperio_tests`,
110+
Host: host,
111+
User: `upperio_tests`,
112+
Password: `upperio_Secre3t`,
113+
},
106114
`ql`: &ql.ConnectionURL{
107115
Database: `ql-test.db`,
108116
},
@@ -252,6 +260,65 @@ var setupFn = map[string]func(driver interface{}) error{
252260
}
253261
return fmt.Errorf("Expecting *sql.DB got %T (%#v).", driver, driver)
254262
},
263+
`mssql`: func(driver interface{}) error {
264+
if sqld, ok := driver.(*sql.DB); ok {
265+
var err error
266+
267+
_, err = sqld.Exec(`DROP TABLE IF EXISTS [birthdays]`)
268+
if err != nil {
269+
return err
270+
}
271+
_, err = sqld.Exec(`CREATE TABLE [birthdays] (
272+
id BIGINT PRIMARY KEY NOT NULL IDENTITY(1,1),
273+
name NVARCHAR(50),
274+
born DATETIME,
275+
born_ut BIGINT
276+
)`)
277+
if err != nil {
278+
return err
279+
}
280+
281+
_, err = sqld.Exec(`DROP TABLE IF EXISTS [fibonacci]`)
282+
if err != nil {
283+
return err
284+
}
285+
_, err = sqld.Exec(`CREATE TABLE [fibonacci] (
286+
id BIGINT PRIMARY KEY NOT NULL IDENTITY(1,1),
287+
input BIGINT NOT NULL,
288+
output BIGINT NOT NULL
289+
)`)
290+
if err != nil {
291+
return err
292+
}
293+
294+
_, err = sqld.Exec(`DROP TABLE IF EXISTS [is_even]`)
295+
if err != nil {
296+
return err
297+
}
298+
_, err = sqld.Exec(`CREATE TABLE [is_even] (
299+
input BIGINT NOT NULL,
300+
is_even TINYINT
301+
)`)
302+
if err != nil {
303+
return err
304+
}
305+
306+
_, err = sqld.Exec(`DROP TABLE IF EXISTS [CaSe_TesT]`)
307+
if err != nil {
308+
return err
309+
}
310+
_, err = sqld.Exec(`CREATE TABLE [CaSe_TesT] (
311+
id BIGINT PRIMARY KEY NOT NULL IDENTITY(1,1),
312+
case_test NVARCHAR(60)
313+
)`)
314+
if err != nil {
315+
return err
316+
}
317+
318+
return nil
319+
}
320+
return fmt.Errorf("Expecting *sql.DB got %T (%#v).", driver, driver)
321+
},
255322
`sqlite`: func(driver interface{}) error {
256323
if sqld, ok := driver.(*sql.DB); ok {
257324
var err error
@@ -635,7 +702,7 @@ func TestSimpleCRUD(t *testing.T) {
635702
}
636703

637704
if reflect.DeepEqual(testItem, controlItem) == false {
638-
t.Fatalf("Struct is different with wrapper %s.", wrapper)
705+
t.Fatalf("Struct is different with wrapper %s, got: %#v, expecting: %#v.", wrapper, testItem, controlItem)
639706
}
640707

641708
err = res.Delete()
@@ -716,6 +783,8 @@ func TestFibonacci(t *testing.T) {
716783
res = res.OrderBy(db.Raw(`RANDOM()`))
717784
case `mysql`:
718785
res = res.OrderBy(db.Raw(`RAND()`))
786+
case `sqlserver`:
787+
res = res.OrderBy(db.Raw(`NEWID()`))
719788
}
720789

721790
total, err = res.Count()

internal/sqladapter/database.go

+29
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,35 @@ func (d *database) Collection(name string) db.Collection {
355355
return col
356356
}
357357

358+
// StatementPrepare creates a prepared statement.
359+
func (d *database) StatementPrepare(ctx context.Context, stmt *exql.Statement) (sqlStmt *sql.Stmt, err error) {
360+
var query string
361+
362+
if d.Settings.LoggingEnabled() {
363+
defer func(start time.Time) {
364+
d.Logger().Log(&db.QueryStatus{
365+
TxID: d.txID,
366+
SessID: d.sessID,
367+
Query: query,
368+
Err: err,
369+
Start: start,
370+
End: time.Now(),
371+
})
372+
}(time.Now())
373+
}
374+
375+
tx := d.Transaction()
376+
377+
query, _ = d.compileStatement(stmt, nil)
378+
if tx != nil {
379+
sqlStmt, err = compat.PrepareContext(tx.(*baseTx), ctx, query)
380+
return
381+
}
382+
383+
sqlStmt, err = compat.PrepareContext(d.sess, ctx, query)
384+
return
385+
}
386+
358387
// StatementExec compiles and executes a statement that does not return any
359388
// rows.
360389
func (d *database) StatementExec(ctx context.Context, stmt *exql.Statement, args ...interface{}) (res sql.Result, err error) {

internal/sqladapter/exql/column.go

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ func (c *Column) Compile(layout *Template) (compiled string, err error) {
5151

5252
for i := range nameChunks {
5353
nameChunks[i] = trimString(nameChunks[i])
54+
if nameChunks[i] == "*" {
55+
continue
56+
}
5457
nameChunks[i] = mustParse(layout.IdentifierQuote, Raw{Value: nameChunks[i]})
5558
}
5659

internal/sqladapter/exql/statement_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,28 @@ func TestSelectStarFromMany(t *testing.T) {
212212
}
213213
}
214214

215+
func TestSelectTableStarFromMany(t *testing.T) {
216+
var s, e string
217+
var stmt Statement
218+
219+
stmt = Statement{
220+
Type: Select,
221+
Columns: JoinColumns(
222+
&Column{Name: "foo.name"},
223+
&Column{Name: "BAR.*"},
224+
&Column{Name: "baz.last_name"},
225+
),
226+
Table: TableWithName("first.table AS foo, second.table as BAR, third.table aS baz"),
227+
}
228+
229+
s = mustTrim(stmt.Compile(defaultTemplate))
230+
e = `SELECT "foo"."name", "BAR".*, "baz"."last_name" FROM "first"."table" AS "foo", "second"."table" AS "BAR", "third"."table" AS "baz"`
231+
232+
if s != e {
233+
t.Fatalf("Got: %s, Expecting: %s", s, e)
234+
}
235+
}
236+
215237
func TestSelectArtistNameFrom(t *testing.T) {
216238
var s, e string
217239
var stmt Statement

internal/sqladapter/result.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,7 @@ func (r *Result) buildCount() (sqlbuilder.Selector, error) {
348348

349349
sel := r.SQLBuilder().Select(db.Raw("count(1) AS _t")).
350350
From(res.table).
351-
GroupBy(res.groupBy...).
352-
Limit(1)
351+
GroupBy(res.groupBy...)
353352

354353
for i := range res.conds {
355354
sel = sel.And(filter(res.conds[i])...)

internal/sqladapter/testing/adapter.go.tpl

+3-1
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,6 @@ func TestTransactionsAndRollback(t *testing.T) {
10951095
err = artist.Truncate()
10961096
assert.NoError(t, err)
10971097
1098-
// Simple transaction
10991098
_, err = artist.Insert(artistType{1, "First"})
11001099
assert.NoError(t, err)
11011100
@@ -1263,9 +1262,12 @@ func TestDataTypes(t *testing.T) {
12631262
testValues := testValuesStruct{
12641263
1, 1, 1, 1, 1,
12651264
-1, -1, -1, -1, -1,
1265+
12661266
1.337, 1.337,
1267+
12671268
true,
12681269
"Hello world!",
1270+
12691271
ts,
12701272
nil,
12711273
&tnz,

lib/sqlbuilder/builder.go

+28
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ var (
8888
)
8989

9090
type exprDB interface {
91+
StatementPrepare(ctx context.Context, stmt *exql.Statement) (*sql.Stmt, error)
9192
StatementQuery(ctx context.Context, stmt *exql.Statement, args ...interface{}) (*sql.Rows, error)
9293
StatementQueryRow(ctx context.Context, stmt *exql.Statement, args ...interface{}) (*sql.Row, error)
9394
StatementExec(ctx context.Context, stmt *exql.Statement, args ...interface{}) (sql.Result, error)
@@ -132,6 +133,23 @@ func (b *sqlBuilder) IteratorContext(ctx context.Context, query interface{}, arg
132133
return &iterator{rows, err}
133134
}
134135

136+
func (b *sqlBuilder) Prepare(query interface{}) (*sql.Stmt, error) {
137+
return b.PrepareContext(b.sess.Context(), query)
138+
}
139+
140+
func (b *sqlBuilder) PrepareContext(ctx context.Context, query interface{}) (*sql.Stmt, error) {
141+
switch q := query.(type) {
142+
case *exql.Statement:
143+
return b.sess.StatementPrepare(ctx, q)
144+
case string:
145+
return b.sess.StatementPrepare(ctx, exql.RawSQL(q))
146+
case db.RawValue:
147+
return b.PrepareContext(ctx, q.Raw())
148+
default:
149+
return nil, fmt.Errorf("Unsupported query type %T.", query)
150+
}
151+
}
152+
135153
func (b *sqlBuilder) Exec(query interface{}, args ...interface{}) (sql.Result, error) {
136154
return b.ExecContext(b.sess.Context(), query, args...)
137155
}
@@ -389,6 +407,8 @@ func columnFragments(columns []interface{}) ([]exql.Fragment, []interface{}, err
389407
f[i] = v
390408
case string:
391409
f[i] = exql.ColumnWithName(v)
410+
case int:
411+
f[i] = exql.RawValue(fmt.Sprintf("%v", v))
392412
case interface{}:
393413
f[i] = exql.ColumnWithName(fmt.Sprintf("%v", v))
394414
default:
@@ -562,6 +582,14 @@ func (p *exprProxy) StatementExec(ctx context.Context, stmt *exql.Statement, arg
562582
return compat.ExecContext(p.db, ctx, s, args)
563583
}
564584

585+
func (p *exprProxy) StatementPrepare(ctx context.Context, stmt *exql.Statement) (*sql.Stmt, error) {
586+
s, err := stmt.Compile(p.t)
587+
if err != nil {
588+
return nil, err
589+
}
590+
return compat.PrepareContext(p.db, ctx, s)
591+
}
592+
565593
func (p *exprProxy) StatementQuery(ctx context.Context, stmt *exql.Statement, args ...interface{}) (*sql.Rows, error) {
566594
s, err := stmt.Compile(p.t)
567595
if err != nil {

lib/sqlbuilder/delete.go

+12
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@ func (del *deleter) Arguments() []interface{} {
127127
return dq.arguments()
128128
}
129129

130+
func (del *deleter) Prepare() (*sql.Stmt, error) {
131+
return del.PrepareContext(del.SQLBuilder().sess.Context())
132+
}
133+
134+
func (del *deleter) PrepareContext(ctx context.Context) (*sql.Stmt, error) {
135+
dq, err := del.build()
136+
if err != nil {
137+
return nil, err
138+
}
139+
return del.SQLBuilder().sess.StatementPrepare(ctx, dq.statement())
140+
}
141+
130142
func (del *deleter) Exec() (sql.Result, error) {
131143
return del.ExecContext(del.SQLBuilder().sess.Context())
132144
}

0 commit comments

Comments
 (0)