update deps

This commit is contained in:
Umputun
2022-04-15 12:50:05 -05:00
parent 53df70bcef
commit f4856c86d7
161 changed files with 2294 additions and 877 deletions
+10 -9
View File
@@ -16,7 +16,7 @@ require (
github.com/go-pkgz/lcw v0.8.1
github.com/go-pkgz/lgr v0.10.4
github.com/go-pkgz/repeater v1.1.3
github.com/go-pkgz/rest v1.13.0
github.com/go-pkgz/rest v1.14.0
github.com/go-pkgz/syncs v1.2.0
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.3.0
@@ -34,13 +34,13 @@ require (
github.com/stretchr/testify v1.7.1
go.etcd.io/bbolt v1.3.6
go.uber.org/goleak v1.1.12
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29
golang.org/x/image v0.0.0-20220321031419-a8550c1d254a
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
golang.org/x/net v0.0.0-20220412020605-290c469a71a5
)
require (
cloud.google.com/go/compute v1.5.0 // indirect
cloud.google.com/go/compute v1.6.0 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -61,16 +61,17 @@ require (
github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.3.0 // indirect
github.com/valyala/fasthttp v1.35.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
go.mongodb.org/mongo-driver v1.8.4 // indirect
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
go.mongodb.org/mongo-driver v1.9.0 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+40 -18
View File
@@ -37,8 +37,9 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/compute v1.2.0/go.mod h1:xlogom/6gr8RJGBe7nT2eGsQYAFUbbv8dbC29qE3Xmw=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
cloud.google.com/go/compute v1.5.0 h1:b1zWmYuuHz7gO9kDcM/EpHGr06UgsYNRpNJzI2kFiLM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
cloud.google.com/go/compute v1.6.0 h1:XdQIN5mdPTSBVwSIVDuY5e8ZzVAccsHvD3qTEz4zIps=
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
@@ -72,8 +73,9 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMw
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis/v2 v2.11.4 h1:GsuyeunTx7EllZBU3/6Ji3dhMQZDpC9rLf1luJ+6M5M=
github.com/alicebob/miniredis/v2 v2.11.4/go.mod h1:VL3UDEfAH59bSa7MuHMuFToxkqyHh69s/WUbYlOAuyg=
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@@ -154,8 +156,8 @@ github.com/go-pkgz/repeater v1.1.3 h1:q6+JQF14ESSy28Dd7F+wRelY4F+41HJ0LEy/szNnMi
github.com/go-pkgz/repeater v1.1.3/go.mod h1:hVTavuO5x3Gxnu8zW7d6sQBfAneKV8X2FjU48kGfpKw=
github.com/go-pkgz/rest v1.5.0/go.mod h1:nQaM3RhSTUAmbBZWY4hfe4buyeC9VckvhoCktiQXJxI=
github.com/go-pkgz/rest v1.12.2/go.mod h1:KUWAqbDteYGS/CiXftomQsKjtEOifXsJ36Ka0skYbmk=
github.com/go-pkgz/rest v1.13.0 h1:1larroBzcOYC5ySdrCLaXIEG1SGNnPborxm6uK+2RLQ=
github.com/go-pkgz/rest v1.13.0/go.mod h1:KUWAqbDteYGS/CiXftomQsKjtEOifXsJ36Ka0skYbmk=
github.com/go-pkgz/rest v1.14.0 h1:brDLCzIGoe0IiUZqRFpsiCVM9m3L88A7z62qS0V9Yfk=
github.com/go-pkgz/rest v1.14.0/go.mod h1:KUWAqbDteYGS/CiXftomQsKjtEOifXsJ36Ka0skYbmk=
github.com/go-pkgz/syncs v1.2.0 h1:aiizQFILlMZ4KtRNaYLcDffRbUQZH9fclsgr5KybWyY=
github.com/go-pkgz/syncs v1.2.0/go.mod h1:fjThZdM2FkC/oSeiqBTOZOtHpbrCh4HuHbipB5qZJJM=
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
@@ -251,6 +253,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
@@ -286,6 +290,7 @@ github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -375,9 +380,11 @@ github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 h1:Otn9S136ELckZ
github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563/go.mod h1:mLqSmt7Dv/CNneF2wfcChfN1rvapyQr01LGKnKex0DQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.14.0 h1:67bfuW9azCMwW/Jlq/C+VeihNpAuJMWkYPBig1gdi3A=
github.com/valyala/fasthttp v1.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE=
github.com/valyala/fasthttp v1.35.0 h1:wwkR8mZn2NbigFsaw2Zj5r+xkmzjbrA/lyTmiSlal/Y=
github.com/valyala/fasthttp v1.35.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
@@ -413,8 +420,8 @@ github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBU
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA=
go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
go.mongodb.org/mongo-driver v1.9.0 h1:WISF656tVHlYe/kd+istlX++s+UbjL5X8f8qKCwl/Ms=
go.mongodb.org/mongo-driver v1.9.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -433,8 +440,9 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -448,8 +456,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220321031419-a8550c1d254a h1:LnH9RNcpPv5Kzi15lXg42lYMPUf0x8CuPv1YnvBWZAg=
golang.org/x/image v0.0.0-20220321031419-a8550c1d254a/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE=
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -516,8 +524,10 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0=
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -534,8 +544,10 @@ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -613,8 +625,10 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64 h1:D1v9ucDTYBtbz5vNuBbAhIMAGhQhJ6Ym5ah3maMVNX4=
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -632,8 +646,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -727,6 +741,8 @@ google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tD
google.golang.org/api v0.66.0/go.mod h1:I1dmXYpX7HGwz/ejRxwQp2qj5bFAz93HiCU1C1oYd9M=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -801,6 +817,11 @@ google.golang.org/genproto v0.0.0-20220201184016-50beb8ab5c44/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -828,6 +849,7 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+8 -11
View File
@@ -93,37 +93,32 @@ Adds the HTTP Deprecation response header, see [draft-dalal-deprecation-header-0
BasicAuth middleware requires basic auth and matches user & passwd with client-provided checker. In case if no basic auth headers returns
`StatusUnauthorized`, in case if checker failed - `StatusForbidden`
## Rewrite middleware
### Rewrite middleware
Rewrites requests with from->to rule. Supports regex (like nginx) and prevents multiple rewrites. For example `Rewrite("^/sites/(.*)/settings/$", "/sites/settings/$1")` will change request's URL from `/sites/id1/settings/` to `/sites/settings/id1`
## NoCache middleware
### NoCache middleware
Sets a number of HTTP headers to prevent a router (handler's) response from being cached by an upstream proxy and/or client.
## Headers middleware
### Headers middleware
Sets headers (passed as key:value) to requests. I.e. `rest.Headers("Server:MyServer", "X-Blah:Foo")`
## Gzip middleware
### Gzip middleware
Compresses response with gzip.
## RealIP middleware
### RealIP middleware
RealIP is a middleware that sets a http.Request's RemoteAddr to the results of parsing either the X-Forwarded-For or X-Real-IP headers.
## Maybe middleware
### Maybe middleware
Maybe middleware will allow you to change the flow of the middleware stack execution depending on return
value of maybeFn(request). This is useful for example if you'd like to skip a middleware handler if
a request does not satisfy the maybeFn logic.
## Headers middleware
Headers middleware adds headers to request
## Helpers
- `rest.Wrap` - converts a list of middlewares to nested handlers calls (in reverse order)
@@ -134,6 +129,8 @@ Headers middleware adds headers to request
- `rest.SendErrorJSON` - makes `{error: blah, details: blah}` json body and responds with given error code. Also, adds context to the logged message
- `rest.NewErrorLogger` - creates a struct providing shorter form of logger call
- `rest.FileServer` - creates a file server for static assets with directory listing disabled
- `realip.Get` - returns client's IP address
- `rest.ParseFromTo` - parses "from" and "to" request's query params with various formats
## Profiler
+15
View File
@@ -296,6 +296,21 @@ func (l *Middleware) sanitizeQuery(rawQuery string) string {
return query.Encode()
}
// AnonymizeIP is a function to reset the last part of IPv4 to 0.
// from 123.212.12.78 it will make 123.212.12.0
func AnonymizeIP(ip string) string {
if ip == "" {
return ""
}
parts := strings.Split(ip, ".")
if len(parts) != 4 {
return ip
}
return strings.Join(parts[:3], ".") + ".0"
}
// customResponseWriter is an HTTP response logger that keeps HTTP status code and
// the number of bytes written.
// It implements http.ResponseWriter, http.Flusher and http.Hijacker.
+31
View File
@@ -5,6 +5,7 @@ import (
"bytes"
"encoding/json"
"net/http"
"time"
"github.com/pkg/errors"
)
@@ -67,3 +68,33 @@ func renderJSONWithStatus(w http.ResponseWriter, data interface{}, code int) {
w.WriteHeader(code)
_, _ = w.Write(buf.Bytes())
}
// ParseFromTo parses from and to query params of the request
func ParseFromTo(r *http.Request) (from, to time.Time, err error) {
parseTimeStamp := func(ts string) (time.Time, error) {
formats := []string{
"2006-01-02T15:04:05.000000000",
"2006-01-02T15:04:05",
"2006-01-02T15:04",
"20060102",
time.RFC3339,
time.RFC3339Nano,
}
for _, f := range formats {
if t, e := time.Parse(f, ts); e == nil {
return t, nil
}
}
return time.Time{}, errors.Errorf("can't parse date %q", ts)
}
if from, err = parseTimeStamp(r.URL.Query().Get("from")); err != nil {
return from, to, errors.Wrap(err, "incorrect from time")
}
if to, err = parseTimeStamp(r.URL.Query().Get("to")); err != nil {
return from, to, errors.Wrap(err, "incorrect to time")
}
return from, to, nil
}
+1 -1
View File
@@ -43,7 +43,7 @@ type Unmarshaler interface {
}
// ValueUnmarshaler is an interface implemented by types that can unmarshal a
// BSON value representaiton of themselves. The BSON bytes and type can be
// BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning.
type ValueUnmarshaler interface {
@@ -53,7 +53,7 @@ type DefaultValueDecoders struct{}
// RegisterDefaultDecoders will register the decoder methods attached to DefaultValueDecoders with
// the provided RegistryBuilder.
//
// There is no support for decoding map[string]interface{} becuase there is no decoder for
// There is no support for decoding map[string]interface{} because there is no decoder for
// interface{}, so users must either register this decoder themselves or use the
// EmptyInterfaceDecoder available in the bson package.
func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
@@ -1504,6 +1504,18 @@ func (dvd DefaultValueDecoders) UnmarshalerDecodeValue(dc DecodeContext, vr bson
return err
}
// If the target Go value is a pointer and the BSON field value is empty, set the value to the
// zero value of the pointer (nil) and don't call UnmarshalBSON. UnmarshalBSON has no way to
// change the pointer value from within the function (only the value at the pointer address),
// so it can't set the pointer to "nil" itself. Since the most common Go value for an empty BSON
// field value is "nil", we set "nil" here and don't call UnmarshalBSON. This behavior matches
// the behavior of the Go "encoding/json" unmarshaler when the target Go value is a pointer and
// the JSON field value is "null".
if val.Kind() == reflect.Ptr && len(src) == 0 {
val.Set(reflect.Zero(val.Type()))
return nil
}
fn := val.Convert(tUnmarshaler).MethodByName("UnmarshalBSON")
errVal := fn.Call([]reflect.Value{reflect.ValueOf(src)})[0]
if !errVal.IsNil() {
+2 -2
View File
@@ -298,7 +298,7 @@ func (rb *RegistryBuilder) Build() *Registry {
return registry
}
// LookupEncoder inspects the registry for an encoder for the given type. The lookup precendence works as follows:
// LookupEncoder inspects the registry for an encoder for the given type. The lookup precedence works as follows:
//
// 1. An encoder registered for the exact type. If the given type represents an interface, an encoder registered using
// RegisterTypeEncoder for the interface will be selected.
@@ -376,7 +376,7 @@ func (r *Registry) lookupInterfaceEncoder(t reflect.Type, allowAddr bool) (Value
return nil, false
}
// LookupDecoder inspects the registry for an decoder for the given type. The lookup precendence works as follows:
// LookupDecoder inspects the registry for an decoder for the given type. The lookup precedence works as follows:
//
// 1. A decoder registered for the exact type. If the given type represents an interface, a decoder registered using
// RegisterTypeDecoder for the interface will be selected.
+1 -1
View File
@@ -423,7 +423,7 @@ func (ejp *extJSONParser) readValue(t bsontype.Type) (*extJSONValue, error) {
if ejp.canonical {
return nil, invalidJSONErrorForType("object", t)
}
return nil, invalidJSONErrorForType("ISO-8601 Internet Date/Time Format as decribed in RFC-3339", t)
return nil, invalidJSONErrorForType("ISO-8601 Internet Date/Time Format as described in RFC-3339", t)
}
ejp.advanceState()
+9 -1
View File
@@ -384,9 +384,13 @@ func (vr *valueReader) ReadBinary() (b []byte, btype byte, err error) {
if err != nil {
return nil, 0, err
}
// Make a copy of the returned byte slice because it's just a subslice from the valueReader's
// buffer and is not safe to return in the unmarshaled value.
cp := make([]byte, len(b))
copy(cp, b)
vr.pop()
return b, btype, nil
return cp, btype, nil
}
func (vr *valueReader) ReadBoolean() (bool, error) {
@@ -737,6 +741,9 @@ func (vr *valueReader) ReadValue() (ValueReader, error) {
return vr, nil
}
// readBytes reads length bytes from the valueReader starting at the current offset. Note that the
// returned byte slice is a subslice from the valueReader buffer and must be converted or copied
// before returning in an unmarshaled value.
func (vr *valueReader) readBytes(length int32) ([]byte, error) {
if length < 0 {
return nil, fmt.Errorf("invalid length: %d", length)
@@ -748,6 +755,7 @@ func (vr *valueReader) readBytes(length int32) ([]byte, error) {
start := vr.offset
vr.offset += int64(length)
return vr.d[start : start+int64(length)], nil
}
+1 -1
View File
@@ -529,7 +529,7 @@ func (vw *valueWriter) WriteDocumentEnd() error {
vw.pop()
if vw.stack[vw.frame].mode == mCodeWithScope {
// We ignore the error here because of the gaurantee of writeLength.
// We ignore the error here because of the guarantee of writeLength.
// See the docs for writeLength for more info.
_ = vw.writeLength()
vw.pop()
+1 -1
View File
@@ -118,7 +118,7 @@
// types, this tag is ignored.
//
// 3. truncate: If the truncate struct tag is specified on a field with a non-float numeric type, BSON doubles unmarshalled
// into that field will be trucated at the decimal point. For example, if 3.14 is unmarshalled into a field of type int,
// into that field will be truncated at the decimal point. For example, if 3.14 is unmarshalled into a field of type int,
// it will be unmarshalled as 3. If this tag is not specified, the decoder will throw an error if the value cannot be
// decoded without losing precision. For float64 or non-numeric types, this tag is ignored.
//
+3
View File
@@ -225,10 +225,13 @@ func MarshalExtJSONAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val
return *sw, nil
}
// IndentExtJSON will prefix and indent the provided extended JSON src and append it to dst.
func IndentExtJSON(dst *bytes.Buffer, src []byte, prefix, indent string) error {
return json.Indent(dst, src, prefix, indent)
}
// MarshalExtJSONIndent returns the extended JSON encoding of val with each line with prefixed
// and indented.
func MarshalExtJSONIndent(val interface{}, canonical, escapeHTML bool, prefix, indent string) ([]byte, error) {
marshaled, err := MarshalExtJSON(val, canonical, escapeHTML)
if err != nil {
+1 -1
View File
@@ -13,7 +13,7 @@ import "go.mongodb.org/mongo-driver/bson/bsoncodec"
var DefaultRegistry = NewRegistryBuilder().Build()
// NewRegistryBuilder creates a new RegistryBuilder configured with the default encoders and
// deocders from the bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the
// decoders from the bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the
// PrimitiveCodecs type in this package.
func NewRegistryBuilder() *bsoncodec.RegistryBuilder {
rb := bsoncodec.NewRegistryBuilder()
+1 -1
View File
@@ -23,7 +23,7 @@ type Unmarshaler interface {
}
// ValueUnmarshaler is an interface implemented by types that can unmarshal a
// BSON value representaiton of themselves. The BSON bytes and type can be
// BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning.
type ValueUnmarshaler interface {
+6 -3
View File
@@ -70,19 +70,22 @@ const (
ReasonStale = "stale"
ReasonConnectionErrored = "connectionError"
ReasonTimedOut = "timeout"
ReasonError = "error"
)
// strings for pool command monitoring types
const (
ConnectionClosed = "ConnectionClosed"
PoolCreated = "ConnectionPoolCreated"
PoolReady = "ConnectionPoolReady"
PoolCleared = "ConnectionPoolCleared"
PoolClosedEvent = "ConnectionPoolClosed"
ConnectionCreated = "ConnectionCreated"
ConnectionReady = "ConnectionReady"
ConnectionClosed = "ConnectionClosed"
GetStarted = "ConnectionCheckOutStarted"
GetFailed = "ConnectionCheckOutFailed"
GetSucceeded = "ConnectionCheckedOut"
ConnectionReturned = "ConnectionCheckedIn"
PoolCleared = "ConnectionPoolCleared"
PoolClosedEvent = "ConnectionPoolClosed"
)
// MonitorPoolOptions contains pool options as formatted in pool events
@@ -1,7 +1,16 @@
// Copyright (C) MongoDB, Inc. 2022-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Package randutil provides common random number utilities.
package randutil
import (
crand "crypto/rand"
"fmt"
"io"
"math/rand"
"sync"
)
@@ -52,3 +61,17 @@ func (lr *LockedRand) Shuffle(n int, swap func(i, j int)) {
lr.r.Shuffle(n, swap)
lr.mu.Unlock()
}
// CryptoSeed returns a random int64 read from the "crypto/rand" random number generator. It is
// intended to be used to seed pseudorandom number generators at package initialization. It panics
// if it encounters any errors.
func CryptoSeed() int64 {
var b [8]byte
_, err := io.ReadFull(crand.Reader, b[:])
if err != nil {
panic(fmt.Errorf("failed to read 8 bytes from a \"crypto/rand\".Reader: %v", err))
}
return (int64(b[0]) << 0) | (int64(b[1]) << 8) | (int64(b[2]) << 16) | (int64(b[3]) << 24) |
(int64(b[4]) << 32) | (int64(b[5]) << 40) | (int64(b[6]) << 48) | (int64(b[7]) << 56)
}
+1 -1
View File
@@ -33,7 +33,7 @@ func StringSliceFromRawValue(name string, val bson.RawValue) ([]string, error) {
return nil, err
}
var strs []string
strs := make([]string, 0, len(arrayValues))
for _, arrayVal := range arrayValues {
str, ok := arrayVal.StringValueOK()
if !ok {
+15
View File
@@ -35,6 +35,7 @@ type bulkWrite struct {
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
result BulkWriteResult
let interface{}
}
func (bw *bulkWrite) execute(ctx context.Context) error {
@@ -228,6 +229,13 @@ func (bw *bulkWrite) runDelete(ctx context.Context, batch bulkWriteBatch) (opera
Database(bw.collection.db.name).Collection(bw.collection.name).
Deployment(bw.collection.client.deployment).Crypt(bw.collection.client.cryptFLE).Hint(hasHint).
ServerAPI(bw.collection.client.serverAPI)
if bw.let != nil {
let, err := transformBsoncoreDocument(bw.collection.registry, bw.let, true, "let")
if err != nil {
return operation.DeleteResult{}, err
}
op = op.Let(let)
}
if bw.ordered != nil {
op = op.Ordered(*bw.ordered)
}
@@ -309,6 +317,13 @@ func (bw *bulkWrite) runUpdate(ctx context.Context, batch bulkWriteBatch) (opera
Database(bw.collection.db.name).Collection(bw.collection.name).
Deployment(bw.collection.client.deployment).Crypt(bw.collection.client.cryptFLE).Hint(hasHint).
ArrayFilters(hasArrayFilters).ServerAPI(bw.collection.client.serverAPI)
if bw.let != nil {
let, err := transformBsoncoreDocument(bw.collection.registry, bw.let, true, "let")
if err != nil {
return operation.UpdateResult{}, err
}
op = op.Let(let)
}
if bw.ordered != nil {
op = op.Ordered(*bw.ordered)
}
+54 -17
View File
@@ -69,21 +69,22 @@ type ChangeStream struct {
// TryNext. If continued access is required, a copy must be made.
Current bson.Raw
aggregate *operation.Aggregate
pipelineSlice []bsoncore.Document
cursor changeStreamCursor
cursorOptions driver.CursorOptions
batch []bsoncore.Document
resumeToken bson.Raw
err error
sess *session.Client
client *Client
registry *bsoncodec.Registry
streamType StreamType
options *options.ChangeStreamOptions
selector description.ServerSelector
operationTime *primitive.Timestamp
wireVersion *description.VersionRange
aggregate *operation.Aggregate
pipelineSlice []bsoncore.Document
pipelineOptions map[string]bsoncore.Value
cursor changeStreamCursor
cursorOptions driver.CursorOptions
batch []bsoncore.Document
resumeToken bson.Raw
err error
sess *session.Client
client *Client
registry *bsoncodec.Registry
streamType StreamType
options *options.ChangeStreamOptions
selector description.ServerSelector
operationTime *primitive.Timestamp
wireVersion *description.VersionRange
}
type changeStreamConfig struct {
@@ -143,6 +144,37 @@ func newChangeStream(ctx context.Context, config changeStreamConfig, pipeline in
if cs.options.MaxAwaitTime != nil {
cs.cursorOptions.MaxTimeMS = int64(*cs.options.MaxAwaitTime / time.Millisecond)
}
if cs.options.Custom != nil {
// Marshal all custom options before passing to the initial aggregate. Return
// any errors from Marshaling.
customOptions := make(map[string]bsoncore.Value)
for optionName, optionValue := range cs.options.Custom {
bsonType, bsonData, err := bson.MarshalValueWithRegistry(cs.registry, optionValue)
if err != nil {
cs.err = err
closeImplicitSession(cs.sess)
return nil, cs.Err()
}
optionValueBSON := bsoncore.Value{Type: bsonType, Data: bsonData}
customOptions[optionName] = optionValueBSON
}
cs.aggregate.CustomOptions(customOptions)
}
if cs.options.CustomPipeline != nil {
// Marshal all custom pipeline options before building pipeline slice. Return
// any errors from Marshaling.
cs.pipelineOptions = make(map[string]bsoncore.Value)
for optionName, optionValue := range cs.options.CustomPipeline {
bsonType, bsonData, err := bson.MarshalValueWithRegistry(cs.registry, optionValue)
if err != nil {
cs.err = err
closeImplicitSession(cs.sess)
return nil, cs.Err()
}
optionValueBSON := bsoncore.Value{Type: bsonType, Data: bsonData}
cs.pipelineOptions[optionName] = optionValueBSON
}
}
switch cs.streamType {
case ClientStream:
@@ -212,7 +244,7 @@ func (cs *ChangeStream) executeOperation(ctx context.Context, resuming bool) err
cs.aggregate.Deployment(cs.createOperationDeployment(server, conn))
if resuming {
cs.replaceOptions(ctx, cs.wireVersion)
cs.replaceOptions(cs.wireVersion)
csOptDoc := cs.createPipelineOptionsDoc()
pipIdx, pipDoc := bsoncore.AppendDocumentStart(nil)
@@ -390,6 +422,11 @@ func (cs *ChangeStream) createPipelineOptionsDoc() bsoncore.Document {
plDoc = bsoncore.AppendTimestampElement(plDoc, "startAtOperationTime", cs.options.StartAtOperationTime.T, cs.options.StartAtOperationTime.I)
}
// Append custom pipeline options.
for optionName, optionValue := range cs.pipelineOptions {
plDoc = bsoncore.AppendValueElement(plDoc, optionName, optionValue)
}
if plDoc, cs.err = bsoncore.AppendDocumentEnd(plDoc, plDocIdx); cs.err != nil {
return nil
}
@@ -408,7 +445,7 @@ func (cs *ChangeStream) pipelineToBSON() (bsoncore.Document, error) {
return pipelineArr, cs.err
}
func (cs *ChangeStream) replaceOptions(ctx context.Context, wireVersion *description.VersionRange) {
func (cs *ChangeStream) replaceOptions(wireVersion *description.VersionRange) {
// Cached resume token: use the resume token as the resumeAfter option and set no other resume options
if cs.resumeToken != nil {
cs.options.SetResumeAfter(cs.resumeToken)
+1 -1
View File
@@ -843,7 +843,7 @@ func (c *Client) Database(name string, opts ...*options.DatabaseOptions) *Databa
// databases are included in the result. It cannot be nil. An empty document (e.g. bson.D{}) should be used to include
// all databases.
//
// The opts paramter can be used to specify options for this operation (see the options.ListDatabasesOptions documentation).
// The opts parameter can be used to specify options for this operation (see the options.ListDatabasesOptions documentation).
//
// For more information about the command, see https://docs.mongodb.com/manual/reference/command/listDatabases/.
func (c *Client) ListDatabases(ctx context.Context, filter interface{}, opts ...*options.ListDatabasesOptions) (ListDatabasesResult, error) {
+78 -15
View File
@@ -225,6 +225,7 @@ func (coll *Collection) BulkWrite(ctx context.Context, models []WriteModel,
collection: coll,
selector: selector,
writeConcern: wc,
let: bwo.Let,
}
err = op.execute(ctx)
@@ -454,6 +455,13 @@ func (coll *Collection) delete(ctx context.Context, filter interface{}, deleteOn
if do.Hint != nil {
op = op.Hint(true)
}
if do.Let != nil {
let, err := transformBsoncoreDocument(coll.registry, do.Let, true, "let")
if err != nil {
return nil, err
}
op = op.Let(let)
}
// deleteMany cannot be retried
retryMode := driver.RetryNone
@@ -548,6 +556,13 @@ func (coll *Collection) updateOrReplace(ctx context.Context, filter bsoncore.Doc
Database(coll.db.name).Collection(coll.name).
Deployment(coll.client.deployment).Crypt(coll.client.cryptFLE).Hint(uo.Hint != nil).
ArrayFilters(uo.ArrayFilters != nil).Ordered(true).ServerAPI(coll.client.serverAPI)
if uo.Let != nil {
let, err := transformBsoncoreDocument(coll.registry, uo.Let, true, "let")
if err != nil {
return nil, err
}
op = op.Let(let)
}
if uo.BypassDocumentValidation != nil && *uo.BypassDocumentValidation {
op = op.BypassDocumentValidation(*uo.BypassDocumentValidation)
@@ -693,11 +708,15 @@ func (coll *Collection) ReplaceOne(ctx context.Context, filter interface{},
updateOptions := make([]*options.UpdateOptions, 0, len(opts))
for _, opt := range opts {
if opt == nil {
continue
}
uOpts := options.Update()
uOpts.BypassDocumentValidation = opt.BypassDocumentValidation
uOpts.Collation = opt.Collation
uOpts.Upsert = opt.Upsert
uOpts.Hint = opt.Hint
uOpts.Let = opt.Let
updateOptions = append(updateOptions, uOpts)
}
@@ -736,8 +755,7 @@ func (coll *Collection) Aggregate(ctx context.Context, pipeline interface{},
}
// aggreate is the helper method for Aggregate
func aggregate(a aggregateParams) (*Cursor, error) {
func aggregate(a aggregateParams) (cur *Cursor, err error) {
if a.ctx == nil {
a.ctx = context.Background()
}
@@ -748,6 +766,12 @@ func aggregate(a aggregateParams) (*Cursor, error) {
}
sess := sessionFromContext(a.ctx)
// Always close any created implicit sessions if aggregate returns an error.
defer func() {
if err != nil && sess != nil {
closeImplicitSession(sess)
}
}()
if sess == nil && a.client.sessionPool != nil {
sess, err = session.NewClientSession(a.client.sessionPool, a.client.id, session.Implicit)
if err != nil {
@@ -821,7 +845,6 @@ func aggregate(a aggregateParams) (*Cursor, error) {
if ao.Hint != nil {
hintVal, err := transformValue(a.registry, ao.Hint, false, "hint")
if err != nil {
closeImplicitSession(sess)
return nil, err
}
op.Hint(hintVal)
@@ -829,11 +852,24 @@ func aggregate(a aggregateParams) (*Cursor, error) {
if ao.Let != nil {
let, err := transformBsoncoreDocument(a.registry, ao.Let, true, "let")
if err != nil {
closeImplicitSession(sess)
return nil, err
}
op.Let(let)
}
if ao.Custom != nil {
// Marshal all custom options before passing to the aggregate operation. Return
// any errors from Marshaling.
customOptions := make(map[string]bsoncore.Value)
for optionName, optionValue := range ao.Custom {
bsonType, bsonData, err := bson.MarshalValueWithRegistry(a.registry, optionValue)
if err != nil {
return nil, err
}
optionValueBSON := bsoncore.Value{Type: bsonType, Data: bsonData}
customOptions[optionName] = optionValueBSON
}
op.CustomOptions(customOptions)
}
retry := driver.RetryNone
if a.retryRead && !hasOutputStage {
@@ -843,7 +879,6 @@ func aggregate(a aggregateParams) (*Cursor, error) {
err = op.Execute(a.ctx)
if err != nil {
closeImplicitSession(sess)
if wce, ok := err.(driver.WriteCommandError); ok && wce.WriteConcernError != nil {
return nil, *convertDriverWriteConcernError(wce.WriteConcernError)
}
@@ -852,7 +887,6 @@ func aggregate(a aggregateParams) (*Cursor, error) {
bc, err := op.Result(cursorOpts)
if err != nil {
closeImplicitSession(sess)
return nil, replaceErrors(err)
}
cursor, err := newCursorWithSession(bc, a.registry, sess)
@@ -1100,7 +1134,7 @@ func (coll *Collection) Distinct(ctx context.Context, fieldName string, filter i
//
// For more information about the command, see https://docs.mongodb.com/manual/reference/command/find/.
func (coll *Collection) Find(ctx context.Context, filter interface{},
opts ...*options.FindOptions) (*Cursor, error) {
opts ...*options.FindOptions) (cur *Cursor, err error) {
if ctx == nil {
ctx = context.Background()
@@ -1112,6 +1146,12 @@ func (coll *Collection) Find(ctx context.Context, filter interface{},
}
sess := sessionFromContext(ctx)
// Always close any created implicit sessions if Find returns an error.
defer func() {
if err != nil && sess != nil {
closeImplicitSession(sess)
}
}()
if sess == nil && coll.client.sessionPool != nil {
var err error
sess, err = session.NewClientSession(coll.client.sessionPool, coll.client.id, session.Implicit)
@@ -1122,7 +1162,6 @@ func (coll *Collection) Find(ctx context.Context, filter interface{},
err = coll.client.validSession(sess)
if err != nil {
closeImplicitSession(sess)
return nil, err
}
@@ -1169,11 +1208,17 @@ func (coll *Collection) Find(ctx context.Context, filter interface{},
if fo.Hint != nil {
hint, err := transformValue(coll.registry, fo.Hint, false, "hint")
if err != nil {
closeImplicitSession(sess)
return nil, err
}
op.Hint(hint)
}
if fo.Let != nil {
let, err := transformBsoncoreDocument(coll.registry, fo.Let, true, "let")
if err != nil {
return nil, err
}
op.Let(let)
}
if fo.Limit != nil {
limit := *fo.Limit
if limit < 0 {
@@ -1186,7 +1231,6 @@ func (coll *Collection) Find(ctx context.Context, filter interface{},
if fo.Max != nil {
max, err := transformBsoncoreDocument(coll.registry, fo.Max, true, "max")
if err != nil {
closeImplicitSession(sess)
return nil, err
}
op.Max(max)
@@ -1200,7 +1244,6 @@ func (coll *Collection) Find(ctx context.Context, filter interface{},
if fo.Min != nil {
min, err := transformBsoncoreDocument(coll.registry, fo.Min, true, "min")
if err != nil {
closeImplicitSession(sess)
return nil, err
}
op.Min(min)
@@ -1214,7 +1257,6 @@ func (coll *Collection) Find(ctx context.Context, filter interface{},
if fo.Projection != nil {
proj, err := transformBsoncoreDocument(coll.registry, fo.Projection, true, "projection")
if err != nil {
closeImplicitSession(sess)
return nil, err
}
op.Projection(proj)
@@ -1234,7 +1276,6 @@ func (coll *Collection) Find(ctx context.Context, filter interface{},
if fo.Sort != nil {
sort, err := transformBsoncoreDocument(coll.registry, fo.Sort, false, "sort")
if err != nil {
closeImplicitSession(sess)
return nil, err
}
op.Sort(sort)
@@ -1246,13 +1287,11 @@ func (coll *Collection) Find(ctx context.Context, filter interface{},
op = op.Retry(retry)
if err = op.Execute(ctx); err != nil {
closeImplicitSession(sess)
return nil, replaceErrors(err)
}
bc, err := op.Result(cursorOpts)
if err != nil {
closeImplicitSession(sess)
return nil, replaceErrors(err)
}
return newCursorWithSession(bc, coll.registry, sess)
@@ -1276,6 +1315,9 @@ func (coll *Collection) FindOne(ctx context.Context, filter interface{},
findOpts := make([]*options.FindOptions, 0, len(opts))
for _, opt := range opts {
if opt == nil {
continue
}
findOpts = append(findOpts, &options.FindOptions{
AllowPartialResults: opt.AllowPartialResults,
BatchSize: opt.BatchSize,
@@ -1406,6 +1448,13 @@ func (coll *Collection) FindOneAndDelete(ctx context.Context, filter interface{}
}
op = op.Hint(hint)
}
if fod.Let != nil {
let, err := transformBsoncoreDocument(coll.registry, fod.Let, true, "let")
if err != nil {
return &SingleResult{err: err}
}
op = op.Let(let)
}
return coll.findAndModify(ctx, op)
}
@@ -1478,6 +1527,13 @@ func (coll *Collection) FindOneAndReplace(ctx context.Context, filter interface{
}
op = op.Hint(hint)
}
if fo.Let != nil {
let, err := transformBsoncoreDocument(coll.registry, fo.Let, true, "let")
if err != nil {
return &SingleResult{err: err}
}
op = op.Let(let)
}
return coll.findAndModify(ctx, op)
}
@@ -1561,6 +1617,13 @@ func (coll *Collection) FindOneAndUpdate(ctx context.Context, filter interface{}
}
op = op.Hint(hint)
}
if fo.Let != nil {
let, err := transformBsoncoreDocument(coll.registry, fo.Let, true, "let")
if err != nil {
return &SingleResult{err: err}
}
op = op.Let(let)
}
return coll.findAndModify(ctx, op)
}
+42
View File
@@ -15,6 +15,7 @@ import (
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/x/bsonx"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
@@ -67,6 +68,47 @@ func newEmptyCursor() *Cursor {
return &Cursor{bc: driver.NewEmptyBatchCursor()}
}
// NewCursorFromDocuments creates a new Cursor pre-loaded with the provided documents, error and registry. If no registry is provided,
// bson.DefaultRegistry will be used.
//
// The documents parameter must be a slice of documents. The slice may be nil or empty, but all elements must be non-nil.
func NewCursorFromDocuments(documents []interface{}, err error, registry *bsoncodec.Registry) (*Cursor, error) {
if registry == nil {
registry = bson.DefaultRegistry
}
// Convert documents slice to a sequence-style byte array.
var docsBytes []byte
for _, doc := range documents {
switch t := doc.(type) {
case nil:
return nil, ErrNilDocument
case bsonx.Doc:
doc = t.Copy()
case []byte:
// Slight optimization so we'll just use MarshalBSON and not go through the codec machinery.
doc = bson.Raw(t)
}
var marshalErr error
docsBytes, marshalErr = bson.MarshalAppendWithRegistry(registry, docsBytes, doc)
if marshalErr != nil {
return nil, marshalErr
}
}
c := &Cursor{
bc: driver.NewBatchCursorFromDocuments(docsBytes),
registry: registry,
err: err,
}
// Initialize batch and batchLength here. The underlying batch cursor will be preloaded with the
// provided contents, and thus already has a batch before calls to Next/TryNext.
c.batch = c.bc.Batch()
c.batchLength = c.bc.Batch().DocumentCount()
return c, nil
}
// ID returns the ID of this cursor, or 0 if the cursor has been closed or exhausted.
func (c *Cursor) ID() int64 { return c.bc.ID() }
+12
View File
@@ -303,6 +303,9 @@ func (db *Database) Drop(ctx context.Context) error {
// documentation).
//
// For more information about the command, see https://docs.mongodb.com/manual/reference/command/listCollections/.
//
// BUG(benjirewis): ListCollectionSpecifications prevents listing more than 100 collections per database when running
// against MongoDB version 2.6.
func (db *Database) ListCollectionSpecifications(ctx context.Context, filter interface{},
opts ...*options.ListCollectionsOptions) ([]*CollectionSpecification, error) {
@@ -337,6 +340,9 @@ func (db *Database) ListCollectionSpecifications(ctx context.Context, filter int
// documentation).
//
// For more information about the command, see https://docs.mongodb.com/manual/reference/command/listCollections/.
//
// BUG(benjirewis): ListCollections prevents listing more than 100 collections per database when running against
// MongoDB version 2.6.
func (db *Database) ListCollections(ctx context.Context, filter interface{}, opts ...*options.ListCollectionsOptions) (*Cursor, error) {
if ctx == nil {
ctx = context.Background()
@@ -382,6 +388,9 @@ func (db *Database) ListCollections(ctx context.Context, filter interface{}, opt
cursorOpts.BatchSize = *lco.BatchSize
op = op.BatchSize(*lco.BatchSize)
}
if lco.AuthorizedCollections != nil {
op = op.AuthorizedCollections(*lco.AuthorizedCollections)
}
retry := driver.RetryNone
if db.client.retryReads {
@@ -415,6 +424,9 @@ func (db *Database) ListCollections(ctx context.Context, filter interface{}, opt
// documentation).
//
// For more information about the command, see https://docs.mongodb.com/manual/reference/command/listCollections/.
//
// BUG(benjirewis): ListCollectionNames prevents listing more than 100 collections per database when running against
// MongoDB version 2.6.
func (db *Database) ListCollectionNames(ctx context.Context, filter interface{}, opts ...*options.ListCollectionsOptions) ([]string, error) {
opts = append(opts, options.ListCollections().SetNameOnly(true))
@@ -143,7 +143,7 @@ func readPrefSelector(rp *readpref.ReadPref, isOutputAggregate bool) ServerSelec
return ServerSelectorFunc(func(t Topology, candidates []Server) ([]Server, error) {
if t.Kind == LoadBalanced {
// In LoadBalanced mode, there should only be one server in the topology and it must be selected. We check
// this before checking MaxStaleness support becuase there's no monitoring in this mode, so the candidate
// this before checking MaxStaleness support because there's no monitoring in this mode, so the candidate
// server wouldn't have a wire version set, which would result in an error.
return candidates, nil
}
+38
View File
@@ -56,6 +56,7 @@ func replaceErrors(err error) error {
Labels: de.Labels,
Name: de.Name,
Wrapped: de.Wrapped,
Raw: bson.Raw(de.Raw),
}
}
if qe, ok := err.(driver.QueryFailureError); ok {
@@ -63,6 +64,7 @@ func replaceErrors(err error) error {
ce := CommandError{
Name: qe.Message,
Wrapped: qe.Wrapped,
Raw: bson.Raw(qe.Response),
}
dollarErr, err := qe.Response.LookupErr("$err")
@@ -207,6 +209,7 @@ type ServerError interface {
}
var _ ServerError = CommandError{}
var _ ServerError = WriteError{}
var _ ServerError = WriteException{}
var _ ServerError = BulkWriteException{}
@@ -217,6 +220,7 @@ type CommandError struct {
Labels []string // Categories to which the error belongs
Name string // A human-readable name corresponding to the error code
Wrapped error // The underlying error, if one exists.
Raw bson.Raw // The original server response containing the error.
}
// Error implements the error interface.
@@ -276,6 +280,9 @@ type WriteError struct {
Code int
Message string
Details bson.Raw
// The original write error from the server response.
Raw bson.Raw
}
func (we WriteError) Error() string {
@@ -286,6 +293,30 @@ func (we WriteError) Error() string {
return msg
}
// HasErrorCode returns true if the error has the specified code.
func (we WriteError) HasErrorCode(code int) bool {
return we.Code == code
}
// HasErrorLabel returns true if the error contains the specified label. WriteErrors do not contain labels,
// so we always return false.
func (we WriteError) HasErrorLabel(label string) bool {
return false
}
// HasErrorMessage returns true if the error contains the specified message.
func (we WriteError) HasErrorMessage(message string) bool {
return strings.Contains(we.Message, message)
}
// HasErrorCodeWithMessage returns true if the error has the specified code and Message contains the specified message.
func (we WriteError) HasErrorCodeWithMessage(code int, message string) bool {
return we.Code == code && strings.Contains(we.Message, message)
}
// serverError implements the ServerError interface.
func (we WriteError) serverError() {}
// WriteErrors is a group of write errors that occurred during execution of a write operation.
type WriteErrors []WriteError
@@ -307,6 +338,7 @@ func writeErrorsFromDriverWriteErrors(errs driver.WriteErrors) WriteErrors {
Code: int(err.Code),
Message: err.Message,
Details: bson.Raw(err.Details),
Raw: bson.Raw(err.Raw),
})
}
return wes
@@ -319,6 +351,7 @@ type WriteConcernError struct {
Code int
Message string
Details bson.Raw
Raw bson.Raw // The original write concern error from the server response.
}
// Error implements the error interface.
@@ -340,6 +373,9 @@ type WriteException struct {
// The categories to which the exception belongs.
Labels []string
// The original server response containing the error.
Raw bson.Raw
}
// Error implements the error interface.
@@ -426,6 +462,7 @@ func convertDriverWriteConcernError(wce *driver.WriteConcernError) *WriteConcern
Code: int(wce.Code),
Message: wce.Message,
Details: bson.Raw(wce.Details),
Raw: bson.Raw(wce.Raw),
}
}
@@ -559,6 +596,7 @@ func processWriteError(err error) (returnResult, error) {
WriteConcernError: convertDriverWriteConcernError(tt.WriteConcernError),
WriteErrors: writeErrorsFromDriverWriteErrors(tt.WriteErrors),
Labels: tt.Labels,
Raw: bson.Raw(tt.Raw),
}
default:
return rrNone, replaceErrors(err)
+2 -2
View File
@@ -196,7 +196,7 @@ func (b *Bucket) OpenDownloadStream(fileID interface{}) (*DownloadStream, error)
}
// DownloadToStream downloads the file with the specified fileID and writes it to the provided io.Writer.
// Returns the number of bytes written to the steam and an error, or nil if there was no error.
// Returns the number of bytes written to the stream and an error, or nil if there was no error.
//
// If this download requires a custom read deadline to be set on the bucket, it cannot be done concurrently with other
// read operations operations on this bucket that also require a custom deadline.
@@ -554,7 +554,7 @@ func (b *Bucket) createIndexes(ctx context.Context) error {
_, err = docRes.DecodeBytes()
if err != mongo.ErrNoDocuments {
// nil, or error that occured during the FindOne operation
// nil, or error that occurred during the FindOne operation
return err
}
+1 -1
View File
@@ -175,7 +175,7 @@ func ensureDollarKey(doc bsoncore.Document) error {
func ensureNoDollarKey(doc bsoncore.Document) error {
if elem, err := doc.IndexErr(0); err == nil && strings.HasPrefix(elem.Key(), "$") {
return errors.New("replacement document cannot contains keys beginning with '$")
return errors.New("replacement document cannot contain keys beginning with '$'")
}
return nil
@@ -6,7 +6,11 @@
package options
import "time"
import (
"time"
"go.mongodb.org/mongo-driver/bson"
)
// AggregateOptions represents options that can be used to configure an Aggregate operation.
type AggregateOptions struct {
@@ -50,6 +54,11 @@ type AggregateOptions struct {
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
// Custom options to be added to aggregate expression. Key-value pairs of the BSON map should correlate with desired
// option names and values. Values must be Marshalable. Custom options may conflict with non-custom options, and custom
// options bypass client-side validation. Prefer using non-custom options where possible.
Custom bson.M
}
// Aggregate creates a new AggregateOptions instance.
@@ -111,6 +120,15 @@ func (ao *AggregateOptions) SetLet(let interface{}) *AggregateOptions {
return ao
}
// SetCustom sets the value for the Custom field. Key-value pairs of the BSON map should correlate
// with desired option names and values. Values must be Marshalable. Custom options may conflict
// with non-custom options, and custom options bypass client-side validation. Prefer using non-custom
// options where possible.
func (ao *AggregateOptions) SetCustom(c bson.M) *AggregateOptions {
ao.Custom = c
return ao
}
// MergeAggregateOptions combines the given AggregateOptions instances into a single AggregateOptions in a last-one-wins
// fashion.
func MergeAggregateOptions(opts ...*AggregateOptions) *AggregateOptions {
@@ -146,6 +164,9 @@ func MergeAggregateOptions(opts ...*AggregateOptions) *AggregateOptions {
if ao.Let != nil {
aggOpts.Let = ao.Let
}
if ao.Custom != nil {
aggOpts.Custom = ao.Custom
}
}
return aggOpts
@@ -19,6 +19,12 @@ type BulkWriteOptions struct {
// If true, no writes will be executed after one fails. The default value is true.
Ordered *bool
// Specifies parameters for all update and delete commands in the BulkWrite. This option is only valid for MongoDB
// versions >= 5.0. Older servers will report an error for using this option. This must be a document mapping
// parameter names to values. Values must be constant or closed expressions that do not reference document fields.
// Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
}
// BulkWrite creates a new *BulkWriteOptions instance.
@@ -40,6 +46,15 @@ func (b *BulkWriteOptions) SetBypassDocumentValidation(bypass bool) *BulkWriteOp
return b
}
// SetLet sets the value for the Let field. Let specifies parameters for all update and delete commands in the BulkWrite.
// This option is only valid for MongoDB versions >= 5.0. Older servers will report an error for using this option.
// This must be a document mapping parameter names to values. Values must be constant or closed expressions that do not
// reference document fields. Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var").
func (b *BulkWriteOptions) SetLet(let interface{}) *BulkWriteOptions {
b.Let = &let
return b
}
// MergeBulkWriteOptions combines the given BulkWriteOptions instances into a single BulkWriteOptions in a last-one-wins
// fashion.
func MergeBulkWriteOptions(opts ...*BulkWriteOptions) *BulkWriteOptions {
@@ -54,6 +69,9 @@ func MergeBulkWriteOptions(opts ...*BulkWriteOptions) *BulkWriteOptions {
if opt.BypassDocumentValidation != nil {
b.BypassDocumentValidation = opt.BypassDocumentValidation
}
if opt.Let != nil {
b.Let = opt.Let
}
}
return b
@@ -9,6 +9,7 @@ package options
import (
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
@@ -46,6 +47,16 @@ type ChangeStreamOptions struct {
// corresponding to an oplog entry immediately after the specified token will be returned. If this is specified,
// ResumeAfter and StartAtOperationTime must not be set. This option is only valid for MongoDB versions >= 4.1.1.
StartAfter interface{}
// Custom options to be added to the initial aggregate for the change stream. Key-value pairs of the BSON map should
// correlate with desired option names and values. Values must be Marshalable. Custom options may conflict with
// non-custom options, and custom options bypass client-side validation. Prefer using non-custom options where possible.
Custom bson.M
// Custom options to be added to the $changeStream stage in the initial aggregate. Key-value pairs of the BSON map should
// correlate with desired option names and values. Values must be Marshalable. Custom pipeline options bypass client-side
// validation. Prefer using non-custom options where possible.
CustomPipeline bson.M
}
// ChangeStream creates a new ChangeStreamOptions instance.
@@ -97,6 +108,23 @@ func (cso *ChangeStreamOptions) SetStartAfter(sa interface{}) *ChangeStreamOptio
return cso
}
// SetCustom sets the value for the Custom field. Key-value pairs of the BSON map should correlate
// with desired option names and values. Values must be Marshalable. Custom options may conflict
// with non-custom options, and custom options bypass client-side validation. Prefer using non-custom
// options where possible.
func (cso *ChangeStreamOptions) SetCustom(c bson.M) *ChangeStreamOptions {
cso.Custom = c
return cso
}
// SetCustomPipeline sets the value for the CustomPipeline field. Key-value pairs of the BSON map
// should correlate with desired option names and values. Values must be Marshalable. Custom pipeline
// options bypass client-side validation. Prefer using non-custom options where possible.
func (cso *ChangeStreamOptions) SetCustomPipeline(cp bson.M) *ChangeStreamOptions {
cso.CustomPipeline = cp
return cso
}
// MergeChangeStreamOptions combines the given ChangeStreamOptions instances into a single ChangeStreamOptions in a
// last-one-wins fashion.
func MergeChangeStreamOptions(opts ...*ChangeStreamOptions) *ChangeStreamOptions {
@@ -126,6 +154,12 @@ func MergeChangeStreamOptions(opts ...*ChangeStreamOptions) *ChangeStreamOptions
if cso.StartAfter != nil {
csOpts.StartAfter = cso.StartAfter
}
if cso.Custom != nil {
csOpts.Custom = cso.Custom
}
if cso.CustomPipeline != nil {
csOpts.CustomPipeline = cso.CustomPipeline
}
}
return csOpts
+1 -1
View File
@@ -574,7 +574,7 @@ func (c *ClientOptions) SetMaxConnIdleTime(d time.Duration) *ClientOptions {
// SetMaxPoolSize specifies that maximum number of connections allowed in the driver's connection pool to each server.
// Requests to a server will block if this maximum is reached. This can also be set through the "maxPoolSize" URI option
// (e.g. "maxPoolSize=100"). The default is 100. If this is 0, it will be set to math.MaxInt64.
// (e.g. "maxPoolSize=100"). If this is 0, maximum connection pool size is not limited. The default is 100.
func (c *ClientOptions) SetMaxPoolSize(u uint64) *ClientOptions {
c.MaxPoolSize = &u
return c
@@ -20,6 +20,12 @@ type DeleteOptions struct {
// operation. The driver will return an error if the hint parameter is a multi-key map. The default value is nil,
// which means that no hint will be sent.
Hint interface{}
// Specifies parameters for the delete expression. This option is only valid for MongoDB versions >= 5.0. Older
// servers will report an error for using this option. This must be a document mapping parameter names to values.
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
}
// Delete creates a new DeleteOptions instance.
@@ -39,6 +45,12 @@ func (do *DeleteOptions) SetHint(hint interface{}) *DeleteOptions {
return do
}
// SetLet sets the value for the Let field.
func (do *DeleteOptions) SetLet(let interface{}) *DeleteOptions {
do.Let = let
return do
}
// MergeDeleteOptions combines the given DeleteOptions instances into a single DeleteOptions in a last-one-wins fashion.
func MergeDeleteOptions(opts ...*DeleteOptions) *DeleteOptions {
dOpts := Delete()
@@ -52,6 +64,9 @@ func MergeDeleteOptions(opts ...*DeleteOptions) *DeleteOptions {
if do.Hint != nil {
dOpts.Hint = do.Hint
}
if do.Let != nil {
dOpts.Let = do.Let
}
}
return dOpts
@@ -99,6 +99,12 @@ type FindOptions struct {
// A document specifying the order in which documents should be returned. The driver will return an error if the
// sort parameter is a multi-key map.
Sort interface{}
// Specifies parameters for the find expression. This option is only valid for MongoDB versions >= 5.0. Older
// servers will report an error for using this option. This must be a document mapping parameter names to values.
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
}
// Find creates a new FindOptions instance.
@@ -148,6 +154,12 @@ func (f *FindOptions) SetHint(hint interface{}) *FindOptions {
return f
}
// SetLet sets the value for the Let field.
func (f *FindOptions) SetLet(let interface{}) *FindOptions {
f.Let = let
return f
}
// SetLimit sets the value for the Limit field.
func (f *FindOptions) SetLimit(i int64) *FindOptions {
f.Limit = &i
@@ -258,6 +270,9 @@ func MergeFindOptions(opts ...*FindOptions) *FindOptions {
if opt.Hint != nil {
fo.Hint = opt.Hint
}
if opt.Let != nil {
fo.Let = opt.Let
}
if opt.Limit != nil {
fo.Limit = opt.Limit
}
@@ -624,6 +639,12 @@ type FindOneAndReplaceOptions struct {
// will return an error if the hint parameter is a multi-key map. The default value is nil, which means that no hint
// will be sent.
Hint interface{}
// Specifies parameters for the find one and replace expression. This option is only valid for MongoDB versions >= 5.0. Older
// servers will report an error for using this option. This must be a document mapping parameter names to values.
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
}
// FindOneAndReplace creates a new FindOneAndReplaceOptions instance.
@@ -679,6 +700,12 @@ func (f *FindOneAndReplaceOptions) SetHint(hint interface{}) *FindOneAndReplaceO
return f
}
// SetLet sets the value for the Let field.
func (f *FindOneAndReplaceOptions) SetLet(let interface{}) *FindOneAndReplaceOptions {
f.Let = let
return f
}
// MergeFindOneAndReplaceOptions combines the given FindOneAndReplaceOptions instances into a single
// FindOneAndReplaceOptions in a last-one-wins fashion.
func MergeFindOneAndReplaceOptions(opts ...*FindOneAndReplaceOptions) *FindOneAndReplaceOptions {
@@ -711,6 +738,9 @@ func MergeFindOneAndReplaceOptions(opts ...*FindOneAndReplaceOptions) *FindOneAn
if opt.Hint != nil {
fo.Hint = opt.Hint
}
if opt.Let != nil {
fo.Let = opt.Let
}
}
return fo
@@ -762,6 +792,12 @@ type FindOneAndUpdateOptions struct {
// will return an error if the hint parameter is a multi-key map. The default value is nil, which means that no hint
// will be sent.
Hint interface{}
// Specifies parameters for the find one and update expression. This option is only valid for MongoDB versions >= 5.0. Older
// servers will report an error for using this option. This must be a document mapping parameter names to values.
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
}
// FindOneAndUpdate creates a new FindOneAndUpdateOptions instance.
@@ -823,6 +859,12 @@ func (f *FindOneAndUpdateOptions) SetHint(hint interface{}) *FindOneAndUpdateOpt
return f
}
// SetLet sets the value for the Let field.
func (f *FindOneAndUpdateOptions) SetLet(let interface{}) *FindOneAndUpdateOptions {
f.Let = let
return f
}
// MergeFindOneAndUpdateOptions combines the given FindOneAndUpdateOptions instances into a single
// FindOneAndUpdateOptions in a last-one-wins fashion.
func MergeFindOneAndUpdateOptions(opts ...*FindOneAndUpdateOptions) *FindOneAndUpdateOptions {
@@ -858,6 +900,9 @@ func MergeFindOneAndUpdateOptions(opts ...*FindOneAndUpdateOptions) *FindOneAndU
if opt.Hint != nil {
fo.Hint = opt.Hint
}
if opt.Let != nil {
fo.Let = opt.Let
}
}
return fo
@@ -890,6 +935,12 @@ type FindOneAndDeleteOptions struct {
// will return an error if the hint parameter is a multi-key map. The default value is nil, which means that no hint
// will be sent.
Hint interface{}
// Specifies parameters for the find one and delete expression. This option is only valid for MongoDB versions >= 5.0. Older
// servers will report an error for using this option. This must be a document mapping parameter names to values.
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
}
// FindOneAndDelete creates a new FindOneAndDeleteOptions instance.
@@ -927,6 +978,12 @@ func (f *FindOneAndDeleteOptions) SetHint(hint interface{}) *FindOneAndDeleteOpt
return f
}
// SetLet sets the value for the Let field.
func (f *FindOneAndDeleteOptions) SetLet(let interface{}) *FindOneAndDeleteOptions {
f.Let = let
return f
}
// MergeFindOneAndDeleteOptions combines the given FindOneAndDeleteOptions instances into a single
// FindOneAndDeleteOptions in a last-one-wins fashion.
func MergeFindOneAndDeleteOptions(opts ...*FindOneAndDeleteOptions) *FindOneAndDeleteOptions {
@@ -950,6 +1007,9 @@ func MergeFindOneAndDeleteOptions(opts ...*FindOneAndDeleteOptions) *FindOneAndD
if opt.Hint != nil {
fo.Hint = opt.Hint
}
if opt.Let != nil {
fo.Let = opt.Let
}
}
return fo
@@ -389,6 +389,9 @@ func MergeIndexOptions(opts ...*IndexOptions) *IndexOptions {
i := Index()
for _, opt := range opts {
if opt == nil {
continue
}
if opt.Background != nil {
i.Background = opt.Background
}
@@ -13,6 +13,10 @@ type ListCollectionsOptions struct {
// The maximum number of documents to be included in each batch returned by the server.
BatchSize *int32
// If true, and NameOnly is true, limits the documents returned to only contain collections the user is authorized to use. The default value
// is false. This option is only valid for MongoDB server versions >= 4.0. Server versions < 4.0 ignore this option.
AuthorizedCollections *bool
}
// ListCollections creates a new ListCollectionsOptions instance.
@@ -32,6 +36,13 @@ func (lc *ListCollectionsOptions) SetBatchSize(size int32) *ListCollectionsOptio
return lc
}
// SetAuthorizedCollections sets the value for the AuthorizedCollections field. This option is only valid for MongoDB server versions >= 4.0. Server
// versions < 4.0 ignore this option.
func (lc *ListCollectionsOptions) SetAuthorizedCollections(b bool) *ListCollectionsOptions {
lc.AuthorizedCollections = &b
return lc
}
// MergeListCollectionsOptions combines the given ListCollectionsOptions instances into a single *ListCollectionsOptions
// in a last-one-wins fashion.
func MergeListCollectionsOptions(opts ...*ListCollectionsOptions) *ListCollectionsOptions {
@@ -46,6 +57,9 @@ func MergeListCollectionsOptions(opts ...*ListCollectionsOptions) *ListCollectio
if opt.BatchSize != nil {
lc.BatchSize = opt.BatchSize
}
if opt.AuthorizedCollections != nil {
lc.AuthorizedCollections = opt.AuthorizedCollections
}
}
return lc
@@ -40,7 +40,7 @@ func (ld *ListDatabasesOptions) SetAuthorizedDatabases(b bool) *ListDatabasesOpt
func MergeListDatabasesOptions(opts ...*ListDatabasesOptions) *ListDatabasesOptions {
ld := ListDatabases()
for _, opt := range opts {
if opts == nil {
if opt == nil {
continue
}
if opt.NameOnly != nil {
+1 -1
View File
@@ -22,7 +22,7 @@ type Collation struct {
Locale string `bson:",omitempty"` // The locale
CaseLevel bool `bson:",omitempty"` // The case level
CaseFirst string `bson:",omitempty"` // The case ordering
Strength int `bson:",omitempty"` // The number of comparision levels to use
Strength int `bson:",omitempty"` // The number of comparison levels to use
NumericOrdering bool `bson:",omitempty"` // Whether to order numbers based on numerical order and not collation order
Alternate string `bson:",omitempty"` // Whether spaces and punctuation are considered base characters
MaxVariable string `bson:",omitempty"` // Which characters are affected by alternate: "shifted"
@@ -30,6 +30,12 @@ type ReplaceOptions struct {
// If true, a new document will be inserted if the filter does not match any documents in the collection. The
// default value is false.
Upsert *bool
// Specifies parameters for the aggregate expression. This option is only valid for MongoDB versions >= 5.0. Older
// servers will report an error for using this option. This must be a document mapping parameter names to values.
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
}
// Replace creates a new ReplaceOptions instance.
@@ -61,6 +67,12 @@ func (ro *ReplaceOptions) SetUpsert(b bool) *ReplaceOptions {
return ro
}
// SetLet sets the value for the Let field.
func (ro *ReplaceOptions) SetLet(l interface{}) *ReplaceOptions {
ro.Let = l
return ro
}
// MergeReplaceOptions combines the given ReplaceOptions instances into a single ReplaceOptions in a last-one-wins
// fashion.
func MergeReplaceOptions(opts ...*ReplaceOptions) *ReplaceOptions {
@@ -81,6 +93,9 @@ func MergeReplaceOptions(opts ...*ReplaceOptions) *ReplaceOptions {
if ro.Upsert != nil {
rOpts.Upsert = ro.Upsert
}
if ro.Let != nil {
rOpts.Let = ro.Let
}
}
return rOpts
@@ -35,6 +35,12 @@ type UpdateOptions struct {
// If true, a new document will be inserted if the filter does not match any documents in the collection. The
// default value is false.
Upsert *bool
// Specifies parameters for the update expression. This option is only valid for MongoDB versions >= 5.0. Older
// servers will report an error for using this option. This must be a document mapping parameter names to values.
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
}
// Update creates a new UpdateOptions instance.
@@ -72,6 +78,12 @@ func (uo *UpdateOptions) SetUpsert(b bool) *UpdateOptions {
return uo
}
// SetLet sets the value for the Let field.
func (uo *UpdateOptions) SetLet(l interface{}) *UpdateOptions {
uo.Let = l
return uo
}
// MergeUpdateOptions combines the given UpdateOptions instances into a single UpdateOptions in a last-one-wins fashion.
func MergeUpdateOptions(opts ...*UpdateOptions) *UpdateOptions {
uOpts := Update()
@@ -94,6 +106,9 @@ func MergeUpdateOptions(opts ...*UpdateOptions) *UpdateOptions {
if uo.Upsert != nil {
uOpts.Upsert = uo.Upsert
}
if uo.Let != nil {
uOpts.Let = uo.Let
}
}
return uOpts
@@ -65,6 +65,9 @@ func New(mode Mode, opts ...Option) (*ReadPref, error) {
}
for _, opt := range opts {
if opt == nil {
continue
}
err := opt(rp)
if err != nil {
return nil, err
+5 -2
View File
@@ -100,13 +100,16 @@ func SessionFromContext(ctx context.Context) Session {
// resources are properly cleaned up, context deadlines and cancellations will not be respected during this call. For a
// usage example, see the Client.StartSession method documentation.
//
// ClusterTime, OperationTime, Client, and ID return the session's current operation time, the session's current cluster
// ClusterTime, OperationTime, Client, and ID return the session's current cluster time, the session's current operation
// time, the Client associated with the session, and the ID document associated with the session, respectively. The ID
// document for a session is in the form {"id": <BSON binary value>}.
//
// EndSession method should abort any existing transactions and close the session.
//
// AdvanceClusterTime and AdvanceOperationTime are for internal use only and must not be called.
// AdvanceClusterTime advances the cluster time for a session. This method will return an error if the session has ended.
//
// AdvanceOperationTime advances the operation time for a session. This method will return an error if the session has
// ended.
type Session interface {
// Functions to modify session state.
StartTransaction(...*options.TransactionOptions) error
+26
View File
@@ -28,6 +28,31 @@ type SingleResult struct {
reg *bsoncodec.Registry
}
// NewSingleResultFromDocument creates a SingleResult with the provided error, registry, and an underlying Cursor pre-loaded with
// the provided document, error and registry. If no registry is provided, bson.DefaultRegistry will be used. If an error distinct
// from the one provided occurs during creation of the SingleResult, that error will be stored on the returned SingleResult.
//
// The document parameter must be a non-nil document.
func NewSingleResultFromDocument(document interface{}, err error, registry *bsoncodec.Registry) *SingleResult {
if document == nil {
return &SingleResult{err: ErrNilDocument}
}
if registry == nil {
registry = bson.DefaultRegistry
}
cur, createErr := NewCursorFromDocuments([]interface{}{document}, err, registry)
if createErr != nil {
return &SingleResult{err: createErr}
}
return &SingleResult{
cur: cur,
err: err,
reg: registry,
}
}
// Decode will unmarshal the document represented by this SingleResult into v. If there was an error from the operation
// that created this SingleResult, that error will be returned. If the operation returned no documents, Decode will
// return ErrNoDocuments.
@@ -71,6 +96,7 @@ func (sr *SingleResult) setRdrContents() error {
return nil
case sr.cur != nil:
defer sr.cur.Close(context.TODO())
if !sr.cur.Next(context.TODO()) {
if err := sr.cur.Err(); err != nil {
return err
+1 -1
View File
@@ -7,4 +7,4 @@
package version // import "go.mongodb.org/mongo-driver/version"
// Driver is the current version of the driver.
var Driver = "v1.8.4"
var Driver = "v1.9.0"
@@ -45,7 +45,7 @@ func (db *DocumentBuilder) AppendInt32(key string, i32 int32) *DocumentBuilder {
return db
}
// AppendDocument will append a bson embeded document element using key
// AppendDocument will append a bson embedded document element using key
// and doc to DocumentBuilder.doc
func (db *DocumentBuilder) AppendDocument(key string, doc []byte) *DocumentBuilder {
db.doc = AppendDocumentElement(db.doc, key, doc)
+3 -3
View File
@@ -15,7 +15,7 @@
// enough bytes. This library attempts to do no validation, it will only return
// false if there are not enough bytes for an item to be read. For example, the
// ReadDocument function checks the length, if that length is larger than the
// number of bytes availble, it will return false, if there are enough bytes, it
// number of bytes available, it will return false, if there are enough bytes, it
// will return those bytes and true. It is the consumers responsibility to
// validate those bytes.
//
@@ -69,7 +69,7 @@ func AppendHeader(dst []byte, t bsontype.Type, key string) []byte {
// was read.
// ReadType will return the first byte of the provided []byte as a type. If
// there is no availble byte, false is returned.
// there is no available byte, false is returned.
func ReadType(src []byte) (bsontype.Type, []byte, bool) {
if len(src) < 1 {
return 0, src, false
@@ -231,7 +231,7 @@ func AppendDocumentEnd(dst []byte, index int32) ([]byte, error) {
// AppendDocument will append doc to dst and return the extended buffer.
func AppendDocument(dst []byte, doc []byte) []byte { return append(dst, doc...) }
// AppendDocumentElement will append a BSON embeded document element using key
// AppendDocumentElement will append a BSON embedded document element using key
// and doc to dst and return the extended buffer.
func AppendDocumentElement(dst []byte, key string, doc []byte) []byte {
return AppendDocument(AppendHeader(dst, bsontype.EmbeddedDocument, key), doc)
+51 -51
View File
@@ -223,7 +223,7 @@ func (r *reflectionFreeDCodec) decodeValue(dc bsoncodec.DecodeContext, vr bsonrw
func (r *reflectionFreeDCodec) encodeDocumentValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, v interface{}) error {
switch val := v.(type) {
case int:
return r.encodeInt(ec, vw, val)
return r.encodeInt(vw, val)
case int8:
return vw.WriteInt32(int32(val))
case int16:
@@ -292,69 +292,69 @@ func (r *reflectionFreeDCodec) encodeDocumentValue(ec bsoncodec.EncodeContext, v
case []primitive.D:
return r.encodeSliceD(ec, vw, val)
case []int:
return r.encodeSliceInt(ec, vw, val)
return r.encodeSliceInt(vw, val)
case []int8:
return r.encodeSliceInt8(ec, vw, val)
return r.encodeSliceInt8(vw, val)
case []int16:
return r.encodeSliceInt16(ec, vw, val)
return r.encodeSliceInt16(vw, val)
case []int32:
return r.encodeSliceInt32(ec, vw, val)
return r.encodeSliceInt32(vw, val)
case []int64:
return r.encodeSliceInt64(ec, vw, val)
case []uint:
return r.encodeSliceUint(ec, vw, val)
case []uint16:
return r.encodeSliceUint16(ec, vw, val)
return r.encodeSliceUint16(vw, val)
case []uint32:
return r.encodeSliceUint32(ec, vw, val)
case []uint64:
return r.encodeSliceUint64(ec, vw, val)
case [][]byte:
return r.encodeSliceByteSlice(ec, vw, val)
return r.encodeSliceByteSlice(vw, val)
case []primitive.Binary:
return r.encodeSliceBinary(ec, vw, val)
return r.encodeSliceBinary(vw, val)
case []bool:
return r.encodeSliceBoolean(ec, vw, val)
return r.encodeSliceBoolean(vw, val)
case []primitive.CodeWithScope:
return r.encodeSliceCWS(ec, vw, val)
case []primitive.DBPointer:
return r.encodeSliceDBPointer(ec, vw, val)
return r.encodeSliceDBPointer(vw, val)
case []primitive.DateTime:
return r.encodeSliceDateTime(ec, vw, val)
return r.encodeSliceDateTime(vw, val)
case []time.Time:
return r.encodeSliceTimeTime(ec, vw, val)
return r.encodeSliceTimeTime(vw, val)
case []primitive.Decimal128:
return r.encodeSliceDecimal128(ec, vw, val)
return r.encodeSliceDecimal128(vw, val)
case []float32:
return r.encodeSliceFloat32(ec, vw, val)
return r.encodeSliceFloat32(vw, val)
case []float64:
return r.encodeSliceFloat64(ec, vw, val)
return r.encodeSliceFloat64(vw, val)
case []primitive.JavaScript:
return r.encodeSliceJavaScript(ec, vw, val)
return r.encodeSliceJavaScript(vw, val)
case []primitive.MinKey:
return r.encodeSliceMinKey(ec, vw, val)
return r.encodeSliceMinKey(vw, val)
case []primitive.MaxKey:
return r.encodeSliceMaxKey(ec, vw, val)
return r.encodeSliceMaxKey(vw, val)
case []primitive.Null:
return r.encodeSliceNull(ec, vw, val)
return r.encodeSliceNull(vw, val)
case []primitive.ObjectID:
return r.encodeSliceObjectID(ec, vw, val)
return r.encodeSliceObjectID(vw, val)
case []primitive.Regex:
return r.encodeSliceRegex(ec, vw, val)
return r.encodeSliceRegex(vw, val)
case []string:
return r.encodeSliceString(ec, vw, val)
return r.encodeSliceString(vw, val)
case []primitive.Symbol:
return r.encodeSliceSymbol(ec, vw, val)
return r.encodeSliceSymbol(vw, val)
case []primitive.Timestamp:
return r.encodeSliceTimestamp(ec, vw, val)
return r.encodeSliceTimestamp(vw, val)
case []primitive.Undefined:
return r.encodeSliceUndefined(ec, vw, val)
return r.encodeSliceUndefined(vw, val)
default:
return fmt.Errorf("value of type %T not supported", v)
}
}
func (r *reflectionFreeDCodec) encodeInt(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val int) error {
func (r *reflectionFreeDCodec) encodeInt(vw bsonrw.ValueWriter, val int) error {
if fitsIn32Bits(int64(val)) {
return vw.WriteInt32(int32(val))
}
@@ -399,7 +399,7 @@ func (r *reflectionFreeDCodec) encodeDocument(ec bsoncodec.EncodeContext, vw bso
return dw.WriteDocumentEnd()
}
func (r *reflectionFreeDCodec) encodeSliceByteSlice(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr [][]byte) error {
func (r *reflectionFreeDCodec) encodeSliceByteSlice(vw bsonrw.ValueWriter, arr [][]byte) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -419,7 +419,7 @@ func (r *reflectionFreeDCodec) encodeSliceByteSlice(ec bsoncodec.EncodeContext,
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceBinary(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.Binary) error {
func (r *reflectionFreeDCodec) encodeSliceBinary(vw bsonrw.ValueWriter, arr []primitive.Binary) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -439,7 +439,7 @@ func (r *reflectionFreeDCodec) encodeSliceBinary(ec bsoncodec.EncodeContext, vw
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceBoolean(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []bool) error {
func (r *reflectionFreeDCodec) encodeSliceBoolean(vw bsonrw.ValueWriter, arr []bool) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -479,7 +479,7 @@ func (r *reflectionFreeDCodec) encodeSliceCWS(ec bsoncodec.EncodeContext, vw bso
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceDBPointer(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.DBPointer) error {
func (r *reflectionFreeDCodec) encodeSliceDBPointer(vw bsonrw.ValueWriter, arr []primitive.DBPointer) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -499,7 +499,7 @@ func (r *reflectionFreeDCodec) encodeSliceDBPointer(ec bsoncodec.EncodeContext,
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceDateTime(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.DateTime) error {
func (r *reflectionFreeDCodec) encodeSliceDateTime(vw bsonrw.ValueWriter, arr []primitive.DateTime) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -519,7 +519,7 @@ func (r *reflectionFreeDCodec) encodeSliceDateTime(ec bsoncodec.EncodeContext, v
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceTimeTime(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []time.Time) error {
func (r *reflectionFreeDCodec) encodeSliceTimeTime(vw bsonrw.ValueWriter, arr []time.Time) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -540,7 +540,7 @@ func (r *reflectionFreeDCodec) encodeSliceTimeTime(ec bsoncodec.EncodeContext, v
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceDecimal128(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.Decimal128) error {
func (r *reflectionFreeDCodec) encodeSliceDecimal128(vw bsonrw.ValueWriter, arr []primitive.Decimal128) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -560,7 +560,7 @@ func (r *reflectionFreeDCodec) encodeSliceDecimal128(ec bsoncodec.EncodeContext,
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceFloat32(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []float32) error {
func (r *reflectionFreeDCodec) encodeSliceFloat32(vw bsonrw.ValueWriter, arr []float32) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -580,7 +580,7 @@ func (r *reflectionFreeDCodec) encodeSliceFloat32(ec bsoncodec.EncodeContext, vw
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceFloat64(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []float64) error {
func (r *reflectionFreeDCodec) encodeSliceFloat64(vw bsonrw.ValueWriter, arr []float64) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -600,7 +600,7 @@ func (r *reflectionFreeDCodec) encodeSliceFloat64(ec bsoncodec.EncodeContext, vw
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceJavaScript(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.JavaScript) error {
func (r *reflectionFreeDCodec) encodeSliceJavaScript(vw bsonrw.ValueWriter, arr []primitive.JavaScript) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -620,7 +620,7 @@ func (r *reflectionFreeDCodec) encodeSliceJavaScript(ec bsoncodec.EncodeContext,
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceMinKey(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.MinKey) error {
func (r *reflectionFreeDCodec) encodeSliceMinKey(vw bsonrw.ValueWriter, arr []primitive.MinKey) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -640,7 +640,7 @@ func (r *reflectionFreeDCodec) encodeSliceMinKey(ec bsoncodec.EncodeContext, vw
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceMaxKey(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.MaxKey) error {
func (r *reflectionFreeDCodec) encodeSliceMaxKey(vw bsonrw.ValueWriter, arr []primitive.MaxKey) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -660,7 +660,7 @@ func (r *reflectionFreeDCodec) encodeSliceMaxKey(ec bsoncodec.EncodeContext, vw
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceNull(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.Null) error {
func (r *reflectionFreeDCodec) encodeSliceNull(vw bsonrw.ValueWriter, arr []primitive.Null) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -680,7 +680,7 @@ func (r *reflectionFreeDCodec) encodeSliceNull(ec bsoncodec.EncodeContext, vw bs
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceObjectID(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.ObjectID) error {
func (r *reflectionFreeDCodec) encodeSliceObjectID(vw bsonrw.ValueWriter, arr []primitive.ObjectID) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -700,7 +700,7 @@ func (r *reflectionFreeDCodec) encodeSliceObjectID(ec bsoncodec.EncodeContext, v
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceRegex(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.Regex) error {
func (r *reflectionFreeDCodec) encodeSliceRegex(vw bsonrw.ValueWriter, arr []primitive.Regex) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -720,7 +720,7 @@ func (r *reflectionFreeDCodec) encodeSliceRegex(ec bsoncodec.EncodeContext, vw b
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceString(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []string) error {
func (r *reflectionFreeDCodec) encodeSliceString(vw bsonrw.ValueWriter, arr []string) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -740,7 +740,7 @@ func (r *reflectionFreeDCodec) encodeSliceString(ec bsoncodec.EncodeContext, vw
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceSymbol(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.Symbol) error {
func (r *reflectionFreeDCodec) encodeSliceSymbol(vw bsonrw.ValueWriter, arr []primitive.Symbol) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -760,7 +760,7 @@ func (r *reflectionFreeDCodec) encodeSliceSymbol(ec bsoncodec.EncodeContext, vw
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceTimestamp(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.Timestamp) error {
func (r *reflectionFreeDCodec) encodeSliceTimestamp(vw bsonrw.ValueWriter, arr []primitive.Timestamp) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -780,7 +780,7 @@ func (r *reflectionFreeDCodec) encodeSliceTimestamp(ec bsoncodec.EncodeContext,
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceUndefined(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []primitive.Undefined) error {
func (r *reflectionFreeDCodec) encodeSliceUndefined(vw bsonrw.ValueWriter, arr []primitive.Undefined) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -840,7 +840,7 @@ func (r *reflectionFreeDCodec) encodeSliceD(ec bsoncodec.EncodeContext, vw bsonr
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceInt(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []int) error {
func (r *reflectionFreeDCodec) encodeSliceInt(vw bsonrw.ValueWriter, arr []int) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -852,7 +852,7 @@ func (r *reflectionFreeDCodec) encodeSliceInt(ec bsoncodec.EncodeContext, vw bso
return err
}
if err := r.encodeInt(ec, arrayValWriter, val); err != nil {
if err := r.encodeInt(arrayValWriter, val); err != nil {
return err
}
}
@@ -860,7 +860,7 @@ func (r *reflectionFreeDCodec) encodeSliceInt(ec bsoncodec.EncodeContext, vw bso
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceInt8(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []int8) error {
func (r *reflectionFreeDCodec) encodeSliceInt8(vw bsonrw.ValueWriter, arr []int8) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -880,7 +880,7 @@ func (r *reflectionFreeDCodec) encodeSliceInt8(ec bsoncodec.EncodeContext, vw bs
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceInt16(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []int16) error {
func (r *reflectionFreeDCodec) encodeSliceInt16(vw bsonrw.ValueWriter, arr []int16) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -900,7 +900,7 @@ func (r *reflectionFreeDCodec) encodeSliceInt16(ec bsoncodec.EncodeContext, vw b
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceInt32(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []int32) error {
func (r *reflectionFreeDCodec) encodeSliceInt32(vw bsonrw.ValueWriter, arr []int32) error {
aw, err := vw.WriteArray()
if err != nil {
return err
@@ -960,7 +960,7 @@ func (r *reflectionFreeDCodec) encodeSliceUint(ec bsoncodec.EncodeContext, vw bs
return aw.WriteArrayEnd()
}
func (r *reflectionFreeDCodec) encodeSliceUint16(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, arr []uint16) error {
func (r *reflectionFreeDCodec) encodeSliceUint16(vw bsonrw.ValueWriter, arr []uint16) error {
aw, err := vw.WriteArray()
if err != nil {
return err
+1 -1
View File
@@ -10,7 +10,7 @@ import (
var DefaultRegistry = NewRegistryBuilder().Build()
// NewRegistryBuilder creates a new RegistryBuilder configured with the default encoders and
// deocders from the bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the
// decoders from the bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the
// PrimitiveCodecs type in this package.
func NewRegistryBuilder() *bsoncodec.RegistryBuilder {
rb := bsoncodec.NewRegistryBuilder()
@@ -76,7 +76,7 @@ func (ac *awsConversation) Step(challenge []byte) (response []byte, err error) {
switch ac.state {
case clientStarting:
ac.state = clientFirst
response, err = ac.firstMsg()
response = ac.firstMsg()
case clientFirst:
ac.state = clientFinal
response, err = ac.finalMsg(challenge)
@@ -270,7 +270,7 @@ func (ac *awsConversation) getCredentials() (*awsv4.StaticProvider, error) {
return creds, err
}
func (ac *awsConversation) firstMsg() ([]byte, error) {
func (ac *awsConversation) firstMsg() []byte {
// Values are cached for use in final message parameters
ac.nonce = make([]byte, 32)
_, _ = rand.Read(ac.nonce)
@@ -279,7 +279,7 @@ func (ac *awsConversation) firstMsg() ([]byte, error) {
msg = bsoncore.AppendInt32Element(msg, "p", 110)
msg = bsoncore.AppendBinaryElement(msg, "r", 0x00, ac.nonce)
msg, _ = bsoncore.AppendDocumentEnd(msg, idx)
return msg, nil
return msg
}
func (ac *awsConversation) finalMsg(s1 []byte) ([]byte, error) {
+3 -2
View File
@@ -4,8 +4,9 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//+build gssapi
//+build windows linux darwin
//go:build gssapi && (windows || linux || darwin)
// +build gssapi
// +build windows linux darwin
package auth
@@ -4,7 +4,8 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//+build !gssapi
//go:build !gssapi
// +build !gssapi
package auth
@@ -4,7 +4,8 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//+build gssapi,!windows,!linux,!darwin
//go:build gssapi && !windows && !linux && !darwin
// +build gssapi,!windows,!linux,!darwin
package auth
@@ -234,7 +234,7 @@ func (ctx *signingCtx) buildCredentialString() {
}
func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) {
var headers []string
headers := make([]string, 0, len(header))
headers = append(headers, "host")
for k, v := range header {
if !r.IsValid(k) {
@@ -4,8 +4,9 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//+build gssapi
//+build linux darwin
//go:build gssapi && (linux || darwin)
// +build gssapi
// +build linux darwin
package gssapi
@@ -4,7 +4,8 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//+build gssapi,windows
//go:build gssapi && windows
// +build gssapi,windows
package gssapi
@@ -184,6 +184,21 @@ func NewEmptyBatchCursor() *BatchCursor {
return &BatchCursor{currentBatch: new(bsoncore.DocumentSequence)}
}
// NewBatchCursorFromDocuments returns a batch cursor with current batch set to a sequence-style
// DocumentSequence containing the provided documents.
func NewBatchCursorFromDocuments(documents []byte) *BatchCursor {
return &BatchCursor{
currentBatch: &bsoncore.DocumentSequence{
Data: documents,
Style: bsoncore.SequenceStyle,
},
// BatchCursors created with this function have no associated ID nor server, so no getMore
// calls will be made.
id: 0,
server: nil,
}
}
// ID returns the cursor ID for this batch cursor.
func (bc *BatchCursor) ID() int64 {
return bc.id
@@ -24,7 +24,7 @@ import (
)
// random is a package-global pseudo-random number generator.
var random = randutil.NewLockedRand(rand.NewSource(time.Now().UnixNano()))
var random = randutil.NewLockedRand(rand.NewSource(randutil.CryptoSeed()))
// ParseAndValidate parses the provided URI into a ConnString object.
// It check that all values are valid.
+4 -4
View File
@@ -197,7 +197,7 @@ func (c *crypt) executeStateMachine(ctx context.Context, cryptCtx *mongocrypt.Co
case mongocrypt.NeedMongoKeys:
err = c.retrieveKeys(ctx, cryptCtx)
case mongocrypt.NeedKms:
err = c.decryptKeys(ctx, cryptCtx)
err = c.decryptKeys(cryptCtx)
case mongocrypt.Ready:
return cryptCtx.Finish()
default:
@@ -265,14 +265,14 @@ func (c *crypt) retrieveKeys(ctx context.Context, cryptCtx *mongocrypt.Context)
return cryptCtx.CompleteOperation()
}
func (c *crypt) decryptKeys(ctx context.Context, cryptCtx *mongocrypt.Context) error {
func (c *crypt) decryptKeys(cryptCtx *mongocrypt.Context) error {
for {
kmsCtx := cryptCtx.NextKmsContext()
if kmsCtx == nil {
break
}
if err := c.decryptKey(ctx, kmsCtx); err != nil {
if err := c.decryptKey(kmsCtx); err != nil {
return err
}
}
@@ -280,7 +280,7 @@ func (c *crypt) decryptKeys(ctx context.Context, cryptCtx *mongocrypt.Context) e
return cryptCtx.FinishKmsContexts()
}
func (c *crypt) decryptKey(ctx context.Context, kmsCtx *mongocrypt.KmsContext) error {
func (c *crypt) decryptKey(kmsCtx *mongocrypt.KmsContext) error {
host, err := kmsCtx.HostName()
if err != nil {
return err
+1 -1
View File
@@ -86,7 +86,7 @@ func (r *Resolver) fetchSeedlistFromSRV(host string, srvName string, stopOnErr b
trimmedHost := strings.TrimSuffix(host, ".")
var parsedHosts []string
parsedHosts := make([]string, 0, len(addresses))
for _, address := range addresses {
trimmedAddressTarget := strings.TrimSuffix(address.Target, ".")
err := validateSRVResult(trimmedAddressTarget, trimmedHost)
+5
View File
@@ -54,7 +54,12 @@ type Connection interface {
WriteWireMessage(context.Context, []byte) error
ReadWireMessage(ctx context.Context, dst []byte) ([]byte, error)
Description() description.Server
// Close closes any underlying connection and returns or frees any resources held by the
// connection. Close is idempotent and can be called multiple times, although subsequent calls
// to Close may return an error. A connection cannot be used after it is closed.
Close() error
ID() string
ServerConnectionID() *int32
Address() address.Address
+8
View File
@@ -82,6 +82,7 @@ type WriteCommandError struct {
WriteConcernError *WriteConcernError
WriteErrors WriteErrors
Labels []string
Raw bsoncore.Document
}
// UnsupportedStorageEngine returns whether or not the WriteCommandError comes from a retryable write being attempted
@@ -129,6 +130,7 @@ type WriteConcernError struct {
Details bsoncore.Document
Labels []string
TopologyVersion *description.TopologyVersion
Raw bsoncore.Document
}
func (wce WriteConcernError) Error() string {
@@ -189,6 +191,7 @@ type WriteError struct {
Code int64
Message string
Details bsoncore.Document
Raw bsoncore.Document
}
func (we WriteError) Error() string { return we.Message }
@@ -218,6 +221,7 @@ type Error struct {
Name string
Wrapped error
TopologyVersion *description.TopologyVersion
Raw bsoncore.Document
}
// UnsupportedStorageEngine returns whether e came as a result of an unsupported storage engine
@@ -417,6 +421,7 @@ func ExtractErrorFromServerResponse(doc bsoncore.Document) error {
we.Details = make([]byte, len(info))
copy(we.Details, info)
}
we.Raw = doc
wcError.WriteErrors = append(wcError.WriteErrors, we)
}
case "writeConcernError":
@@ -425,6 +430,7 @@ func ExtractErrorFromServerResponse(doc bsoncore.Document) error {
break
}
wcError.WriteConcernError = new(WriteConcernError)
wcError.WriteConcernError.Raw = doc
if code, exists := doc.Lookup("code").AsInt64OK(); exists {
wcError.WriteConcernError.Code = code
}
@@ -472,6 +478,7 @@ func ExtractErrorFromServerResponse(doc bsoncore.Document) error {
Name: codeName,
Labels: labels,
TopologyVersion: tv,
Raw: doc,
}
}
@@ -480,6 +487,7 @@ func ExtractErrorFromServerResponse(doc bsoncore.Document) error {
if wcError.WriteConcernError != nil {
wcError.WriteConcernError.TopologyVersion = tv
}
wcError.Raw = doc
return wcError
}
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build cse
// +build cse
package mongocrypt
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build cse
// +build cse
package mongocrypt
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build !cse
// +build !cse
package mongocrypt
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build cse
// +build cse
package mongocrypt
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build cse
// +build cse
package mongocrypt
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build !cse
// +build !cse
package mongocrypt
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build cse
// +build cse
package mongocrypt
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build !cse
// +build !cse
package mongocrypt
@@ -4,6 +4,7 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build !cse
// +build !cse
package mongocrypt
+1 -1
View File
@@ -261,7 +261,7 @@ func contactResponders(ctx context.Context, cfg config) (*ResponseDetails, error
//
// 2. If any other errors occurred, including the defaultRequestTimeout expiring, or the response has a
// non-200 status code, suppress the error because we want to ignore this responder and wait for a different
// one to responsd.
// one to respond.
httpResponse, err := http.DefaultClient.Do(request)
if err != nil {
urlErr, ok := err.(*url.Error)
+126 -71
View File
@@ -47,6 +47,11 @@ const (
readSnapshotMinWireVersion int32 = 13
)
// RetryablePoolError is a connection pool error that can be retried while executing an operation.
type RetryablePoolError interface {
Retryable() bool
}
// InvalidOperationError is returned from Validate and indicates that a required field is missing
// from an instance of Operation.
type InvalidOperationError struct{ MissingField string }
@@ -305,40 +310,8 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
}
}
srvr, conn, err := op.getServerAndConnection(ctx)
if err != nil {
return err
}
defer conn.Close()
desc := description.SelectedServer{Server: conn.Description(), Kind: op.Deployment.Kind()}
scratch = scratch[:0]
if desc.WireVersion == nil || desc.WireVersion.Max < 4 {
switch op.Legacy {
case LegacyFind:
return op.legacyFind(ctx, scratch, srvr, conn, desc)
case LegacyGetMore:
return op.legacyGetMore(ctx, scratch, srvr, conn, desc)
case LegacyKillCursors:
return op.legacyKillCursors(ctx, scratch, srvr, conn, desc)
}
}
if desc.WireVersion == nil || desc.WireVersion.Max < 3 {
switch op.Legacy {
case LegacyListCollections:
return op.legacyListCollections(ctx, scratch, srvr, conn, desc)
case LegacyListIndexes:
return op.legacyListIndexes(ctx, scratch, srvr, conn, desc)
}
}
var res bsoncore.Document
var operationErr WriteCommandError
var original error
var retries int
retryable := op.retryable(desc.Server)
if retryable && op.RetryMode != nil {
if op.RetryMode != nil {
switch op.Type {
case Write:
if op.Client == nil {
@@ -350,15 +323,6 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
case RetryContext:
retries = -1
}
op.Client.RetryWrite = false
if *op.RetryMode > RetryNone {
op.Client.RetryWrite = true
if !op.Client.Committing && !op.Client.Aborting {
op.Client.IncrementTxnNumber()
}
}
case Read:
switch *op.RetryMode {
case RetryOnce, RetryOncePerCommand:
@@ -368,10 +332,107 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
}
}
}
var srvr Server
var conn Connection
var res bsoncore.Document
var operationErr WriteCommandError
var prevErr error
batching := op.Batches.Valid()
retryEnabled := op.RetryMode != nil && op.RetryMode.Enabled()
retrySupported := false
first := true
currIndex := 0
// resetForRetry records the error that caused the retry, decrements retries, and resets the
// retry loop variables to request a new server and a new connection for the next attempt.
resetForRetry := func(err error) {
retries--
prevErr = err
// If we got a connection, close it immediately to release pool resources for
// subsequent retries.
if conn != nil {
conn.Close()
}
// Set the server and connection to nil to request a new server and connection.
srvr = nil
conn = nil
}
for {
// If the server or connection are nil, try to select a new server and get a new connection.
if srvr == nil || conn == nil {
srvr, conn, err = op.getServerAndConnection(ctx)
if err != nil {
// If the returned error is retryable and there are retries remaining (negative
// retries means retry indefinitely), then retry the operation. Set the server
// and connection to nil to request a new server and connection.
if rerr, ok := err.(RetryablePoolError); ok && rerr.Retryable() && retries != 0 {
resetForRetry(err)
continue
}
// If this is a retry and there's an error from a previous attempt, return the previous
// error instead of the current connection error.
if prevErr != nil {
return prevErr
}
return err
}
defer conn.Close()
}
// Run steps that must only be run on the first attempt, but not again for retries.
if first {
// Determine if retries are supported for the current operation on the current server
// description. Per the retryable writes specification, only determine this for the
// first server selected:
//
// If the server selected for the first attempt of a retryable write operation does
// not support retryable writes, drivers MUST execute the write as if retryable writes
// were not enabled.
retrySupported = op.retryable(conn.Description())
// If retries are supported for the current operation on the current server description,
// client retries are enabled, the operation type is write, and we haven't incremented
// the txn number yet, enable retry writes on the session and increment the txn number.
// Calling IncrementTxnNumber() for server descriptions or topologies that do not
// support retries (e.g. standalone topologies) will cause server errors. Only do this
// check for the first attempt to keep retried writes in the same transaction.
if retrySupported && op.RetryMode != nil && op.Type == Write && op.Client != nil {
op.Client.RetryWrite = false
if op.RetryMode.Enabled() {
op.Client.RetryWrite = true
if !op.Client.Committing && !op.Client.Aborting {
op.Client.IncrementTxnNumber()
}
}
}
first = false
}
desc := description.SelectedServer{Server: conn.Description(), Kind: op.Deployment.Kind()}
scratch = scratch[:0]
if desc.WireVersion == nil || desc.WireVersion.Max < 4 {
switch op.Legacy {
case LegacyFind:
return op.legacyFind(ctx, scratch, srvr, conn, desc)
case LegacyGetMore:
return op.legacyGetMore(ctx, scratch, srvr, conn, desc)
case LegacyKillCursors:
return op.legacyKillCursors(ctx, scratch, srvr, conn, desc)
}
}
if desc.WireVersion == nil || desc.WireVersion.Max < 3 {
switch op.Legacy {
case LegacyListCollections:
return op.legacyListCollections(ctx, scratch, srvr, conn, desc)
case LegacyListIndexes:
return op.legacyListIndexes(ctx, scratch, srvr, conn, desc)
}
}
if batching {
targetBatchSize := desc.MaxDocumentSize
maxDocSize := desc.MaxDocumentSize
@@ -455,7 +516,7 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
var perr error
switch tt := err.(type) {
case WriteCommandError:
if e := err.(WriteCommandError); retryable && op.Type == Write && e.UnsupportedStorageEngine() {
if e := err.(WriteCommandError); retrySupported && op.Type == Write && e.UnsupportedStorageEngine() {
return ErrUnsupportedStorageEngine
}
@@ -470,23 +531,16 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
tt.Labels = append(tt.Labels, RetryableWriteError)
}
if retryable && retryableErr && retries != 0 {
retries--
original = err
conn.Close() // Avoid leaking the connection.
srvr, conn, err = op.getServerAndConnection(ctx)
if err != nil || conn == nil || !op.retryable(conn.Description()) {
if conn != nil {
conn.Close()
}
return original
}
defer conn.Close() // Avoid leaking the new connection.
// If retries are supported for the current operation on the first server description,
// the error is considered retryable, and there are retries remaining (negative retries
// means retry indefinitely), then retry the operation.
if retrySupported && retryableErr && retries != 0 {
if op.Client != nil && op.Client.Committing {
// Apply majority write concern for retries
op.Client.UpdateCommitTransactionWriteConcern()
op.WriteConcern = op.Client.CurrentWc
}
resetForRetry(tt)
continue
}
@@ -520,6 +574,7 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
Code: int32(tt.WriteConcernError.Code),
Message: tt.WriteConcernError.Message,
Labels: tt.Labels,
Raw: tt.Raw,
}
// The UnknownTransactionCommitResult label is added to all writeConcernErrors besides unknownReplWriteConcernCode
// and unsatisfiableWriteConcernCode
@@ -534,13 +589,15 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
operationErr.WriteConcernError = tt.WriteConcernError
operationErr.WriteErrors = append(operationErr.WriteErrors, tt.WriteErrors...)
operationErr.Labels = tt.Labels
operationErr.Raw = tt.Raw
case Error:
if tt.HasErrorLabel(TransientTransactionError) || tt.HasErrorLabel(UnknownTransactionCommitResult) {
if err := op.Client.ClearPinnedResources(); err != nil {
return err
}
}
if e := err.(Error); retryable && op.Type == Write && e.UnsupportedStorageEngine() {
if e := err.(Error); retrySupported && op.Type == Write && e.UnsupportedStorageEngine() {
return ErrUnsupportedStorageEngine
}
@@ -561,23 +618,16 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
retryableErr = tt.RetryableRead()
}
if retryable && retryableErr && retries != 0 {
retries--
original = err
conn.Close() // Avoid leaking the connection.
srvr, conn, err = op.getServerAndConnection(ctx)
if err != nil || conn == nil || !op.retryable(conn.Description()) {
if conn != nil {
conn.Close()
}
return original
}
defer conn.Close() // Avoid leaking the new connection.
// If retries are supported for the current operation on the first server description,
// the error is considered retryable, and there are retries remaining (negative retries
// means retry indefinitely), then retry the operation.
if retrySupported && retryableErr && retries != 0 {
if op.Client != nil && op.Client.Committing {
// Apply majority write concern for retries
op.Client.UpdateCommitTransactionWriteConcern()
op.WriteConcern = op.Client.CurrentWc
}
resetForRetry(tt)
continue
}
@@ -629,8 +679,11 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error {
return err
}
// If we're batching and there are batches remaining, advance to the next batch. This isn't
// a retry, so increment the transaction number, reset the retries number, and don't set
// server or connection to nil to continue using the same connection.
if batching && len(op.Batches.Documents) > 0 {
if retryable && op.Client != nil && op.RetryMode != nil {
if retrySupported && op.Client != nil && op.RetryMode != nil {
if *op.RetryMode > RetryNone {
op.Client.IncrementTxnNumber()
}
@@ -813,8 +866,10 @@ func (Operation) decompressWireMessage(wm []byte) ([]byte, error) {
func (op Operation) createWireMessage(ctx context.Context, dst []byte,
desc description.SelectedServer, conn Connection) ([]byte, startedInformation, error) {
if desc.WireVersion == nil || desc.WireVersion.Max < wiremessage.OpmsgWireVersion {
// If topology is not LoadBalanced, API version is not declared, and wire version is unknown
// or less than 6, use OP_QUERY. Otherwise, use OP_MSG.
if desc.Kind != description.LoadBalanced && op.ServerAPI == nil &&
(desc.WireVersion == nil || desc.WireVersion.Max < wiremessage.OpmsgWireVersion) {
return op.createQueryWireMessage(dst, desc)
}
return op.createMsgWireMessage(ctx, dst, desc, conn)
@@ -44,7 +44,7 @@ func (at *AbortTransaction) processResponse(driver.ResponseInfo) error {
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (at *AbortTransaction) Execute(ctx context.Context) error {
if at.deployment == nil {
return errors.New("the AbortTransaction operation must have a Deployment set before Execute can be called")
@@ -21,7 +21,7 @@ import (
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Performs an aggregate operation
// Aggregate represents an aggregate operation.
type Aggregate struct {
allowDiskUse *bool
batchSize *int32
@@ -46,6 +46,7 @@ type Aggregate struct {
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
hasOutputStage bool
customOptions map[string]bsoncore.Value
result driver.CursorResponse
}
@@ -67,6 +68,8 @@ func (a *Aggregate) Result(opts driver.CursorOptions) (*driver.BatchCursor, erro
return driver.NewBatchCursor(a.result, clientSession, clock, opts)
}
// ResultCursorResponse returns the underlying CursorResponse result of executing this
// operation.
func (a *Aggregate) ResultCursorResponse() driver.CursorResponse {
return a.result
}
@@ -79,7 +82,7 @@ func (a *Aggregate) processResponse(info driver.ResponseInfo) error {
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (a *Aggregate) Execute(ctx context.Context) error {
if a.deployment == nil {
return errors.New("the Aggregate operation must have a Deployment set before Execute can be called")
@@ -153,6 +156,9 @@ func (a *Aggregate) command(dst []byte, desc description.SelectedServer) ([]byte
if a.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", a.let)
}
for optionName, optionValue := range a.customOptions {
dst = bsoncore.AppendValueElement(dst, optionName, optionValue)
}
cursorDoc, _ = bsoncore.AppendDocumentEnd(cursorDoc, cursorIdx)
dst = bsoncore.AppendDocumentElement(dst, "cursor", cursorDoc)
@@ -391,3 +397,13 @@ func (a *Aggregate) HasOutputStage(hos bool) *Aggregate {
a.hasOutputStage = hos
return a
}
// CustomOptions specifies extra options to use in the aggregate command.
func (a *Aggregate) CustomOptions(co map[string]bsoncore.Value) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.customOptions = co
return a
}
@@ -69,7 +69,7 @@ func (c *Command) ResultCursor() (*driver.BatchCursor, error) {
return c.resultCursor, nil
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (c *Command) Execute(ctx context.Context) error {
if c.deployment == nil {
return errors.New("the Command operation must have a Deployment set before Execute can be called")
@@ -44,7 +44,7 @@ func (ct *CommitTransaction) processResponse(driver.ResponseInfo) error {
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (ct *CommitTransaction) Execute(ctx context.Context) error {
if ct.deployment == nil {
return errors.New("the CommitTransaction operation must have a Deployment set before Execute can be called")
@@ -20,7 +20,7 @@ import (
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Performs a count operation
// Count represents a count operation.
type Count struct {
maxTimeMS *int64
query bsoncore.Document
@@ -39,12 +39,13 @@ type Count struct {
serverAPI *driver.ServerAPIOptions
}
// CountResult represents a count result returned by the server.
type CountResult struct {
// The number of documents found
N int64
}
func buildCountResult(response bsoncore.Document, srvr driver.Server) (CountResult, error) {
func buildCountResult(response bsoncore.Document) (CountResult, error) {
elements, err := response.Elements()
if err != nil {
return CountResult{}, err
@@ -94,11 +95,11 @@ func (c *Count) Result() CountResult { return c.result }
func (c *Count) processResponse(info driver.ResponseInfo) error {
var err error
c.result, err = buildCountResult(info.ServerResponse, info.Server)
c.result, err = buildCountResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (c *Count) Execute(ctx context.Context) error {
if c.deployment == nil {
return errors.New("the Count operation must have a Deployment set before Execute can be called")
@@ -18,7 +18,7 @@ import (
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Create a create operation
// Create represents a create operation.
type Create struct {
capped *bool
collation bsoncore.Document
@@ -56,7 +56,7 @@ func (c *Create) processResponse(driver.ResponseInfo) error {
return nil
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (c *Create) Execute(ctx context.Context) error {
if c.deployment == nil {
return errors.New("the Create operation must have a Deployment set before Execute can be called")
@@ -127,7 +127,7 @@ func (c *Create) command(dst []byte, desc description.SelectedServer) ([]byte, e
return dst, nil
}
// Specifies if the collection is capped.
// Capped specifies if the collection is capped.
func (c *Create) Capped(capped bool) *Create {
if c == nil {
c = new(Create)
@@ -147,7 +147,7 @@ func (c *Create) Collation(collation bsoncore.Document) *Create {
return c
}
// Specifies the name of the collection to create.
// CollectionName specifies the name of the collection to create.
func (c *Create) CollectionName(collectionName string) *Create {
if c == nil {
c = new(Create)
@@ -157,7 +157,7 @@ func (c *Create) CollectionName(collectionName string) *Create {
return c
}
// Specifies a default configuration for indexes on the collection.
// IndexOptionDefaults specifies a default configuration for indexes on the collection.
func (c *Create) IndexOptionDefaults(indexOptionDefaults bsoncore.Document) *Create {
if c == nil {
c = new(Create)
@@ -167,7 +167,7 @@ func (c *Create) IndexOptionDefaults(indexOptionDefaults bsoncore.Document) *Cre
return c
}
// Specifies the maximum number of documents allowed in a capped collection.
// Max specifies the maximum number of documents allowed in a capped collection.
func (c *Create) Max(max int64) *Create {
if c == nil {
c = new(Create)
@@ -177,7 +177,7 @@ func (c *Create) Max(max int64) *Create {
return c
}
// Specifies the agggregtion pipeline to be run against the source to create the view.
// Pipeline specifies the agggregtion pipeline to be run against the source to create the view.
func (c *Create) Pipeline(pipeline bsoncore.Document) *Create {
if c == nil {
c = new(Create)
@@ -187,7 +187,7 @@ func (c *Create) Pipeline(pipeline bsoncore.Document) *Create {
return c
}
// Specifies the maximum size in bytes for a capped collection.
// Size specifies the maximum size in bytes for a capped collection.
func (c *Create) Size(size int64) *Create {
if c == nil {
c = new(Create)
@@ -197,7 +197,7 @@ func (c *Create) Size(size int64) *Create {
return c
}
// Specifies the storage engine to use for the index.
// StorageEngine specifies the storage engine to use for the index.
func (c *Create) StorageEngine(storageEngine bsoncore.Document) *Create {
if c == nil {
c = new(Create)
@@ -207,7 +207,7 @@ func (c *Create) StorageEngine(storageEngine bsoncore.Document) *Create {
return c
}
// Specifies what should happen if a document being inserted does not pass validation.
// ValidationAction specifies what should happen if a document being inserted does not pass validation.
func (c *Create) ValidationAction(validationAction string) *Create {
if c == nil {
c = new(Create)
@@ -217,7 +217,8 @@ func (c *Create) ValidationAction(validationAction string) *Create {
return c
}
// Specifies how strictly the server applies validation rules to existing documents in the collection during update operations.
// ValidationLevel specifies how strictly the server applies validation rules to existing documents in the collection
// during update operations.
func (c *Create) ValidationLevel(validationLevel string) *Create {
if c == nil {
c = new(Create)
@@ -227,7 +228,7 @@ func (c *Create) ValidationLevel(validationLevel string) *Create {
return c
}
// Specifies validation rules for the collection.
// Validator specifies validation rules for the collection.
func (c *Create) Validator(validator bsoncore.Document) *Create {
if c == nil {
c = new(Create)
@@ -237,7 +238,7 @@ func (c *Create) Validator(validator bsoncore.Document) *Create {
return c
}
// Specifies the name of the source collection or view on which the view will be created.
// ViewOn specifies the name of the source collection or view on which the view will be created.
func (c *Create) ViewOn(viewOn string) *Create {
if c == nil {
c = new(Create)
@@ -38,6 +38,7 @@ type CreateIndexes struct {
serverAPI *driver.ServerAPIOptions
}
// CreateIndexesResult represents a createIndexes result returned by the server.
type CreateIndexesResult struct {
// If the collection was created automatically.
CreatedCollectionAutomatically bool
@@ -47,7 +48,7 @@ type CreateIndexesResult struct {
IndexesBefore int32
}
func buildCreateIndexesResult(response bsoncore.Document, srvr driver.Server) (CreateIndexesResult, error) {
func buildCreateIndexesResult(response bsoncore.Document) (CreateIndexesResult, error) {
elements, err := response.Elements()
if err != nil {
return CreateIndexesResult{}, err
@@ -90,11 +91,11 @@ func (ci *CreateIndexes) Result() CreateIndexesResult { return ci.result }
func (ci *CreateIndexes) processResponse(info driver.ResponseInfo) error {
var err error
ci.result, err = buildCreateIndexesResult(info.ServerResponse, info.Server)
ci.result, err = buildCreateIndexesResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (ci *CreateIndexes) Execute(ctx context.Context) error {
if ci.deployment == nil {
return errors.New("the CreateIndexes operation must have a Deployment set before Execute can be called")
@@ -133,9 +134,9 @@ func (ci *CreateIndexes) command(dst []byte, desc description.SelectedServer) ([
return dst, nil
}
// The number of data-bearing members of a replica set, including the primary, that must complete the index builds
// successfully before the primary marks the indexes as ready. This should either be a string or int32 value.
//
// CommitQuorum specifies the number of data-bearing members of a replica set, including the primary, that must
// complete the index builds successfully before the primary marks the indexes as ready. This should either be a
// string or int32 value.
func (ci *CreateIndexes) CommitQuorum(commitQuorum bsoncore.Value) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
@@ -145,7 +146,7 @@ func (ci *CreateIndexes) CommitQuorum(commitQuorum bsoncore.Value) *CreateIndexe
return ci
}
// An array containing index specification documents for the indexes being created.
// Indexes specifies an array containing index specification documents for the indexes being created.
func (ci *CreateIndexes) Indexes(indexes bsoncore.Document) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
@@ -36,14 +36,16 @@ type Delete struct {
hint *bool
result DeleteResult
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
}
// DeleteResult represents a delete result returned by the server.
type DeleteResult struct {
// Number of documents successfully deleted.
N int32
}
func buildDeleteResult(response bsoncore.Document, srvr driver.Server) (DeleteResult, error) {
func buildDeleteResult(response bsoncore.Document) (DeleteResult, error) {
elements, err := response.Elements()
if err != nil {
return DeleteResult{}, err
@@ -73,12 +75,12 @@ func NewDelete(deletes ...bsoncore.Document) *Delete {
func (d *Delete) Result() DeleteResult { return d.result }
func (d *Delete) processResponse(info driver.ResponseInfo) error {
dr, err := buildDeleteResult(info.ServerResponse, info.Server)
dr, err := buildDeleteResult(info.ServerResponse)
d.result.N += dr.N
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (d *Delete) Execute(ctx context.Context) error {
if d.deployment == nil {
return errors.New("the Delete operation must have a Deployment set before Execute can be called")
@@ -121,6 +123,9 @@ func (d *Delete) command(dst []byte, desc description.SelectedServer) ([]byte, e
return nil, errUnacknowledgedHint
}
}
if d.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", d.let)
}
return dst, nil
}
@@ -269,3 +274,13 @@ func (d *Delete) ServerAPI(serverAPI *driver.ServerAPIOptions) *Delete {
d.serverAPI = serverAPI
return d
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (d *Delete) Let(let bsoncore.Document) *Delete {
if d == nil {
d = new(Delete)
}
d.let = let
return d
}
@@ -40,12 +40,13 @@ type Distinct struct {
serverAPI *driver.ServerAPIOptions
}
// DistinctResult represents a distinct result returned by the server.
type DistinctResult struct {
// The distinct values for the field.
Values bsoncore.Value
}
func buildDistinctResult(response bsoncore.Document, srvr driver.Server) (DistinctResult, error) {
func buildDistinctResult(response bsoncore.Document) (DistinctResult, error) {
elements, err := response.Elements()
if err != nil {
return DistinctResult{}, err
@@ -73,11 +74,11 @@ func (d *Distinct) Result() DistinctResult { return d.result }
func (d *Distinct) processResponse(info driver.ResponseInfo) error {
var err error
d.result, err = buildDistinctResult(info.ServerResponse, info.Server)
d.result, err = buildDistinctResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (d *Distinct) Execute(ctx context.Context) error {
if d.deployment == nil {
return errors.New("the Distinct operation must have a Deployment set before Execute can be called")
@@ -34,6 +34,7 @@ type DropCollection struct {
serverAPI *driver.ServerAPIOptions
}
// DropCollectionResult represents a dropCollection result returned by the server.
type DropCollectionResult struct {
// The number of indexes in the dropped collection.
NIndexesWas int32
@@ -41,7 +42,7 @@ type DropCollectionResult struct {
Ns string
}
func buildDropCollectionResult(response bsoncore.Document, srvr driver.Server) (DropCollectionResult, error) {
func buildDropCollectionResult(response bsoncore.Document) (DropCollectionResult, error) {
elements, err := response.Elements()
if err != nil {
return DropCollectionResult{}, err
@@ -76,11 +77,11 @@ func (dc *DropCollection) Result() DropCollectionResult { return dc.result }
func (dc *DropCollection) processResponse(info driver.ResponseInfo) error {
var err error
dc.result, err = buildDropCollectionResult(info.ServerResponse, info.Server)
dc.result, err = buildDropCollectionResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (dc *DropCollection) Execute(ctx context.Context) error {
if dc.deployment == nil {
return errors.New("the DropCollection operation must have a Deployment set before Execute can be called")
@@ -36,7 +36,7 @@ func NewDropDatabase() *DropDatabase {
return &DropDatabase{}
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (dd *DropDatabase) Execute(ctx context.Context) error {
if dd.deployment == nil {
return errors.New("the DropDatabase operation must have a Deployment set before Execute can be called")
@@ -36,12 +36,13 @@ type DropIndexes struct {
serverAPI *driver.ServerAPIOptions
}
// DropIndexesResult represents a dropIndexes result returned by the server.
type DropIndexesResult struct {
// Number of indexes that existed before the drop was executed.
NIndexesWas int32
}
func buildDropIndexesResult(response bsoncore.Document, srvr driver.Server) (DropIndexesResult, error) {
func buildDropIndexesResult(response bsoncore.Document) (DropIndexesResult, error) {
elements, err := response.Elements()
if err != nil {
return DropIndexesResult{}, err
@@ -72,11 +73,11 @@ func (di *DropIndexes) Result() DropIndexesResult { return di.result }
func (di *DropIndexes) processResponse(info driver.ResponseInfo) error {
var err error
di.result, err = buildDropIndexesResult(info.ServerResponse, info.Server)
di.result, err = buildDropIndexesResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (di *DropIndexes) Execute(ctx context.Context) error {
if di.deployment == nil {
return errors.New("the DropIndexes operation must have a Deployment set before Execute can be called")
@@ -42,7 +42,7 @@ func (es *EndSessions) processResponse(driver.ResponseInfo) error {
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (es *EndSessions) Execute(ctx context.Context) error {
if es.deployment == nil {
return errors.New("the EndSessions operation must have a Deployment set before Execute can be called")
@@ -70,7 +70,7 @@ func (es *EndSessions) command(dst []byte, desc description.SelectedServer) ([]b
return dst, nil
}
// sessionIDs specify the sessions to be expired.
// SessionIDs specifies the sessions to be expired.
func (es *EndSessions) SessionIDs(sessionIDs bsoncore.Document) *EndSessions {
if es == nil {
es = new(EndSessions)
@@ -30,6 +30,7 @@ type Find struct {
comment *string
filter bsoncore.Document
hint bsoncore.Value
let bsoncore.Document
limit *int64
max bsoncore.Document
maxTimeMS *int64
@@ -78,7 +79,7 @@ func (f *Find) processResponse(info driver.ResponseInfo) error {
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (f *Find) Execute(ctx context.Context) error {
if f.deployment == nil {
return errors.New("the Find operation must have a Deployment set before Execute can be called")
@@ -136,6 +137,9 @@ func (f *Find) command(dst []byte, desc description.SelectedServer) ([]byte, err
if f.hint.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "hint", f.hint)
}
if f.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", f.let)
}
if f.limit != nil {
dst = bsoncore.AppendInt64Element(dst, "limit", *f.limit)
}
@@ -261,6 +265,16 @@ func (f *Find) Hint(hint bsoncore.Value) *Find {
return f
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (f *Find) Let(let bsoncore.Document) *Find {
if f == nil {
f = new(Find)
}
f.let = let
return f
}
// Limit sets a limit on the number of documents to return.
func (f *Find) Limit(limit int64) *Find {
if f == nil {
@@ -321,7 +335,7 @@ func (f *Find) OplogReplay(oplogReplay bool) *Find {
return f
}
// Project limits the fields returned for all documents.
// Projection limits the fields returned for all documents.
func (f *Find) Projection(projection bsoncore.Document) *Find {
if f == nil {
f = new(Find)
@@ -46,10 +46,12 @@ type FindAndModify struct {
crypt driver.Crypt
hint bsoncore.Value
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
result FindAndModifyResult
}
// LastErrorObject represents information about updates and upserts returned by the server.
type LastErrorObject struct {
// True if an update modified an existing document
UpdatedExisting bool
@@ -57,6 +59,7 @@ type LastErrorObject struct {
Upserted interface{}
}
// FindAndModifyResult represents a findAndModify result returned by the server.
type FindAndModifyResult struct {
// Either the old or modified document, depending on the value of the new parameter.
Value bsoncore.Document
@@ -64,7 +67,7 @@ type FindAndModifyResult struct {
LastErrorObject LastErrorObject
}
func buildFindAndModifyResult(response bsoncore.Document, srvr driver.Server) (FindAndModifyResult, error) {
func buildFindAndModifyResult(response bsoncore.Document) (FindAndModifyResult, error) {
elements, err := response.Elements()
if err != nil {
return FindAndModifyResult{}, err
@@ -109,12 +112,12 @@ func (fam *FindAndModify) Result() FindAndModifyResult { return fam.result }
func (fam *FindAndModify) processResponse(info driver.ResponseInfo) error {
var err error
fam.result, err = buildFindAndModifyResult(info.ServerResponse, info.Server)
fam.result, err = buildFindAndModifyResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (fam *FindAndModify) Execute(ctx context.Context) error {
if fam.deployment == nil {
return errors.New("the FindAndModify operation must have a Deployment set before Execute can be called")
@@ -200,6 +203,9 @@ func (fam *FindAndModify) command(dst []byte, desc description.SelectedServer) (
}
dst = bsoncore.AppendValueElement(dst, "hint", fam.hint)
}
if fam.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", fam.let)
}
return dst, nil
}
@@ -436,3 +442,13 @@ func (fam *FindAndModify) ServerAPI(serverAPI *driver.ServerAPIOptions) *FindAnd
fam.serverAPI = serverAPI
return fam
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (fam *FindAndModify) Let(let bsoncore.Document) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.let = let
return fam
}
@@ -159,7 +159,9 @@ func (h *Hello) handshakeCommand(dst []byte, desc description.SelectedServer) ([
// command appends all necessary command fields.
func (h *Hello) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
if h.serverAPI != nil || desc.Server.HelloOK {
// Use "hello" if topology is LoadBalanced, API version is declared or server
// has responded with "helloOk". Otherwise, use legacy hello.
if desc.Kind == description.LoadBalanced || h.serverAPI != nil || desc.Server.HelloOK {
dst = bsoncore.AppendInt32Element(dst, "hello", 1)
} else {
dst = bsoncore.AppendInt32Element(dst, internal.LegacyHello, 1)
@@ -38,12 +38,13 @@ type Insert struct {
serverAPI *driver.ServerAPIOptions
}
// InsertResult represents an insert result returned by the server.
type InsertResult struct {
// Number of documents successfully inserted.
N int32
}
func buildInsertResult(response bsoncore.Document, srvr driver.Server) (InsertResult, error) {
func buildInsertResult(response bsoncore.Document) (InsertResult, error) {
elements, err := response.Elements()
if err != nil {
return InsertResult{}, err
@@ -73,12 +74,12 @@ func NewInsert(documents ...bsoncore.Document) *Insert {
func (i *Insert) Result() InsertResult { return i.result }
func (i *Insert) processResponse(info driver.ResponseInfo) error {
ir, err := buildInsertResult(info.ServerResponse, info.Server)
ir, err := buildInsertResult(info.ServerResponse)
i.result.N += ir.N
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (i *Insert) Execute(ctx context.Context) error {
if i.deployment == nil {
return errors.New("the Insert operation must have a Deployment set before Execute can be called")
@@ -39,6 +39,7 @@ type ListDatabases struct {
result ListDatabasesResult
}
// ListDatabasesResult represents a listDatabases result returned by the server.
type ListDatabasesResult struct {
// An array of documents, one document for each database
Databases []databaseRecord
@@ -52,7 +53,7 @@ type databaseRecord struct {
Empty bool
}
func buildListDatabasesResult(response bsoncore.Document, srvr driver.Server) (ListDatabasesResult, error) {
func buildListDatabasesResult(response bsoncore.Document) (ListDatabasesResult, error) {
elements, err := response.Elements()
if err != nil {
return ListDatabasesResult{}, err
@@ -133,12 +134,12 @@ func (ld *ListDatabases) Result() ListDatabasesResult { return ld.result }
func (ld *ListDatabases) processResponse(info driver.ResponseInfo) error {
var err error
ld.result, err = buildListDatabasesResult(info.ServerResponse, info.Server)
ld.result, err = buildListDatabasesResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (ld *ListDatabases) Execute(ctx context.Context) error {
if ld.deployment == nil {
return errors.New("the ListDatabases operation must have a Deployment set before Execute can be called")
@@ -20,20 +20,21 @@ import (
// ListCollections performs a listCollections operation.
type ListCollections struct {
filter bsoncore.Document
nameOnly *bool
session *session.Client
clock *session.ClusterClock
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
readPreference *readpref.ReadPref
selector description.ServerSelector
retry *driver.RetryMode
result driver.CursorResponse
batchSize *int32
serverAPI *driver.ServerAPIOptions
filter bsoncore.Document
nameOnly *bool
authorizedCollections *bool
session *session.Client
clock *session.ClusterClock
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
readPreference *readpref.ReadPref
selector description.ServerSelector
retry *driver.RetryMode
result driver.CursorResponse
batchSize *int32
serverAPI *driver.ServerAPIOptions
}
// NewListCollections constructs and returns a new ListCollections.
@@ -63,7 +64,7 @@ func (lc *ListCollections) processResponse(info driver.ResponseInfo) error {
return err
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (lc *ListCollections) Execute(ctx context.Context) error {
if lc.deployment == nil {
return errors.New("the ListCollections operation must have a Deployment set before Execute can be called")
@@ -89,7 +90,6 @@ func (lc *ListCollections) Execute(ctx context.Context) error {
}
func (lc *ListCollections) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendInt32Element(dst, "listCollections", 1)
if lc.filter != nil {
dst = bsoncore.AppendDocumentElement(dst, "filter", lc.filter)
@@ -97,6 +97,10 @@ func (lc *ListCollections) command(dst []byte, desc description.SelectedServer)
if lc.nameOnly != nil {
dst = bsoncore.AppendBooleanElement(dst, "nameOnly", *lc.nameOnly)
}
if lc.authorizedCollections != nil {
dst = bsoncore.AppendBooleanElement(dst, "authorizedCollections", *lc.authorizedCollections)
}
cursorDoc := bsoncore.NewDocumentBuilder()
if lc.batchSize != nil {
cursorDoc.AppendInt32("batchSize", *lc.batchSize)
@@ -126,6 +130,17 @@ func (lc *ListCollections) NameOnly(nameOnly bool) *ListCollections {
return lc
}
// AuthorizedCollections specifies whether to only return collections the user
// is authorized to use.
func (lc *ListCollections) AuthorizedCollections(authorizedCollections bool) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.authorizedCollections = &authorizedCollections
return lc
}
// Session sets the session for this operation.
func (lc *ListCollections) Session(session *session.Client) *ListCollections {
if lc == nil {
@@ -58,7 +58,7 @@ func (li *ListIndexes) processResponse(info driver.ResponseInfo) error {
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (li *ListIndexes) Execute(ctx context.Context) error {
if li.deployment == nil {
return errors.New("the ListIndexes operation must have a Deployment set before Execute can be called")
@@ -39,6 +39,7 @@ type Update struct {
result UpdateResult
crypt driver.Crypt
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
}
// Upsert contains the information for an upsert in an Update operation.
@@ -57,7 +58,7 @@ type UpdateResult struct {
Upserted []Upsert
}
func buildUpdateResult(response bsoncore.Document, srvr driver.Server) (UpdateResult, error) {
func buildUpdateResult(response bsoncore.Document) (UpdateResult, error) {
elements, err := response.Elements()
if err != nil {
return UpdateResult{}, err
@@ -116,7 +117,7 @@ func NewUpdate(updates ...bsoncore.Document) *Update {
func (u *Update) Result() UpdateResult { return u.result }
func (u *Update) processResponse(info driver.ResponseInfo) error {
ur, err := buildUpdateResult(info.ServerResponse, info.Server)
ur, err := buildUpdateResult(info.ServerResponse)
u.result.N += ur.N
u.result.NModified += ur.NModified
@@ -130,7 +131,7 @@ func (u *Update) processResponse(info driver.ResponseInfo) error {
}
// Execute runs this operations and returns an error if the operaiton did not execute successfully.
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (u *Update) Execute(ctx context.Context) error {
if u.deployment == nil {
return errors.New("the Update operation must have a Deployment set before Execute can be called")
@@ -185,6 +186,9 @@ func (u *Update) command(dst []byte, desc description.SelectedServer) ([]byte, e
return nil, errors.New("the 'arrayFilters' command parameter requires a minimum server wire version of 6")
}
}
if u.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", u.let)
}
return dst, nil
}
@@ -357,3 +361,13 @@ func (u *Update) ServerAPI(serverAPI *driver.ServerAPIOptions) *Update {
u.serverAPI = serverAPI
return u
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (u *Update) Let(let bsoncore.Document) *Update {
if u == nil {
u = new(Update)
}
u.let = let
return u
}
@@ -40,7 +40,7 @@ var ErrAbortTwice = errors.New("cannot call abortTransaction twice")
// ErrCommitAfterAbort is returned if commit is called after an abort.
var ErrCommitAfterAbort = errors.New("cannot call commitTransaction after calling abortTransaction")
// ErrUnackWCUnsupported is returned if an unacknowledged write concern is supported for a transaciton.
// ErrUnackWCUnsupported is returned if an unacknowledged write concern is supported for a transaction.
var ErrUnackWCUnsupported = errors.New("transactions do not support unacknowledged write concerns")
// ErrSnapshotTransaction is returned if an transaction is started on a snapshot session.
@@ -364,7 +364,7 @@ func (c *Client) TransactionRunning() bool {
return c != nil && (c.TransactionState == Starting || c.TransactionState == InProgress)
}
// TransactionCommitted returns true of the client session just committed a transaciton.
// TransactionCommitted returns true of the client session just committed a transaction.
func (c *Client) TransactionCommitted() bool {
return c.TransactionState == Committed
}
@@ -27,6 +27,13 @@ import (
"go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage"
)
// Connection state constants.
const (
connDisconnected int64 = iota
connConnected
connInitialized
)
var globalConnectionID uint64 = 1
var (
@@ -38,10 +45,10 @@ var (
func nextConnectionID() uint64 { return atomic.AddUint64(&globalConnectionID, 1) }
type connection struct {
// connected must be accessed using the atomic package and should be at the beginning of the struct.
// state must be accessed using the atomic package and should be at the beginning of the struct.
// - atomic bug: https://pkg.go.dev/sync/atomic#pkg-note-BUG
// - suggested layout: https://go101.org/article/memory-layout.html
connected int64
state int64
id string
nc net.Conn // When nil, the connection is closed.
@@ -56,7 +63,6 @@ type connection struct {
zliblevel int
zstdLevel int
connectDone chan struct{}
connectErr error
config *connectionConfig
cancelConnectContext context.CancelFunc
connectContextMade chan struct{}
@@ -73,11 +79,8 @@ type connection struct {
}
// newConnection handles the creation of a connection. It does not connect the connection.
func newConnection(addr address.Address, opts ...ConnectionOption) (*connection, error) {
cfg, err := newConnectionConfig(opts...)
if err != nil {
return nil, err
}
func newConnection(addr address.Address, opts ...ConnectionOption) *connection {
cfg := newConnectionConfig(opts...)
id := fmt.Sprintf("%s[-%d]", addr, nextConnectionID())
@@ -97,21 +100,9 @@ func newConnection(addr address.Address, opts ...ConnectionOption) (*connection,
if !c.config.loadBalanced {
c.setGenerationNumber()
}
atomic.StoreInt64(&c.connected, initialized)
atomic.StoreInt64(&c.state, connInitialized)
return c, nil
}
func (c *connection) processInitializationError(err error) {
atomic.StoreInt64(&c.connected, disconnected)
if c.nc != nil {
_ = c.nc.Close()
}
c.connectErr = ConnectionError{Wrapped: err, init: true}
if c.config.errorHandlingCallback != nil {
c.config.errorHandlingCallback(c.connectErr, c.generation, c.desc.ServiceID)
}
return c
}
// setGenerationNumber sets the connection's generation number if a callback has been provided to do so in connection
@@ -135,14 +126,28 @@ func (c *connection) hasGenerationNumber() bool {
return c.desc.LoadBalanced()
}
// connect handles the I/O for a connection. It will dial, configure TLS, and perform
// initialization handshakes.
func (c *connection) connect(ctx context.Context) {
if !atomic.CompareAndSwapInt64(&c.connected, initialized, connected) {
return
// connect handles the I/O for a connection. It will dial, configure TLS, and perform initialization
// handshakes. All errors returned by connect are considered "before the handshake completes" and
// must be handled by calling the appropriate SDAM handshake error handler.
func (c *connection) connect(ctx context.Context) (err error) {
if !atomic.CompareAndSwapInt64(&c.state, connInitialized, connConnected) {
return nil
}
defer close(c.connectDone)
// If connect returns an error, set the connection status as disconnected and close the
// underlying net.Conn if it was created.
defer func() {
if err != nil {
atomic.StoreInt64(&c.state, connDisconnected)
if c.nc != nil {
_ = c.nc.Close()
}
}
}()
// Create separate contexts for dialing a connection and doing the MongoDB/auth handshakes.
//
// handshakeCtx is simply a cancellable version of ctx because there's no default timeout that needs to be applied
@@ -181,12 +186,9 @@ func (c *connection) connect(ctx context.Context) {
close(c.connectContextMade)
// Assign the result of DialContext to a temporary net.Conn to ensure that c.nc is not set in an error case.
var err error
var tempNc net.Conn
tempNc, err = c.config.dialer.DialContext(dialCtx, c.addr.Network(), c.addr.String())
tempNc, err := c.config.dialer.DialContext(dialCtx, c.addr.Network(), c.addr.String())
if err != nil {
c.processInitializationError(err)
return
return ConnectionError{Wrapped: err, init: true}
}
c.nc = tempNc
@@ -201,18 +203,15 @@ func (c *connection) connect(ctx context.Context) {
}
tlsNc, err := configureTLS(dialCtx, c.config.tlsConnectionSource, c.nc, c.addr, tlsConfig, ocspOpts)
if err != nil {
c.processInitializationError(err)
return
return ConnectionError{Wrapped: err, init: true}
}
c.nc = tlsNc
}
c.bumpIdleDeadline()
// running hello and authentication is handled by a handshaker on the configuration instance.
handshaker := c.config.handshaker
if handshaker == nil {
return
return nil
}
var handshakeInfo driver.HandshakeInformation
@@ -247,8 +246,7 @@ func (c *connection) connect(ctx context.Context) {
// We have a failed handshake here
if err != nil {
c.processInitializationError(err)
return
return ConnectionError{Wrapped: err, init: true}
}
if len(c.desc.Compression) > 0 {
@@ -279,13 +277,13 @@ func (c *connection) connect(ctx context.Context) {
}
}
}
return nil
}
func (c *connection) wait() error {
func (c *connection) wait() {
if c.connectDone != nil {
<-c.connectDone
}
return c.connectErr
}
func (c *connection) closeConnectContext() {
@@ -330,7 +328,7 @@ func (c *connection) cancellationListenerCallback() {
func (c *connection) writeWireMessage(ctx context.Context, wm []byte) error {
var err error
if atomic.LoadInt64(&c.connected) != connected {
if atomic.LoadInt64(&c.state) != connConnected {
return ConnectionError{ConnectionID: c.id, message: "connection is closed"}
}
select {
@@ -364,7 +362,6 @@ func (c *connection) writeWireMessage(ctx context.Context, wm []byte) error {
}
}
c.bumpIdleDeadline()
return nil
}
@@ -387,7 +384,7 @@ func (c *connection) write(ctx context.Context, wm []byte) (err error) {
// readWireMessage reads a wiremessage from the connection. The dst parameter will be overwritten.
func (c *connection) readWireMessage(ctx context.Context, dst []byte) ([]byte, error) {
if atomic.LoadInt64(&c.connected) != connected {
if atomic.LoadInt64(&c.state) != connConnected {
return dst, ConnectionError{ConnectionID: c.id, message: "connection is closed"}
}
@@ -429,7 +426,6 @@ func (c *connection) readWireMessage(ctx context.Context, dst []byte) ([]byte, e
}
}
c.bumpIdleDeadline()
return dst, nil
}
@@ -490,7 +486,7 @@ func (c *connection) read(ctx context.Context, dst []byte) (bytesRead []byte, er
func (c *connection) close() error {
// Overwrite the connection state as the first step so only the first close call will execute.
if !atomic.CompareAndSwapInt64(&c.connected, connected, disconnected) {
if !atomic.CompareAndSwapInt64(&c.state, connConnected, connDisconnected) {
return nil
}
@@ -503,7 +499,7 @@ func (c *connection) close() error {
}
func (c *connection) closed() bool {
return atomic.LoadInt64(&c.connected) == disconnected
return atomic.LoadInt64(&c.state) == connDisconnected
}
func (c *connection) idleTimeoutExpired() bool {
@@ -600,6 +596,10 @@ type Connection struct {
refCount int
cleanupPoolFn func()
// cleanupServerFn resets the server state when a connection is returned to the connection pool
// via Close() or expired via Expire().
cleanupServerFn func()
mu sync.RWMutex
}
@@ -701,6 +701,10 @@ func (c *Connection) cleanupReferences() error {
c.cleanupPoolFn()
c.cleanupPoolFn = nil
}
if c.cleanupServerFn != nil {
c.cleanupServerFn()
c.cleanupServerFn = nil
}
c.connection = nil
return err
}
@@ -806,7 +810,6 @@ func configureTLS(ctx context.Context,
config *tls.Config,
ocspOpts *ocsp.VerifyOptions,
) (net.Conn, error) {
// Ensure config.ServerName is always set for SNI.
if config.ServerName == "" {
hostname := addr.String()
@@ -820,27 +823,15 @@ func configureTLS(ctx context.Context,
}
client := tlsConnSource.Client(nc, config)
errChan := make(chan error, 1)
go func() {
errChan <- client.Handshake()
}()
select {
case err := <-errChan:
if err != nil {
return nil, err
}
// Only do OCSP verification if TLS verification is requested.
if config.InsecureSkipVerify {
break
}
if err := clientHandshake(ctx, client); err != nil {
return nil, err
}
// Only do OCSP verification if TLS verification is requested.
if !config.InsecureSkipVerify {
if ocspErr := ocsp.Verify(ctx, client.ConnectionState(), ocspOpts); ocspErr != nil {
return nil, ocspErr
}
case <-ctx.Done():
return nil, ctx.Err()
}
return client, nil
}
@@ -53,13 +53,12 @@ type connectionConfig struct {
zstdLevel *int
ocspCache ocsp.Cache
disableOCSPEndpointCheck bool
errorHandlingCallback func(err error, startGenNum uint64, svcID *primitive.ObjectID)
tlsConnectionSource tlsConnectionSource
loadBalanced bool
getGenerationFn generationNumberFn
}
func newConnectionConfig(opts ...ConnectionOption) (*connectionConfig, error) {
func newConnectionConfig(opts ...ConnectionOption) *connectionConfig {
cfg := &connectionConfig{
connectTimeout: 30 * time.Second,
dialer: nil,
@@ -67,131 +66,111 @@ func newConnectionConfig(opts ...ConnectionOption) (*connectionConfig, error) {
}
for _, opt := range opts {
err := opt(cfg)
if err != nil {
return nil, err
if opt == nil {
continue
}
opt(cfg)
}
if cfg.dialer == nil {
cfg.dialer = &net.Dialer{}
}
return cfg, nil
return cfg
}
// ConnectionOption is used to configure a connection.
type ConnectionOption func(*connectionConfig) error
type ConnectionOption func(*connectionConfig)
func withTLSConnectionSource(fn func(tlsConnectionSource) tlsConnectionSource) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.tlsConnectionSource = fn(c.tlsConnectionSource)
return nil
}
}
func withErrorHandlingCallback(fn func(err error, startGenNum uint64, svcID *primitive.ObjectID)) ConnectionOption {
return func(c *connectionConfig) error {
c.errorHandlingCallback = fn
return nil
}
}
// WithCompressors sets the compressors that can be used for communication.
func WithCompressors(fn func([]string) []string) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.compressors = fn(c.compressors)
return nil
}
}
// WithConnectTimeout configures the maximum amount of time a dial will wait for a
// Connect to complete. The default is 30 seconds.
func WithConnectTimeout(fn func(time.Duration) time.Duration) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.connectTimeout = fn(c.connectTimeout)
return nil
}
}
// WithDialer configures the Dialer to use when making a new connection to MongoDB.
func WithDialer(fn func(Dialer) Dialer) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.dialer = fn(c.dialer)
return nil
}
}
// WithHandshaker configures the Handshaker that wll be used to initialize newly
// dialed connections.
func WithHandshaker(fn func(Handshaker) Handshaker) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.handshaker = fn(c.handshaker)
return nil
}
}
// WithIdleTimeout configures the maximum idle time to allow for a connection.
func WithIdleTimeout(fn func(time.Duration) time.Duration) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.idleTimeout = fn(c.idleTimeout)
return nil
}
}
// WithReadTimeout configures the maximum read time for a connection.
func WithReadTimeout(fn func(time.Duration) time.Duration) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.readTimeout = fn(c.readTimeout)
return nil
}
}
// WithWriteTimeout configures the maximum write time for a connection.
func WithWriteTimeout(fn func(time.Duration) time.Duration) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.writeTimeout = fn(c.writeTimeout)
return nil
}
}
// WithTLSConfig configures the TLS options for a connection.
func WithTLSConfig(fn func(*tls.Config) *tls.Config) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.tlsConfig = fn(c.tlsConfig)
return nil
}
}
// WithMonitor configures a event for command monitoring.
func WithMonitor(fn func(*event.CommandMonitor) *event.CommandMonitor) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.cmdMonitor = fn(c.cmdMonitor)
return nil
}
}
// WithZlibLevel sets the zLib compression level.
func WithZlibLevel(fn func(*int) *int) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.zlibLevel = fn(c.zlibLevel)
return nil
}
}
// WithZstdLevel sets the zstd compression level.
func WithZstdLevel(fn func(*int) *int) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.zstdLevel = fn(c.zstdLevel)
return nil
}
}
// WithOCSPCache specifies a cache to use for OCSP verification.
func WithOCSPCache(fn func(ocsp.Cache) ocsp.Cache) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.ocspCache = fn(c.ocspCache)
return nil
}
}
@@ -199,23 +178,20 @@ func WithOCSPCache(fn func(ocsp.Cache) ocsp.Cache) ConnectionOption {
// to true, the driver will only check stapled responses and will continue the connection without reaching out to
// OCSP responders.
func WithDisableOCSPEndpointCheck(fn func(bool) bool) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.disableOCSPEndpointCheck = fn(c.disableOCSPEndpointCheck)
return nil
}
}
// WithConnectionLoadBalanced specifies whether or not the connection is to a server behind a load balancer.
func WithConnectionLoadBalanced(fn func(bool) bool) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.loadBalanced = fn(c.loadBalanced)
return nil
}
}
func withGenerationNumberFn(fn func(generationNumberFn) generationNumberFn) ConnectionOption {
return func(c *connectionConfig) error {
return func(c *connectionConfig) {
c.getGenerationFn = fn(c.getGenerationFn)
return nil
}
}
@@ -11,7 +11,7 @@ type ConnectionError struct {
ConnectionID string
Wrapped error
// init will be set to true if this error occured during connection initialization or
// init will be set to true if this error occurred during connection initialization or
// during a connection handshake.
init bool
message string
@@ -21,7 +21,7 @@ type ConnectionError struct {
func (e ConnectionError) Error() string {
message := e.message
if e.init {
fullMsg := "error occured during connection handshake"
fullMsg := "error occurred during connection handshake"
if message != "" {
fullMsg = fmt.Sprintf("%s: %s", fullMsg, message)
}
+7 -9
View File
@@ -18,7 +18,7 @@ import (
var (
// SupportedWireVersions is the range of wire versions supported by the driver.
SupportedWireVersions = description.NewVersionRange(2, 14)
SupportedWireVersions = description.NewVersionRange(2, 15)
)
const (
@@ -46,7 +46,7 @@ func newFSM() *fsm {
//
// apply should operation on immutable descriptions so we don't have to lock for the entire time we're applying the
// server description.
func (f *fsm) apply(s description.Server) (description.Topology, description.Server, error) {
func (f *fsm) apply(s description.Server) (description.Topology, description.Server) {
newServers := make([]description.Server, len(f.Servers))
copy(newServers, f.Servers)
@@ -77,7 +77,7 @@ func (f *fsm) apply(s description.Server) (description.Topology, description.Ser
}
if _, ok := f.findServer(s.Addr); !ok {
return f.Topology, s, nil
return f.Topology, s
}
updatedDesc := s
@@ -107,7 +107,7 @@ func (f *fsm) apply(s description.Server) (description.Topology, description.Ser
MinSupportedMongoDBVersion,
)
f.Topology.CompatibilityErr = f.compatibilityErr
return f.Topology, s, nil
return f.Topology, s
}
if server.WireVersion.Min > SupportedWireVersions.Max {
@@ -119,14 +119,14 @@ func (f *fsm) apply(s description.Server) (description.Topology, description.Ser
SupportedWireVersions.Max,
)
f.Topology.CompatibilityErr = f.compatibilityErr
return f.Topology, s, nil
return f.Topology, s
}
}
}
f.compatible.Store(true)
f.compatibilityErr = nil
return f.Topology, updatedDesc, nil
return f.Topology, updatedDesc
}
func (f *fsm) applyToReplicaSetNoPrimary(s description.Server) description.Server {
@@ -376,12 +376,10 @@ func (f *fsm) removeServerByAddr(addr address.Address) {
}
}
func (f *fsm) replaceServer(s description.Server) bool {
func (f *fsm) replaceServer(s description.Server) {
if i, ok := f.findServer(s.Addr); ok {
f.setServer(i, s)
return true
}
return false
}
func (f *fsm) setServer(i int, s description.Server) {
@@ -0,0 +1,37 @@
// Copyright (C) MongoDB, Inc. 2022-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build !go1.17
// +build !go1.17
package topology
import (
"crypto/tls"
"time"
)
// hangingTLSConn is an implementation of tlsConn that wraps the tls.Conn type and overrides the Handshake function to
// sleep for a fixed amount of time.
type hangingTLSConn struct {
*tls.Conn
sleepTime time.Duration
}
var _ tlsConn = (*hangingTLSConn)(nil)
func newHangingTLSConn(conn *tls.Conn, sleepTime time.Duration) *hangingTLSConn {
return &hangingTLSConn{
Conn: conn,
sleepTime: sleepTime,
}
}
// Handshake implements the tlsConn interface on Go 1.16 and less.
func (h *hangingTLSConn) Handshake() error {
time.Sleep(h.sleepTime)
return h.Conn.Handshake()
}
@@ -0,0 +1,44 @@
// Copyright (C) MongoDB, Inc. 2022-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//go:build go1.17
// +build go1.17
package topology
import (
"context"
"crypto/tls"
"time"
)
// hangingTLSConn is an implementation of tlsConn that wraps the tls.Conn type and overrides the HandshakeContext function to
// sleep for a fixed amount of time.
type hangingTLSConn struct {
*tls.Conn
sleepTime time.Duration
}
var _ tlsConn = (*hangingTLSConn)(nil)
func newHangingTLSConn(conn *tls.Conn, sleepTime time.Duration) *hangingTLSConn {
return &hangingTLSConn{
Conn: conn,
sleepTime: sleepTime,
}
}
// HandshakeContext implements the tlsConn interface on Go 1.17 and higher.
func (h *hangingTLSConn) HandshakeContext(ctx context.Context) error {
timer := time.NewTimer(h.sleepTime)
defer timer.Stop()
select {
case <-timer.C:
case <-ctx.Done():
}
return h.Conn.HandshakeContext(ctx)
}

Some files were not shown because too many files have changed in this diff Show More