mongo 2.19.1 → 2.19.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/mongo/collection/view/iterable.rb +15 -0
  4. data/lib/mongo/collection/view.rb +1 -0
  5. data/lib/mongo/collection.rb +23 -1
  6. data/lib/mongo/operation/create_search_indexes/op_msg.rb +31 -0
  7. data/lib/mongo/operation/create_search_indexes.rb +15 -0
  8. data/lib/mongo/operation/drop_search_index/op_msg.rb +33 -0
  9. data/lib/mongo/operation/drop_search_index.rb +15 -0
  10. data/lib/mongo/operation/shared/specifiable.rb +7 -0
  11. data/lib/mongo/operation/update_search_index/op_msg.rb +34 -0
  12. data/lib/mongo/operation/update_search_index.rb +15 -0
  13. data/lib/mongo/operation.rb +3 -0
  14. data/lib/mongo/search_index/view.rb +232 -0
  15. data/lib/mongo/version.rb +1 -1
  16. data/lib/mongo.rb +1 -0
  17. data/spec/atlas/atlas_connectivity_spec.rb +1 -5
  18. data/spec/atlas/operations_spec.rb +1 -5
  19. data/spec/integration/find_options_spec.rb +227 -0
  20. data/spec/integration/search_indexes_prose_spec.rb +168 -0
  21. data/spec/lite_spec_helper.rb +32 -10
  22. data/spec/runners/unified/search_index_operations.rb +63 -0
  23. data/spec/runners/unified/test.rb +3 -1
  24. data/spec/spec_helper.rb +1 -1
  25. data/spec/spec_tests/data/index_management/createSearchIndex.yml +62 -0
  26. data/spec/spec_tests/data/index_management/createSearchIndexes.yml +83 -0
  27. data/spec/spec_tests/data/index_management/dropSearchIndex.yml +42 -0
  28. data/spec/spec_tests/data/index_management/listSearchIndexes.yml +85 -0
  29. data/spec/spec_tests/data/index_management/updateSearchIndex.yml +45 -0
  30. data/spec/spec_tests/index_management_unified_spec.rb +13 -0
  31. data/spec/support/faas/app/aws_lambda/mongodb/Gemfile.lock +19 -0
  32. data/spec/support/spec_config.rb +5 -0
  33. data.tar.gz.sig +0 -0
  34. metadata +1277 -1250
  35. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 624436394458300bf64df3d0b424b75ea03746b8f1a53987c18be7e33f5d4f74
4
- data.tar.gz: da54416a85f4a3e6318ec6833ae14997a864a5d490c8e0fe451aa2c0acd4fe71
3
+ metadata.gz: '0916a285c62c2e70c94532ca2ed61af6bfcb1ead971a2be825aefbde560209c3'
4
+ data.tar.gz: a9db987bb6f1e2b7e9882c86472bc2c8b10eca0d4bdca9de2a37968de086d8f3
5
5
  SHA512:
6
- metadata.gz: a4c15fae18c57a1c33f45cde07bf325f7d2c45f2fafdf99d521900d0277feb395f0947d422939eda0572d7f0a17819a94ba1e906b1939d83e1aaefc4b662b2a0
7
- data.tar.gz: e0cc5f507b02f8e787c1793b8cb708cd17090505e6ac239db7ed02cd54367d9a0079a6f64f23bf2d661820c6bbbc2df82467a15b90e884a8d9bee88a84065abb
6
+ metadata.gz: ab6a8e7e008174f346f1acd96bb073a39cd4fbdd2a70e44f63f8dcdc421c4d38ba9277cc9c50099c944599886e53230597bdab8bd4c861de29af2bd66dd2be76
7
+ data.tar.gz: 8fe9155b17bbb9b57021eabd7e2211baf2cb0002b211900e8564e0b1c2f9e894bf726a037b1e8b72e6dd55251edefe1e81fd8c3ea61aacd0fd5d7eb76cbc4163
checksums.yaml.gz.sig CHANGED
Binary file
@@ -185,6 +185,8 @@ module Mongo
185
185
  collection.client.log_warn("The :oplog_replay option is deprecated and ignored by MongoDB 4.4 and later")
186
186
  end
187
187
 
188
+ maybe_set_tailable_options(spec)
189
+
188
190
  if explained?
189
191
  spec[:explain] = options[:explain]
190
192
  Operation::Explain.new(spec)
@@ -200,6 +202,19 @@ module Mongo
200
202
  def use_query_cache?
201
203
  QueryCache.enabled? && !collection.system_collection?
202
204
  end
205
+
206
+ # Add tailable cusror options to the command specifiction if needed.
207
+ #
208
+ # @param [ Hash ] spec The command specification.
209
+ def maybe_set_tailable_options(spec)
210
+ case cursor_type
211
+ when :tailable
212
+ spec[:tailable] = true
213
+ when :tailable_await
214
+ spec[:tailable] = true
215
+ spec[:await_data] = true
216
+ end
217
+ end
203
218
  end
204
219
  end
205
220
  end
@@ -127,6 +127,7 @@ module Mongo
127
127
  # return in each response from MongoDB.
128
128
  # @option options [ Hash ] :collation The collation to use.
129
129
  # @option options [ String ] :comment Associate a comment with the query.
130
+ # @option options [ :tailable, :tailable_await ] :cursor_type The type of cursor to use.
130
131
  # @option options [ Hash ] :explain Execute an explain with the provided
131
132
  # explain options (known options are :verbose and :verbosity) rather
132
133
  # than a find.
@@ -725,13 +725,35 @@ module Mongo
725
725
  #
726
726
  # @option options [ Session ] :session The session to use.
727
727
  #
728
- # @return [ View::Index ] The index view.
728
+ # @return [ Index::View ] The index view.
729
729
  #
730
730
  # @since 2.0.0
731
731
  def indexes(options = {})
732
732
  Index::View.new(self, options)
733
733
  end
734
734
 
735
+ # Get a view of all search indexes for this collection. Can be iterated or
736
+ # operated on directly. If id or name are given, the iterator will return
737
+ # only the indicated index. For all other operations, id and name are
738
+ # ignored.
739
+ #
740
+ # @note Only one of id or name may be given; it is an error to specify both,
741
+ # although both may be omitted safely.
742
+ #
743
+ # @param [ Hash ] options The options to use to configure the view.
744
+ #
745
+ # @option options [ String ] :id The id of the specific index to query (optional)
746
+ # @option options [ String ] :name The name of the specific index to query (optional)
747
+ # @option options [ Hash ] :aggregate The options hash to pass to the
748
+ # aggregate command (optional)
749
+ #
750
+ # @return [ SearchIndex::View ] The search index view.
751
+ #
752
+ # @since 2.0.0
753
+ def search_indexes(options = {})
754
+ SearchIndex::View.new(self, options)
755
+ end
756
+
735
757
  # Get a pretty printed string inspection for the collection.
736
758
  #
737
759
  # @example Inspect the collection.
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongo
4
+ module Operation
5
+ class CreateSearchIndexes
6
+ # A MongoDB createSearchIndexes operation sent as an op message.
7
+ #
8
+ # @api private
9
+ class OpMsg < OpMsgBase
10
+ include ExecutableTransactionLabel
11
+
12
+ private
13
+
14
+ # Returns the command to send to the database, describing the
15
+ # desired createSearchIndexes operation.
16
+ #
17
+ # @param [ Mongo::Server ] _server the server that will receive the
18
+ # command
19
+ #
20
+ # @return [ Hash ] the selector
21
+ def selector(_server)
22
+ {
23
+ createSearchIndexes: coll_name,
24
+ :$db => db_name,
25
+ indexes: indexes,
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mongo/operation/create_search_indexes/op_msg'
4
+
5
+ module Mongo
6
+ module Operation
7
+ # A MongoDB createSearchIndexes command operation.
8
+ #
9
+ # @api private
10
+ class CreateSearchIndexes
11
+ include Specifiable
12
+ include OpMsgExecutable
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongo
4
+ module Operation
5
+ class DropSearchIndex
6
+ # A MongoDB createSearchIndexes operation sent as an op message.
7
+ #
8
+ # @api private
9
+ class OpMsg < OpMsgBase
10
+ include ExecutableTransactionLabel
11
+
12
+ private
13
+
14
+ # Returns the command to send to the database, describing the
15
+ # desired dropSearchIndex operation.
16
+ #
17
+ # @param [ Mongo::Server ] _server the server that will receive the
18
+ # command
19
+ #
20
+ # @return [ Hash ] the selector
21
+ def selector(_server)
22
+ {
23
+ dropSearchIndex: coll_name,
24
+ :$db => db_name,
25
+ }.tap do |sel|
26
+ sel[:id] = index_id if index_id
27
+ sel[:name] = index_name if index_name
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mongo/operation/drop_search_index/op_msg'
4
+
5
+ module Mongo
6
+ module Operation
7
+ # A MongoDB dropSearchIndex command operation.
8
+ #
9
+ # @api private
10
+ class DropSearchIndex
11
+ include Specifiable
12
+ include OpMsgExecutable
13
+ end
14
+ end
15
+ end
@@ -260,6 +260,13 @@ module Mongo
260
260
  spec[INDEX]
261
261
  end
262
262
 
263
+ # Get the index id from the spec.
264
+ #
265
+ # @return [ String ] The index id.
266
+ def index_id
267
+ spec[:index_id]
268
+ end
269
+
263
270
  # Get the index name from the spec.
264
271
  #
265
272
  # @example Get the index name.
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongo
4
+ module Operation
5
+ class UpdateSearchIndex
6
+ # A MongoDB updateSearchIndex operation sent as an op message.
7
+ #
8
+ # @api private
9
+ class OpMsg < OpMsgBase
10
+ include ExecutableTransactionLabel
11
+
12
+ private
13
+
14
+ # Returns the command to send to the database, describing the
15
+ # desired updateSearchIndex operation.
16
+ #
17
+ # @param [ Mongo::Server ] _server the server that will receive the
18
+ # command
19
+ #
20
+ # @return [ Hash ] the selector
21
+ def selector(_server)
22
+ {
23
+ updateSearchIndex: coll_name,
24
+ :$db => db_name,
25
+ definition: index,
26
+ }.tap do |sel|
27
+ sel[:id] = index_id if index_id
28
+ sel[:name] = index_name if index_name
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mongo/operation/update_search_index/op_msg'
4
+
5
+ module Mongo
6
+ module Operation
7
+ # A MongoDB updateSearchIndex command operation.
8
+ #
9
+ # @api private
10
+ class UpdateSearchIndex
11
+ include Specifiable
12
+ include OpMsgExecutable
13
+ end
14
+ end
15
+ end
@@ -51,6 +51,9 @@ require 'mongo/operation/update_user'
51
51
  require 'mongo/operation/remove_user'
52
52
  require 'mongo/operation/create_index'
53
53
  require 'mongo/operation/drop_index'
54
+ require 'mongo/operation/create_search_indexes'
55
+ require 'mongo/operation/drop_search_index'
56
+ require 'mongo/operation/update_search_index'
54
57
 
55
58
  module Mongo
56
59
 
@@ -0,0 +1,232 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongo
4
+ module SearchIndex
5
+ # A class representing a view of search indexes.
6
+ class View
7
+ include Enumerable
8
+ include Retryable
9
+ include Collection::Helpers
10
+
11
+ # @return [ Mongo::Collection ] the collection this view belongs to
12
+ attr_reader :collection
13
+
14
+ # @return [ nil | String ] the index id to query
15
+ attr_reader :requested_index_id
16
+
17
+ # @return [ nil | String ] the index name to query
18
+ attr_reader :requested_index_name
19
+
20
+ # @return [ Hash ] the options hash to use for the aggregate command
21
+ # when querying the available indexes.
22
+ attr_reader :aggregate_options
23
+
24
+ # Create the new search index view.
25
+ #
26
+ # @param [ Collection ] collection The collection.
27
+ # @param [ Hash ] options The options that configure the behavior of the view.
28
+ #
29
+ # @option options [ String ] :id The specific index id to query (optional)
30
+ # @option options [ String ] :name The name of the specific index to query (optional)
31
+ # @option options [ Hash ] :aggregate The options hash to send to the
32
+ # aggregate command when querying the available indexes.
33
+ def initialize(collection, options = {})
34
+ @collection = collection
35
+ @requested_index_id = options[:id]
36
+ @requested_index_name = options[:name]
37
+ @aggregate_options = options[:aggregate] || {}
38
+
39
+ return if @aggregate_options.is_a?(Hash)
40
+
41
+ raise ArgumentError, "The :aggregate option must be a Hash (got a #{@aggregate_options.class})"
42
+ end
43
+
44
+ # Create a single search index with the given definition. If the name is
45
+ # provided, the new index will be given that name.
46
+ #
47
+ # @param [ Hash ] definition The definition of the search index.
48
+ # @param [ nil | String ] name The name to give the new search index.
49
+ #
50
+ # @return [ String ] the name of the new search index.
51
+ def create_one(definition, name: nil)
52
+ create_many([ { name: name, definition: definition } ]).first
53
+ end
54
+
55
+ # Create multiple search indexes with a single command.
56
+ #
57
+ # @param [ Array<Hash> ] indexes The description of the indexes to
58
+ # create. Each element of the list must be a hash with a definition
59
+ # key, and an optional name key.
60
+ #
61
+ # @return [ Array<String> ] the names of the new search indexes.
62
+ def create_many(indexes)
63
+ spec = spec_with(indexes: indexes.map { |v| validate_search_index!(v) })
64
+ result = Operation::CreateSearchIndexes.new(spec).execute(next_primary, context: execution_context)
65
+ result.first['indexesCreated'].map { |idx| idx['name'] }
66
+ end
67
+
68
+ # Drop the search index with the given id, or name. One or the other must
69
+ # be specified, but not both.
70
+ #
71
+ # @param [ String ] id the id of the index to drop
72
+ # @param [ String ] name the name of the index to drop
73
+ #
74
+ # @return [ Mongo::Operation::Result | false ] the result of the
75
+ # operation, or false if the given index does not exist.
76
+ def drop_one(id: nil, name: nil)
77
+ validate_id_or_name!(id, name)
78
+
79
+ spec = spec_with(index_id: id, index_name: name)
80
+ op = Operation::DropSearchIndex.new(spec)
81
+
82
+ # per the spec:
83
+ # Drivers MUST suppress NamespaceNotFound errors for the
84
+ # ``dropSearchIndex`` helper. Drop operations should be idempotent.
85
+ do_drop(op, nil, execution_context)
86
+ end
87
+
88
+ # Iterate over the search indexes.
89
+ #
90
+ # @param [ Proc ] block if given, each search index will be yieleded to
91
+ # the block.
92
+ #
93
+ # @return [ self | Enumerator ] if a block is given, self is returned.
94
+ # Otherwise, an enumerator will be returned.
95
+ def each(&block)
96
+ @result ||= begin
97
+ spec = {}.tap do |s|
98
+ s[:id] = requested_index_id if requested_index_id
99
+ s[:name] = requested_index_name if requested_index_name
100
+ end
101
+
102
+ collection.aggregate(
103
+ [ { '$listSearchIndexes' => spec } ],
104
+ aggregate_options
105
+ )
106
+ end
107
+
108
+ return @result.to_enum unless block
109
+
110
+ @result.each(&block)
111
+ self
112
+ end
113
+
114
+ # Update the search index with the given id or name. One or the other
115
+ # must be provided, but not both.
116
+ #
117
+ # @param [ Hash ] definition the definition to replace the given search
118
+ # index with.
119
+ # @param [ nil | String ] id the id of the search index to update
120
+ # @param [ nil | String ] name the name of the search index to update
121
+ #
122
+ # @return [ Mongo::Operation::Result ] the result of the operation
123
+ def update_one(definition, id: nil, name: nil)
124
+ validate_id_or_name!(id, name)
125
+
126
+ spec = spec_with(index_id: id, index_name: name, index: definition)
127
+ Operation::UpdateSearchIndex.new(spec).execute(next_primary, context: execution_context)
128
+ end
129
+
130
+ # The following methods are to make the view act more like an array,
131
+ # without having to explicitly make it an array...
132
+
133
+ # Queries whether the search index enumerable is empty.
134
+ #
135
+ # @return [ true | false ] whether the enumerable is empty or not.
136
+ def empty?
137
+ count.zero?
138
+ end
139
+
140
+ private
141
+
142
+ # A helper method for building the specification document with certain
143
+ # values pre-populated.
144
+ #
145
+ # @param [ Hash ] extras the values to put into the specification
146
+ #
147
+ # @return [ Hash ] the specification document
148
+ def spec_with(extras)
149
+ {
150
+ coll_name: collection.name,
151
+ db_name: collection.database.name,
152
+ }.merge(extras)
153
+ end
154
+
155
+ # A helper method for retrieving the primary server from the cluster.
156
+ #
157
+ # @return [ Mongo::Server ] the server to use
158
+ def next_primary(ping = nil, session = nil)
159
+ collection.cluster.next_primary(ping, session)
160
+ end
161
+
162
+ # A helper method for constructing a new operation context for executing
163
+ # an operation.
164
+ #
165
+ # @return [ Mongo::Operation::Context ] the operation context
166
+ def execution_context
167
+ Operation::Context.new(client: collection.client)
168
+ end
169
+
170
+ # Validates the given id and name, ensuring that exactly one of them
171
+ # is non-nil.
172
+ #
173
+ # @param [ nil | String ] id the id to validate
174
+ # @param [ nil | String ] name the name to validate
175
+ #
176
+ # @raise [ ArgumentError ] if neither or both arguments are nil
177
+ def validate_id_or_name!(id, name)
178
+ return unless (id.nil? && name.nil?) || (!id.nil? && !name.nil?)
179
+
180
+ raise ArgumentError, 'exactly one of id or name must be specified'
181
+ end
182
+
183
+ # Validates the given search index document, ensuring that it has no
184
+ # extra keys, and that the name and definition are valid.
185
+ #
186
+ # @param [ Hash ] doc the document to validate
187
+ #
188
+ # @raise [ ArgumentError ] if the document is invalid.
189
+ def validate_search_index!(doc)
190
+ validate_search_index_keys!(doc.keys)
191
+ validate_search_index_name!(doc[:name] || doc['name'])
192
+ validate_search_index_definition!(doc[:definition] || doc['definition'])
193
+ doc
194
+ end
195
+
196
+ # Validates the keys of a search index document, ensuring that
197
+ # they are all valid.
198
+ #
199
+ # @param [ Array<String | Hash> ] keys the keys of a search index document
200
+ #
201
+ # @raise [ ArgumentError ] if the list contains any invalid keys
202
+ def validate_search_index_keys!(keys)
203
+ extras = keys - [ 'name', 'definition', :name, :definition ]
204
+
205
+ raise ArgumentError, "invalid keys in search index creation: #{extras.inspect}" if extras.any?
206
+ end
207
+
208
+ # Validates the name of a search index, ensuring that it is either a
209
+ # String or nil.
210
+ #
211
+ # @param [ nil | String ] name the name of a search index
212
+ #
213
+ # @raise [ ArgumentError ] if the name is not valid
214
+ def validate_search_index_name!(name)
215
+ return if name.nil? || name.is_a?(String)
216
+
217
+ raise ArgumentError, "search index name must be nil or a string (got #{name.inspect})"
218
+ end
219
+
220
+ # Validates the definition of a search index.
221
+ #
222
+ # @param [ Hash ] definition the definition of a search index
223
+ #
224
+ # @raise [ ArgumentError ] if the definition is not valid
225
+ def validate_search_index_definition!(definition)
226
+ return if definition.is_a?(Hash)
227
+
228
+ raise ArgumentError, "search index definition must be a Hash (got #{definition.inspect})"
229
+ end
230
+ end
231
+ end
232
+ end
data/lib/mongo/version.rb CHANGED
@@ -20,5 +20,5 @@ module Mongo
20
20
  # The current version of the driver.
21
21
  #
22
22
  # @since 2.0.0
23
- VERSION = '2.19.1'.freeze
23
+ VERSION = '2.19.3'.freeze
24
24
  end
data/lib/mongo.rb CHANGED
@@ -64,6 +64,7 @@ require 'mongo/client_encryption'
64
64
  require 'mongo/dbref'
65
65
  require 'mongo/grid'
66
66
  require 'mongo/index'
67
+ require 'mongo/search_index/view'
67
68
  require 'mongo/lint'
68
69
  require 'mongo/query_cache'
69
70
  require 'mongo/server'
@@ -7,11 +7,7 @@ describe 'Atlas connectivity' do
7
7
  let(:uri) { ENV['ATLAS_URI'] }
8
8
  let(:client) { Mongo::Client.new(uri) }
9
9
 
10
- before do
11
- if uri.nil?
12
- skip "ATLAS_URI not set in environment"
13
- end
14
- end
10
+ require_atlas
15
11
 
16
12
  describe 'connection to Atlas' do
17
13
  it 'runs ismaster successfully' do
@@ -7,11 +7,7 @@ describe 'Operations' do
7
7
  let(:uri) { ENV['ATLAS_URI'] }
8
8
  let(:client) { Mongo::Client.new(uri) }
9
9
 
10
- before do
11
- if uri.nil?
12
- skip "ATLAS_URI not set in environment"
13
- end
14
- end
10
+ require_atlas
15
11
 
16
12
  describe 'ping' do
17
13
  it 'works' do