Skip to content

Commit 89135f4

Browse files
authored
Merge pull request globalsign#152 from globalsign/release/r2018.04.23
Release/r2018.04.23
2 parents 1601ff5 + 41f09a9 commit 89135f4

22 files changed

+927
-98
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
_harness
2-
2+
.vscode

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ language: go
33
go_import_path: github.com/globalsign/mgo
44

55
go:
6-
- 1.8.x
76
- 1.9.x
7+
- 1.10.x
88

99
env:
1010
global:
@@ -29,7 +29,7 @@ install:
2929
- go get gopkg.in/check.v1
3030
- go get gopkg.in/yaml.v2
3131
- go get gopkg.in/tomb.v2
32-
- go get github.com/golang/lint/golint
32+
- go get github.com/golang/lint
3333

3434
before_script:
3535
- golint ./... | grep -v 'ID' | cat

README.md

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33
The MongoDB driver for Go
44
-------------------------
55

6-
This fork has had a few improvements by ourselves as well as several PR's merged from the original mgo repo that are currently awaiting review. Changes are mostly geared towards performance improvements and bug fixes, though a few new features have been added.
6+
This fork has had a few improvements by ourselves as well as several PR's merged from the original mgo repo that are currently awaiting review.
7+
Changes are mostly geared towards performance improvements and bug fixes, though a few new features have been added.
78

89
Further PR's (with tests) are welcome, but please maintain backwards compatibility.
910

11+
Detailed documentation of the API is available at
12+
[GoDoc](https://godoc.org/github.com/globalsign/mgo).
13+
14+
A [sub-package](https://godoc.org/github.com/globalsign/mgo/bson) that implements the [BSON](http://bsonspec.org) specification is also included, and may be used independently of the driver.
15+
1016
## Changes
1117
* Fixes attempting to authenticate before every query ([details](https://github.com/go-mgo/mgo/issues/254))
1218
* Removes bulk update / delete batch size limitations ([details](https://github.com/go-mgo/mgo/issues/288))
@@ -15,13 +21,13 @@ Further PR's (with tests) are welcome, but please maintain backwards compatibili
1521
* Support majority read concerns ([details](https://github.com/globalsign/mgo/pull/2))
1622
* Improved connection handling ([details](https://github.com/globalsign/mgo/pull/5))
1723
* Hides SASL warnings ([details](https://github.com/globalsign/mgo/pull/7))
18-
* Support for partial indexes ([detials](https://github.com/domodwyer/mgo/commit/5efe8eccb028238d93c222828cae4806aeae9f51))
19-
* Fixes timezone handling ([details](https://github.com/go-mgo/mgo/pull/464))
24+
* Support for partial indexes ([details](https://github.com/domodwyer/mgo/commit/5efe8eccb028238d93c222828cae4806aeae9f51))
25+
* Fixes timezone handling ([details](https://github.com/go-mgo/mgo/pull/464))
2026
* Integration tests run against MongoDB 3.2 & 3.4 releases ([details](https://github.com/globalsign/mgo/pull/4), [more](https://github.com/globalsign/mgo/pull/24), [more](https://github.com/globalsign/mgo/pull/35))
2127
* Improved multi-document transaction performance ([details](https://github.com/globalsign/mgo/pull/10), [more](https://github.com/globalsign/mgo/pull/11), [more](https://github.com/globalsign/mgo/pull/16))
2228
* Fixes cursor timeouts ([details](https://jira.mongodb.org/browse/SERVER-24899))
2329
* Support index hints and timeouts for count queries ([details](https://github.com/globalsign/mgo/pull/17))
24-
* Don't panic when handling indexed `int64` fields ([detials](https://github.com/go-mgo/mgo/issues/475))
30+
* Don't panic when handling indexed `int64` fields ([details](https://github.com/go-mgo/mgo/issues/475))
2531
* Supports dropping all indexes on a collection ([details](https://github.com/globalsign/mgo/pull/25))
2632
* Annotates log entries/profiler output with optional appName on 3.4+ ([details](https://github.com/globalsign/mgo/pull/28))
2733
* Support for read-only [views](https://docs.mongodb.com/manual/core/views/) in 3.4+ ([details](https://github.com/globalsign/mgo/pull/33))
@@ -37,27 +43,39 @@ Further PR's (with tests) are welcome, but please maintain backwards compatibili
3743
* Use JSON tags when no explicit BSON are tags set ([details](https://github.com/globalsign/mgo/pull/91))
3844
* Support [$changeStream](https://docs.mongodb.com/manual/changeStreams/) tailing on 3.6+ ([details](https://github.com/globalsign/mgo/pull/97))
3945
* Fix deadlock in cluster synchronisation ([details](https://github.com/globalsign/mgo/issues/120))
46+
* Implement `maxIdleTimeout` for pooled connections ([details](https://github.com/globalsign/mgo/pull/116))
47+
* Connection pool waiting improvements ([details](https://github.com/globalsign/mgo/pull/115))
48+
* Fixes BSON encoding for `$in` and friends ([details](https://github.com/globalsign/mgo/pull/128))
49+
* Add BSON stream encoders ([details](https://github.com/globalsign/mgo/pull/127))
50+
* Add integer map key support in the BSON encoder ([details](https://github.com/globalsign/mgo/pull/140))
51+
* Support aggregation [collations](https://docs.mongodb.com/manual/reference/collation/) ([details](https://github.com/globalsign/mgo/pull/144))
4052

4153
---
4254

4355
### Thanks to
56+
* @aksentyev
4457
* @bachue
4558
* @bozaro
4659
* @BenLubar
60+
* @carldunham
4761
* @carter2000
4862
* @cezarsa
4963
* @drichelson
5064
* @dvic
5165
* @eaglerayp
5266
* @feliixx
5367
* @fmpwizard
68+
* @gazoon
69+
* @gnawux
5470
* @idy
5571
* @jameinel
72+
* @johnlawsharrison
5673
* @KJTsanaktsidis
57-
* @gazoon
5874
* @mapete94
75+
* @maxnoel
76+
* @mcspring
5977
* @peterdeka
6078
* @Reenjii
6179
* @smoya
6280
* @steve-gray
63-
* @wgallagher
81+
* @wgallagher

bson/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[![GoDoc](https://godoc.org/github.com/globalsign/mgo/bson?status.svg)](https://godoc.org/github.com/globalsign/mgo/bson)
2+
3+
An Implementation of BSON for Go
4+
--------------------------------
5+
6+
Package bson is an implementation of the [BSON specification](http://bsonspec.org) for Go.
7+
8+
While the BSON package implements the BSON spec as faithfully as possible, there
9+
is some MongoDB specific behaviour (such as map keys `$in`, `$all`, etc) in the
10+
`bson` package. The priority is for backwards compatibility for the `mgo`
11+
driver, though fixes for obviously buggy behaviour is welcome (and features, etc
12+
behind feature flags).

bson/bson_test.go

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ import (
3434
"errors"
3535
"net/url"
3636
"reflect"
37+
"strings"
3738
"testing"
3839
"time"
39-
"strings"
4040

4141
"github.com/globalsign/mgo/bson"
4242
. "gopkg.in/check.v1"
@@ -111,6 +111,10 @@ var sampleItems = []testItemType{
111111
{bson.M{"BSON": []interface{}{"awesome", float64(5.05), 1986}},
112112
"1\x00\x00\x00\x04BSON\x00&\x00\x00\x00\x020\x00\x08\x00\x00\x00" +
113113
"awesome\x00\x011\x00333333\x14@\x102\x00\xc2\x07\x00\x00\x00\x00"},
114+
{bson.M{"slice": []uint8{1, 2}},
115+
"\x13\x00\x00\x00\x05slice\x00\x02\x00\x00\x00\x00\x01\x02\x00"},
116+
{bson.M{"slice": []byte{1, 2}},
117+
"\x13\x00\x00\x00\x05slice\x00\x02\x00\x00\x00\x00\x01\x02\x00"},
114118
}
115119

116120
func (s *S) TestMarshalSampleItems(c *C) {
@@ -343,6 +347,27 @@ func (s *S) TestOneWayMarshalItems(c *C) {
343347
}
344348
}
345349

350+
// --------------------------------------------------------------------------
351+
// Some ops marshaling operations which would encode []uint8 or []byte in array.
352+
353+
var arrayOpsMarshalItems = []testItemType{
354+
{bson.M{"_": bson.M{"$in": []uint8{1, 2}}},
355+
"\x03_\x00\x1d\x00\x00\x00\x04$in\x00\x13\x00\x00\x00\x100\x00\x01\x00\x00\x00\x101\x00\x02\x00\x00\x00\x00\x00"},
356+
{bson.M{"_": bson.M{"$nin": []uint8{1, 2}}},
357+
"\x03_\x00\x1e\x00\x00\x00\x04$nin\x00\x13\x00\x00\x00\x100\x00\x01\x00\x00\x00\x101\x00\x02\x00\x00\x00\x00\x00"},
358+
{bson.M{"_": bson.M{"$all": []uint8{1, 2}}},
359+
"\x03_\x00\x1e\x00\x00\x00\x04$all\x00\x13\x00\x00\x00\x100\x00\x01\x00\x00\x00\x101\x00\x02\x00\x00\x00\x00\x00"},
360+
}
361+
362+
func (s *S) TestArrayOpsMarshalItems(c *C) {
363+
for i, item := range arrayOpsMarshalItems {
364+
data, err := bson.Marshal(item.obj)
365+
c.Assert(err, IsNil)
366+
c.Assert(string(data), Equals, wrapInDoc(item.data),
367+
Commentf("Failed on item %d", i))
368+
}
369+
}
370+
346371
// --------------------------------------------------------------------------
347372
// Two-way tests for user-defined structures using the samples
348373
// from bsonspec.org.
@@ -582,6 +607,8 @@ func (s *S) TestMarshalOneWayItems(c *C) {
582607
// --------------------------------------------------------------------------
583608
// One-way unmarshaling tests.
584609

610+
type intAlias int
611+
585612
var unmarshalItems = []testItemType{
586613
// Field is private. Should not attempt to unmarshal it.
587614
{&struct{ priv byte }{},
@@ -636,6 +663,14 @@ var unmarshalItems = []testItemType{
636663
// Decode a doc within a doc in to a slice within a doc; shouldn't error
637664
{&struct{ Foo []string }{},
638665
"\x03\x66\x6f\x6f\x00\x05\x00\x00\x00\x00"},
666+
667+
// int key maps
668+
{map[int]string{10: "s"},
669+
"\x0210\x00\x02\x00\x00\x00s\x00"},
670+
671+
//// event if type is alias to int
672+
{map[intAlias]string{10: "s"},
673+
"\x0210\x00\x02\x00\x00\x00s\x00"},
639674
}
640675

641676
func (s *S) TestUnmarshalOneWayItems(c *C) {
@@ -713,11 +748,6 @@ var unmarshalErrorItems = []unmarshalErrorType{
713748
"\x10name\x00\x08\x00\x00\x00",
714749
"Duplicated key 'name' in struct bson_test.structWithDupKeys"},
715750

716-
// Non-string map key.
717-
{map[int]interface{}{},
718-
"\x10name\x00\x08\x00\x00\x00",
719-
"BSON map must have string keys. Got: map\\[int\\]interface \\{\\}"},
720-
721751
{nil,
722752
"\xEEname\x00",
723753
"Unknown element kind \\(0xEE\\)"},
@@ -733,6 +763,11 @@ var unmarshalErrorItems = []unmarshalErrorType{
733763
{nil,
734764
"\x08\x62\x00\x02",
735765
"encoded boolean must be 1 or 0, found 2"},
766+
767+
// Non-string and not numeric map key.
768+
{map[bool]interface{}{true: 1},
769+
"\x10true\x00\x01\x00\x00\x00",
770+
"BSON map must have string or decimal keys. Got: map\\[bool\\]interface \\{\\}"},
736771
}
737772

738773
func (s *S) TestUnmarshalErrorItems(c *C) {
@@ -1136,8 +1171,8 @@ type inlineBadKeyMap struct {
11361171
M map[int]int `bson:",inline"`
11371172
}
11381173
type inlineUnexported struct {
1139-
M map[string]interface{} `bson:",inline"`
1140-
unexported `bson:",inline"`
1174+
M map[string]interface{} `bson:",inline"`
1175+
unexported `bson:",inline"`
11411176
}
11421177
type unexported struct {
11431178
A int
@@ -1194,11 +1229,11 @@ func (s ifaceSlice) GetBSON() (interface{}, error) {
11941229

11951230
type (
11961231
MyString string
1197-
MyBytes []byte
1198-
MyBool bool
1199-
MyD []bson.DocElem
1200-
MyRawD []bson.RawDocElem
1201-
MyM map[string]interface{}
1232+
MyBytes []byte
1233+
MyBool bool
1234+
MyD []bson.DocElem
1235+
MyRawD []bson.RawDocElem
1236+
MyM map[string]interface{}
12021237
)
12031238

12041239
var (

bson/decode.go

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,6 @@ func (d *decoder) readDocTo(out reflect.Value) {
176176
switch outk {
177177
case reflect.Map:
178178
keyType = outt.Key()
179-
if keyType.Kind() != reflect.String {
180-
panic("BSON map must have string keys. Got: " + outt.String())
181-
}
182179
if keyType != typeString {
183180
convertKey = true
184181
}
@@ -240,7 +237,42 @@ func (d *decoder) readDocTo(out reflect.Value) {
240237
if d.readElemTo(e, kind) {
241238
k := reflect.ValueOf(name)
242239
if convertKey {
243-
k = k.Convert(keyType)
240+
mapKeyType := out.Type().Key()
241+
mapKeyKind := mapKeyType.Kind()
242+
243+
switch mapKeyKind {
244+
case reflect.Int:
245+
fallthrough
246+
case reflect.Int8:
247+
fallthrough
248+
case reflect.Int16:
249+
fallthrough
250+
case reflect.Int32:
251+
fallthrough
252+
case reflect.Int64:
253+
fallthrough
254+
case reflect.Uint:
255+
fallthrough
256+
case reflect.Uint8:
257+
fallthrough
258+
case reflect.Uint16:
259+
fallthrough
260+
case reflect.Uint32:
261+
fallthrough
262+
case reflect.Uint64:
263+
fallthrough
264+
case reflect.Float32:
265+
fallthrough
266+
case reflect.Float64:
267+
parsed := d.parseMapKeyAsFloat(k, mapKeyKind)
268+
k = reflect.ValueOf(parsed)
269+
case reflect.String:
270+
mapKeyType = keyType
271+
default:
272+
panic("BSON map must have string or decimal keys. Got: " + outt.String())
273+
}
274+
275+
k = k.Convert(mapKeyType)
244276
}
245277
out.SetMapIndex(k, e)
246278
}
@@ -276,6 +308,16 @@ func (d *decoder) readDocTo(out reflect.Value) {
276308
d.docType = docType
277309
}
278310

311+
func (decoder) parseMapKeyAsFloat(k reflect.Value, mapKeyKind reflect.Kind) float64 {
312+
parsed, err := strconv.ParseFloat(k.String(), 64)
313+
if err != nil {
314+
panic("Map key is defined to be a decimal type (" + mapKeyKind.String() + ") but got error " +
315+
err.Error())
316+
}
317+
318+
return parsed
319+
}
320+
279321
func (d *decoder) readArrayDocTo(out reflect.Value) {
280322
end := int(d.readInt32())
281323
end += d.i - 4

bson/encode.go

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ var (
6060
typeTimeDuration = reflect.TypeOf(time.Duration(0))
6161
)
6262

63+
var (
64+
// spec for []uint8 or []byte encoding
65+
arrayOps = map[string]bool{
66+
"$in": true,
67+
"$nin": true,
68+
"$all": true,
69+
}
70+
)
71+
6372
const itoaCacheSize = 32
6473

6574
const (
@@ -194,7 +203,7 @@ func (e *encoder) addDoc(v reflect.Value) {
194203

195204
func (e *encoder) addMap(v reflect.Value) {
196205
for _, k := range v.MapKeys() {
197-
e.addElem(k.String(), v.MapIndex(k), false)
206+
e.addElem(fmt.Sprint(k), v.MapIndex(k), false)
198207
}
199208
}
200209

@@ -423,8 +432,13 @@ func (e *encoder) addElem(name string, v reflect.Value, minSize bool) {
423432
vt := v.Type()
424433
et := vt.Elem()
425434
if et.Kind() == reflect.Uint8 {
426-
e.addElemName(0x05, name)
427-
e.addBinary(0x00, v.Bytes())
435+
if arrayOps[name] {
436+
e.addElemName(0x04, name)
437+
e.addDoc(v)
438+
} else {
439+
e.addElemName(0x05, name)
440+
e.addBinary(0x00, v.Bytes())
441+
}
428442
} else if et == typeDocElem || et == typeRawDocElem {
429443
e.addElemName(0x03, name)
430444
e.addDoc(v)
@@ -436,16 +450,21 @@ func (e *encoder) addElem(name string, v reflect.Value, minSize bool) {
436450
case reflect.Array:
437451
et := v.Type().Elem()
438452
if et.Kind() == reflect.Uint8 {
439-
e.addElemName(0x05, name)
440-
if v.CanAddr() {
441-
e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte))
453+
if arrayOps[name] {
454+
e.addElemName(0x04, name)
455+
e.addDoc(v)
442456
} else {
443-
n := v.Len()
444-
e.addInt32(int32(n))
445-
e.addBytes(0x00)
446-
for i := 0; i < n; i++ {
447-
el := v.Index(i)
448-
e.addBytes(byte(el.Uint()))
457+
e.addElemName(0x05, name)
458+
if v.CanAddr() {
459+
e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte))
460+
} else {
461+
n := v.Len()
462+
e.addInt32(int32(n))
463+
e.addBytes(0x00)
464+
for i := 0; i < n; i++ {
465+
el := v.Index(i)
466+
e.addBytes(byte(el.Uint()))
467+
}
449468
}
450469
}
451470
} else {

0 commit comments

Comments
 (0)