@@ -20,7 +20,7 @@ defmodule Mongo do
20
20
a 1-arity fun, `{module, function, args}` with `DBConnection.LogEntry.t`
21
21
prepended to `args` or `nil`. See `DBConnection.LogEntry` (default: `nil`)
22
22
* `:database` - the database to run the operation on
23
- * `:connect_timeout_ms ` - maximum timeout for connect (default: `5_000`)
23
+ * `:connect_timeout ` - maximum timeout for connect (default: `5_000`)
24
24
25
25
## Read options
26
26
@@ -54,7 +54,7 @@ defmodule Mongo do
54
54
alias Mongo.Topology
55
55
alias Mongo.UrlParser
56
56
57
- @ timeout 5000
57
+ @ timeout 15000 # 5000
58
58
59
59
@ dialyzer [ no_match: [ count_documents!: 4 ] ]
60
60
@@ -64,8 +64,6 @@ defmodule Mongo do
64
64
@ type result ( t ) :: :ok | { :ok , t } | { :error , Mongo.Error . t }
65
65
@ type result! ( t ) :: nil | t | no_return
66
66
67
- @ cmd_collection "$cmd"
68
-
69
67
defmacrop bangify ( result ) do
70
68
quote do
71
69
case unquote ( result ) do
@@ -101,7 +99,7 @@ defmodule Mongo do
101
99
* `:idle` - The idle strategy, `:passive` to avoid checkin when idle and
102
100
`:active` to checking when idle (default: `:passive`)
103
101
* `:idle_timeout` - The idle timeout to ping the database (default: `1_000`)
104
- * `:connect_timeout_ms ` - The maximum timeout for the initial connection
102
+ * `:connect_timeout ` - The maximum timeout for the initial connection
105
103
(default: `5_000`)
106
104
* `:backoff_min` - The minimum backoff interval (default: `1_000`)
107
105
* `:backoff_max` - The maximum backoff interval (default: `30_000`)
@@ -141,41 +139,86 @@ defmodule Mongo do
141
139
Mongo.IdServer . new
142
140
end
143
141
142
+ @ doc """
143
+
144
+ Creates a change stream cursor on collections.
145
+
146
+ `on_resume_token` is function that takes the new resume token, if it changed.
147
+
148
+ ## Options
149
+
150
+ * `:full_document` -
151
+ * `:max_time` - Specifies a time limit in milliseconds. This option is used on `getMore` commands
152
+ * `:batch_size` - Specifies the number of maximum number of documents to
153
+ return (default: 1)
154
+ * `:resume_after` - Specifies the logical starting point for the new change stream.
155
+ * `:start_at_operation_time` - The change stream will only provide changes that occurred at or after the specified timestamp (since 4.0)
156
+ * `:start_after` - Similar to `resumeAfter`, this option takes a resume token and starts a new change stream
157
+ returning the first notification after the token. This will allow users to watch collections that have been dropped and recreated
158
+ or newly renamed collections without missing any notifications. (since 4.0.7)
159
+ """
160
+ @ spec watch_collection ( GenServer . server , collection , [ BSON . document ] , fun , Keyword . it ) :: cursor
161
+ def watch_collection ( topology_pid , coll , pipeline , on_resume_token \\ nil , opts \\ [ ] ) do
162
+
163
+ stream_opts = % {
164
+ fullDocument: opts [ :full_document ] || "default" ,
165
+ resumeAfter: opts [ :resume_after ] ,
166
+ startAtOperationTime: opts [ :start_at_operation_time ] ,
167
+ startAfter: opts [ :start_after ]
168
+ } |> filter_nils ( )
169
+
170
+ cmd = [
171
+ aggregate: coll ,
172
+ pipeline: [ % { "$changeStream" => stream_opts } | pipeline ] ,
173
+ explain: opts [ :explain ] ,
174
+ allowDiskUse: opts [ :allow_disk_use ] ,
175
+ collation: opts [ :collation ] ,
176
+ maxTimeMS: opts [ :max_time ] ,
177
+ cursor: filter_nils ( % { batchSize: opts [ :batch_size ] } ) ,
178
+ bypassDocumentValidation: opts [ :bypass_document_validation ] ,
179
+ hint: opts [ :hint ] ,
180
+ comment: opts [ :comment ] ,
181
+ readConcern: opts [ :read_concern ]
182
+ ] |> filter_nils ( )
183
+
184
+ opts = Keyword . drop ( opts , ~w( full_document resume_after start_at_operation_time start_after explain allow_disk_use collation bypass_document_validation hint comment read_concern) a )
185
+
186
+ on_resume_token = on_resume_token || ( fn _token -> nil end )
187
+ change_stream_cursor ( topology_pid , cmd , on_resume_token , opts )
188
+
189
+ end
190
+
191
+ @ spec watch_db ( GenServer . server , [ BSON . document ] , fun , Keyword . it ) :: cursor
192
+ def watch_db ( topology_pid , pipeline , on_resume_token \\ nil , opts \\ [ ] ) do
193
+ watch_collection ( topology_pid , 0 , pipeline , on_resume_token , opts )
194
+ end
195
+
144
196
@ doc """
145
197
Performs aggregation operation using the aggregation pipeline.
146
198
147
- ## Options
199
+ For all options see [ Options](https://docs.mongodb.com/manual/reference/command/aggregate/#aggregate)
148
200
149
- * `:allow_disk_use` - Enables writing to temporary files (Default: false)
150
- * `:collation` - Optionally specifies a collation to use in MongoDB 3.4 and
151
- * `:max_time` - Specifies a time limit in milliseconds
152
- * `:use_cursor` - Use a cursor for a batched response (Default: true)
153
201
"""
154
202
@ spec aggregate ( GenServer . server , collection , [ BSON . document ] , Keyword . t ) :: cursor
155
203
def aggregate ( topology_pid , coll , pipeline , opts \\ [ ] ) do
156
- query = [
204
+
205
+ cmd = [
157
206
aggregate: coll ,
158
207
pipeline: pipeline ,
208
+ explain: opts [ :explain ] ,
159
209
allowDiskUse: opts [ :allow_disk_use ] ,
160
210
collation: opts [ :collation ] ,
161
- maxTimeMS: opts [ :max_time ]
162
- ] |> filter_nils
163
- wv_query = % Query { action: :wire_version }
211
+ maxTimeMS: opts [ :max_time ] ,
212
+ cursor: filter_nils ( % { batchSize: opts [ :batch_size ] } ) ,
213
+ bypassDocumentValidation: opts [ :bypass_document_validation ] ,
214
+ hint: opts [ :hint ] ,
215
+ comment: opts [ :comment ] ,
216
+ readConcern: opts [ :read_concern ]
217
+ ] |> filter_nils ( )
164
218
165
- with { :ok , conn , slave_ok , _ } <- select_server ( topology_pid , :read , opts ) ,
166
- opts = Keyword . put ( opts , :slave_ok , slave_ok ) ,
167
- { :ok , _query , version } <- DBConnection . execute ( conn , wv_query , [ ] , defaults ( opts ) ) do
168
- cursor? = version >= 1 and Keyword . get ( opts , :use_cursor , true )
169
- opts = Keyword . drop ( opts , ~w( allow_disk_use max_time use_cursor) a )
170
-
171
- if cursor? do
172
- query = query ++ [ cursor: filter_nils ( % { batchSize: opts [ :batch_size ] } ) ]
173
- cursor ( conn , @ cmd_collection , query , opts )
174
- else
175
- query = query ++ [ cursor: % { } ]
176
- cursor ( conn , @ cmd_collection , query , opts )
177
- end
178
- end
219
+ opts = Keyword . drop ( opts , ~w( explain allow_disk_use collation bypass_document_validation hint comment read_concern) a )
220
+
221
+ cursor ( topology_pid , cmd , opts )
179
222
end
180
223
181
224
@ doc """
@@ -209,7 +252,7 @@ defmodule Mongo do
209
252
sort: opts [ :sort ] ,
210
253
upsert: opts [ :upsert ] ,
211
254
collation: opts [ :collation ] ,
212
- ] |> filter_nils
255
+ ] |> filter_nils ( )
213
256
214
257
opts = Keyword . drop ( opts , ~w( bypass_document_validation max_time projection return_document sort upsert collation) a )
215
258
@@ -249,7 +292,7 @@ defmodule Mongo do
249
292
sort: opts [ :sort ] ,
250
293
upsert: opts [ :upsert ] ,
251
294
collation: opts [ :collation ] ,
252
- ] |> filter_nils
295
+ ] |> filter_nils ( )
253
296
254
297
opts = Keyword . drop ( opts , ~w( bypass_document_validation max_time projection return_document sort upsert collation) a )
255
298
@@ -281,7 +324,7 @@ defmodule Mongo do
281
324
fields: opts [ :projection ] ,
282
325
sort: opts [ :sort ] ,
283
326
collation: opts [ :collation ] ,
284
- ] |> filter_nils
327
+ ] |> filter_nils ( )
285
328
opts = Keyword . drop ( opts , ~w( max_time projection sort collation) a )
286
329
287
330
with { :ok , conn , _ , _ } <- select_server ( topology_pid , :write , opts ) ,
@@ -298,7 +341,7 @@ defmodule Mongo do
298
341
skip: opts [ :skip ] ,
299
342
hint: opts [ :hint ] ,
300
343
collation: opts [ :collation ]
301
- ] |> filter_nils
344
+ ] |> filter_nils ( )
302
345
303
346
opts = Keyword . drop ( opts , ~w( limit skip hint collation) a )
304
347
@@ -323,11 +366,11 @@ defmodule Mongo do
323
366
@ spec count_documents ( GenServer . server , collection , BSON . document , Keyword . t ) :: result ( non_neg_integer )
324
367
def count_documents ( topology_pid , coll , filter , opts \\ [ ] ) do
325
368
pipeline = [
326
- { "$match" , filter } ,
327
- { "$skip" , opts [ :skip ] } ,
328
- { "$limit" , opts [ :limit ] } ,
329
- { "$group" , % { "_id" => nil , "n" => % { "$sum" => 1 } } }
330
- ] |> filter_nils |> Enum . map ( & List . wrap / 1 )
369
+ "$match": filter ,
370
+ "$skip": opts [ :skip ] ,
371
+ "$limit": opts [ :limit ] ,
372
+ "$group": % { "_id" => nil , "n" => % { "$sum" => 1 } }
373
+ ] |> filter_nils ( ) |> Enum . map ( & List . wrap / 1 )
331
374
332
375
documents =
333
376
topology_pid
@@ -383,7 +426,7 @@ defmodule Mongo do
383
426
query: filter ,
384
427
collation: opts [ :collation ] ,
385
428
maxTimeMS: opts [ :max_time ]
386
- ] |> filter_nils
429
+ ] |> filter_nils ( )
387
430
388
431
opts = Keyword . drop ( opts , ~w( max_time) a )
389
432
@@ -420,7 +463,7 @@ defmodule Mongo do
420
463
other -> other
421
464
end
422
465
423
- query = [
466
+ cmd = [
424
467
{ "find" , coll } ,
425
468
{ "filter" , filter } ,
426
469
{ "limit" , opts [ :limit ] } ,
@@ -445,13 +488,11 @@ defmodule Mongo do
445
488
{ "sort" , opts [ :sort ] }
446
489
]
447
490
448
- query = filter_nils ( query )
491
+ cmd = filter_nils ( cmd )
449
492
450
493
drop = ~w( limit hint single_batch read_concern max min collation return_key show_record_id tailable no_cursor_timeout await_data batch_size projection comment max_time skip sort) a
451
494
opts = Keyword . drop ( opts , drop )
452
- with { :ok , conn , slave_ok , _ } <- select_server ( topology_pid , :read , opts ) ,
453
- opts = Keyword . put ( opts , :slave_ok , slave_ok ) ,
454
- do: cursor ( conn , coll , query , opts )
495
+ cursor ( topology_pid , cmd , opts )
455
496
end
456
497
457
498
@ doc """
@@ -498,7 +539,12 @@ defmodule Mongo do
498
539
@ spec direct_command ( pid , BSON . document , Keyword . t ) :: { :ok , BSON . document | nil } | { :error , Mongo.Error . t }
499
540
def direct_command ( conn , query , opts \\ [ ] ) do
500
541
params = [ query ]
501
- query = % Query { action: :command }
542
+
543
+ query = case Keyword . has_key? ( opts , :error ) do
544
+ false -> % Query { action: :command }
545
+ true -> % Query { action: :error }
546
+ end
547
+ ## query = %Query{action: :command}
502
548
503
549
with { :ok , _query , response } <- DBConnection . execute ( conn , query , params , defaults ( opts ) ) do
504
550
case response do
@@ -512,6 +558,17 @@ defmodule Mongo do
512
558
end
513
559
end
514
560
561
+
562
+ @ doc """
563
+ Returns the current wire version.
564
+ """
565
+ def wire_version ( conn , opts \\ [ ] ) do
566
+ cmd = % Query { action: :wire_version }
567
+ with { :ok , _query , version } <- DBConnection . execute ( conn , cmd , % { } , defaults ( opts ) ) do
568
+ { :ok , version }
569
+ end
570
+ end
571
+
515
572
@ doc """
516
573
Similar to `command/3` but unwraps the result and raises on error.
517
574
"""
@@ -843,11 +900,8 @@ defmodule Mongo do
843
900
"""
844
901
@ spec list_indexes ( GenServer . server , String . t , Keyword . t ) :: cursor
845
902
def list_indexes ( topology_pid , coll , opts \\ [ ] ) do
846
- with { :ok , conn , slave_ok , _ } <- Mongo . select_server ( topology_pid , :read , opts ) do
847
- opts = Keyword . put ( opts , :slave_ok , slave_ok )
848
- query = [ listIndexes: coll ]
849
- cursor ( conn , @ cmd_collection , query , opts )
850
- end
903
+ cmd = [ listIndexes: coll ]
904
+ cursor ( topology_pid , cmd , opts )
851
905
end
852
906
853
907
@ doc """
@@ -872,13 +926,10 @@ defmodule Mongo do
872
926
#
873
927
# In versions 2.8.0-rc3 and later, the listCollections command returns a cursor!
874
928
#
875
- with { :ok , conn , slave_ok , _ } <- Mongo . select_server ( topology_pid , :read , opts ) do
876
- params = [ listCollections: 1 ]
877
- opts = Keyword . put ( opts , :slave_ok , slave_ok )
878
- cursor ( conn , @ cmd_collection , params , opts )
879
- |> Stream . filter ( fn coll -> coll [ "type" ] == "collection" end )
880
- |> Stream . map ( fn coll -> coll [ "name" ] end )
881
- end
929
+ cmd = [ listCollections: 1 ]
930
+ cursor ( topology_pid , cmd , opts )
931
+ |> Stream . filter ( fn coll -> coll [ "type" ] == "collection" end )
932
+ |> Stream . map ( fn coll -> coll [ "name" ] end )
882
933
end
883
934
884
935
@ doc """
@@ -939,12 +990,12 @@ defmodule Mongo do
939
990
defp key_to_string ( key ) when is_atom ( key ) , do: Atom . to_string ( key )
940
991
defp key_to_string ( key ) when is_binary ( key ) , do: key
941
992
942
- defp cursor ( conn , coll , query , opts ) do
943
- % Mongo.Cursor {
944
- conn: conn ,
945
- coll: coll ,
946
- query: query ,
947
- opts: opts }
993
+ defp cursor ( topology_pid , cmd , opts ) do
994
+ % Mongo.Cursor { topology_pid: topology_pid , cmd: cmd , on_resume_token: nil , opts: opts }
995
+ end
996
+
997
+ defp change_stream_cursor ( topology_pid , cmd , fun , opts ) do
998
+ % Mongo.Cursor { topology_pid: topology_pid , cmd: cmd , on_resume_token: fun , opts: opts }
948
999
end
949
1000
950
1001
defp filter_nils ( keyword ) when is_list ( keyword ) do
0 commit comments