diff --git a/.travis.yml b/.travis.yml index 3cbab23e3c..99fb99af96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,12 @@ language: ruby -services: mongodb - bundler_args: --without development rvm: - 1.9.3 - 2.0.0 - - 2.1 - - 2.2 + - 2.1.5 + - 2.2.0 - jruby gemfile: @@ -16,9 +14,20 @@ gemfile: - gemfiles/rails41.gemfile - gemfiles/rails42.gemfile -env: JRUBY_OPTS="--server -J-Xms512m -J-Xmx1024m" +env: + global: + - CI="travis" + - JRUBY_OPTS="--server -J-Xms512m -J-Xmx1024m" + matrix: + - MONGODB=2.4.14 + - MONGODB=2.6.10 + - MONGODB=3.0.3 -sudo: false +before_script: + - wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-${MONGODB}.tgz -O /tmp/mongodb.tgz + - tar -xvf /tmp/mongodb.tgz + - mkdir /tmp/data + - ${PWD}/mongodb-linux-x86_64-${MONGODB}/bin/mongod --dbpath /tmp/data --bind_ip 127.0.0.1 --auth &> /dev/null & notifications: email: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 73d174aafa..b92228eda8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,19 @@ For instructions on upgrading to newer versions, visit [mongoid.org](http://mongoid.org/en/mongoid/docs/upgrading.html). -## 4.0.3 - Not released +## 5.0.0 - Not released + +### Major Changes (Backwards Incompatible) + +* Mongoid now uses the official Mongo Ruby Driver 2.x instead of Moped. + +* Most driver specific configuration options have changed, please see [here](http://docs.mongodb.org/ecosystem/tutorial/ruby-driver-tutorial/#ruby-options) for the new options. + +* `find_and_modify` has been removed and replaced with 3 options: `find_one_and_update`, `find_one_and_delete` and `find_one_and_replace`. + +* `text_search` has been removed as it is now a `$text` option in a query from 2.6 on. + +* Mongoid no longer supports MongoDB 2.2 - support is now for only 2.4 and higher. ### New Features diff --git a/Gemfile b/Gemfile index efe47aff3b..de0ff3fbf8 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,5 @@ source "https://rubygems.org" + gemspec gem "rake" diff --git a/gemfiles/rails41.gemfile b/gemfiles/rails41.gemfile index 0fe69f4c48..7b076e9003 100644 --- a/gemfiles/rails41.gemfile +++ b/gemfiles/rails41.gemfile @@ -1,6 +1,7 @@ source "https://rubygems.org" gemspec path: '..' +gem "mongo", :github => "mongodb/mongo-ruby-driver" gem "rake" gem "actionpack", "~> 4.1.8" gem "activemodel", "~> 4.1.8" diff --git a/gemfiles/rails42.gemfile b/gemfiles/rails42.gemfile index d29c3433b7..24b146438e 100644 --- a/gemfiles/rails42.gemfile +++ b/gemfiles/rails42.gemfile @@ -1,6 +1,7 @@ source "https://rubygems.org" gemspec path: '..' +gem "mongo", :github => "mongodb/mongo-ruby-driver" gem "rake" gem "actionpack", "~> 4.2.0" gem "activemodel", "~> 4.2.0" diff --git a/lib/mongoid.rb b/lib/mongoid.rb index befb3a0806..88da6e0f41 100644 --- a/lib/mongoid.rb +++ b/lib/mongoid.rb @@ -13,14 +13,13 @@ require "active_model" require "origin" -require "moped" +require "mongo" require "mongoid/version" require "mongoid/config" require "mongoid/loggable" require "mongoid/sessions" require "mongoid/document" -require "mongoid/log_subscriber" require "mongoid/tasks/database" require "mongoid/query_cache" diff --git a/lib/mongoid/config.rb b/lib/mongoid/config.rb index 088c7746ff..09e2377e56 100644 --- a/lib/mongoid/config.rb +++ b/lib/mongoid/config.rb @@ -48,7 +48,7 @@ def configured? # @param [ String ] name The database name. # # @since 3.0.0 - def connect_to(name, options = { read: :primary }) + def connect_to(name, options = { read: { mode: :primary }}) self.sessions = { default: { database: name, @@ -169,7 +169,7 @@ def override_session(name) # # @since 2.0.2 def purge! - Sessions.default.collections.each(&:drop) and true + Sessions.default.database.collections.each(&:drop) and true end # Truncate all data in all collections, but not the indexes. @@ -183,8 +183,8 @@ def purge! # # @since 2.0.2 def truncate! - Sessions.default.collections.each do |collection| - collection.find.remove_all + Sessions.default.database.collections.each do |collection| + collection.find.delete_many end and true end @@ -217,22 +217,6 @@ def sessions @sessions ||= {} end - # Set the session configuration options. - # - # @example Set the session configuration options. - # config.sessions = { default: { hosts: [ "localhost:27017" ] }} - # - # @param [ Hash ] sessions The configuration options. - # - # @since 3.0.0 - def sessions=(sessions) - raise Errors::NoSessionsConfig.new unless sessions - sess = sessions.with_indifferent_access - Validators::Session.validate(sess) - @sessions = sess - sess - end - # Get the time zone to use. # # @example Get the time zone. @@ -256,5 +240,15 @@ def time_zone def running_with_passenger? @running_with_passenger ||= defined?(PhusionPassenger) end + + private + + def sessions=(sessions) + raise Errors::NoSessionsConfig.new unless sessions + sess = sessions.with_indifferent_access + Validators::Session.validate(sess) + @sessions = sess + sess + end end end diff --git a/lib/mongoid/contextual/aggregable/mongo.rb b/lib/mongoid/contextual/aggregable/mongo.rb index 5ad601974c..560602fbee 100644 --- a/lib/mongoid/contextual/aggregable/mongo.rb +++ b/lib/mongoid/contextual/aggregable/mongo.rb @@ -23,7 +23,7 @@ module Mongo # # @since 3.0.0 def aggregates(field) - result = collection.aggregate(pipeline(field)).to_a + result = collection.find.aggregate(pipeline(field)).to_a if result.empty? { "count" => 0, "sum" => nil, "avg" => nil, "min" => nil, "max" => nil } else diff --git a/lib/mongoid/contextual/atomic.rb b/lib/mongoid/contextual/atomic.rb index 31c073cc1b..b859867798 100644 --- a/lib/mongoid/contextual/atomic.rb +++ b/lib/mongoid/contextual/atomic.rb @@ -14,7 +14,7 @@ module Atomic # # @since 3.0.0 def add_to_set(adds) - query.update_all("$addToSet" => collect_operations(adds)) + view.update_many("$addToSet" => collect_operations(adds)) end # Perform an atomic $bit operation on the matching documents. @@ -28,7 +28,7 @@ def add_to_set(adds) # # @since 3.0.0 def bit(bits) - query.update_all("$bit" => collect_operations(bits)) + view.update_many("$bit" => collect_operations(bits)) end # Perform an atomic $inc operation on the matching documents. @@ -42,7 +42,7 @@ def bit(bits) # # @since 3.0.0 def inc(incs) - query.update_all("$inc" => collect_operations(incs)) + view.update_many("$inc" => collect_operations(incs)) end # Perform an atomic $pop operation on the matching documents. @@ -59,7 +59,7 @@ def inc(incs) # # @since 3.0.0 def pop(pops) - query.update_all("$pop" => collect_operations(pops)) + view.update_many("$pop" => collect_operations(pops)) end # Perform an atomic $pull operation on the matching documents. @@ -75,7 +75,7 @@ def pop(pops) # # @since 3.0.0 def pull(pulls) - query.update_all("$pull" => collect_operations(pulls)) + view.update_many("$pull" => collect_operations(pulls)) end # Perform an atomic $pullAll operation on the matching documents. @@ -89,7 +89,7 @@ def pull(pulls) # # @since 3.0.0 def pull_all(pulls) - query.update_all("$pullAll" => collect_operations(pulls)) + view.update_many("$pullAll" => collect_operations(pulls)) end # Perform an atomic $push operation on the matching documents. @@ -103,7 +103,7 @@ def pull_all(pulls) # # @since 3.0.0 def push(pushes) - query.update_all("$push" => collect_operations(pushes)) + view.update_many("$push" => collect_operations(pushes)) end # Perform an atomic $pushAll operation on the matching documents. @@ -117,7 +117,7 @@ def push(pushes) # # @since 3.0.0 def push_all(pushes) - query.update_all("$pushAll" => collect_operations(pushes)) + view.update_many("$pushAll" => collect_operations(pushes)) end # Perform an atomic $rename of fields on the matching documents. @@ -135,7 +135,7 @@ def rename(renames) ops[old_name] = new_name.to_s ops end - query.update_all("$rename" => collect_operations(operations)) + view.update_many("$rename" => collect_operations(operations)) end # Perform an atomic $set of fields on the matching documents. @@ -149,7 +149,7 @@ def rename(renames) # # @since 3.0.0 def set(sets) - query.update_all("$set" => collect_operations(sets)) + view.update_many("$set" => collect_operations(sets)) end # Perform an atomic $unset of a field on the matching documents. @@ -164,7 +164,7 @@ def set(sets) # @since 3.0.0 def unset(*args) fields = args.__find_args__.collect { |f| [database_field_name(f), true] } - query.update_all("$unset" => Hash[fields]) + view.update_many("$unset" => Hash[fields]) end private diff --git a/lib/mongoid/contextual/command.rb b/lib/mongoid/contextual/command.rb index 209274149e..2246ace93c 100644 --- a/lib/mongoid/contextual/command.rb +++ b/lib/mongoid/contextual/command.rb @@ -28,7 +28,7 @@ def command # # @since 3.0.0 def session - collection.database.session + collection.database.client end end end diff --git a/lib/mongoid/contextual/find_and_modify.rb b/lib/mongoid/contextual/find_and_modify.rb deleted file mode 100644 index b0e71cd288..0000000000 --- a/lib/mongoid/contextual/find_and_modify.rb +++ /dev/null @@ -1,69 +0,0 @@ -# encoding: utf-8 -module Mongoid - module Contextual - class FindAndModify - include Command - - # @attribute [r] criteria The criteria for the context. - # @attribute [r] options The command options. - # @attribute [r] update The updates. - # @attribute [r] query The Moped query. - attr_reader :criteria, :options, :update, :query - - # Initialize the find and modify command, used for MongoDB's - # $findAndModify. - # - # @example Initialize the command. - # FindAndModify.new(criteria, { "$set" => { likes: 1 }}) - # - # @param [ Criteria ] criteria The criteria. - # @param [ Hash ] update The updates. - # @param [ Hash ] options The command options. - # - # @option options [ true, false ] :new Return the updated document. - # @option options [ true, false ] :remove Delete the first document. - # @option options [ true, false ] :upsert Create the document if it doesn't exist. - # - # @since 3.0.0 - def initialize(collection, criteria, update, options = {}) - @collection, @criteria, @options, @update = - collection, criteria, options, update.mongoize - @query = collection.find(criteria.selector) - apply_criteria_options - end - - # Get the result of the $findAndModify. - # - # @example Get the result. - # find_and_modify.result - # - # @return [ Hash ] The result of the command. - # - # @since 3.0.0 - def result - query.modify(update, options) - end - - private - - # Apply criteria specific options - query, sort, fields. - # - # @api private - # - # @example Apply the criteria options - # find_and_modify.apply_criteria_options - # - # @return [ nil ] Nothing. - # - # @since 3.0.0 - def apply_criteria_options - if spec = criteria.options[:sort] - query.sort(spec) - end - if spec = criteria.options[:fields] - query.select(spec) - end - end - end - end -end diff --git a/lib/mongoid/contextual/geo_near.rb b/lib/mongoid/contextual/geo_near.rb index c6c510db29..f94e5bb0d0 100644 --- a/lib/mongoid/contextual/geo_near.rb +++ b/lib/mongoid/contextual/geo_near.rb @@ -246,7 +246,7 @@ def documents # # @since 3.0.0 def results - @results ||= session.command(command) + @results ||= session.command(command).first end end end diff --git a/lib/mongoid/contextual/map_reduce.rb b/lib/mongoid/contextual/map_reduce.rb index a0da1d46fb..29ebd2853b 100644 --- a/lib/mongoid/contextual/map_reduce.rb +++ b/lib/mongoid/contextual/map_reduce.rb @@ -268,9 +268,9 @@ def apply_criteria_options # @since 3.0.0 def documents return results["results"] if results.has_key?("results") - query = session[output_collection].find - query.no_timeout if criteria.options[:timeout] == false - query + view = session[output_collection].find + view.no_cursor_timeout if criteria.options[:timeout] == false + view end # Get the collection that the map/reduce results were stored in. @@ -299,7 +299,7 @@ def output_collection # @since 3.0.0 def results raise Errors::NoMapReduceOutput.new(command) unless command[:out] - @results ||= __session__.command(command) + @results ||= __session__.command(command).first end # Get the session with the proper consistency. @@ -316,7 +316,7 @@ def results # @since 3.0.15 def __session__ if command[:out][:inline] != 1 - session.with(read: :primary) + session.with(read: { mode: :primary }) else session end diff --git a/lib/mongoid/contextual/memory.rb b/lib/mongoid/contextual/memory.rb index 835152cdc2..27be890b57 100644 --- a/lib/mongoid/contextual/memory.rb +++ b/lib/mongoid/contextual/memory.rb @@ -47,7 +47,7 @@ def delete doc.as_document end unless removed.empty? - collection.find(selector).update( + collection.find(selector).update_one( positionally(selector, "$pullAll" => { path => removed }) ) end @@ -307,7 +307,7 @@ def update_documents(attributes, docs) updates["$set"].merge!(doc.atomic_updates["$set"] || {}) doc.move_changes end - collection.find(selector).update(updates) unless updates["$set"].empty? + collection.find(selector).update_one(updates) unless updates["$set"].empty? end # Get the limiting value. diff --git a/lib/mongoid/contextual/mongo.rb b/lib/mongoid/contextual/mongo.rb index 57bb1509ab..6e6e8c93d4 100644 --- a/lib/mongoid/contextual/mongo.rb +++ b/lib/mongoid/contextual/mongo.rb @@ -2,10 +2,8 @@ require "mongoid/contextual/atomic" require "mongoid/contextual/aggregable/mongo" require "mongoid/contextual/command" -require "mongoid/contextual/find_and_modify" require "mongoid/contextual/geo_near" require "mongoid/contextual/map_reduce" -require "mongoid/contextual/text_search" require "mongoid/relations/eager" module Mongoid @@ -17,8 +15,8 @@ class Mongo include Relations::Eager include Queryable - # @attribute [r] query The Moped query. - attr_reader :query + # @attribute [r] view The Mongo collection view. + attr_reader :view # Is the context cached? # @@ -37,27 +35,23 @@ def cached? # @example Get the number of matching documents. # context.count # - # @example Get the count of documents matching the provided. - # context.count(document) + # @example Get the count of documents with the provided options. + # context.count(limit: 1) # # @example Get the count for where the provided block is true. # context.count do |doc| # doc.likes > 1 # end # - # @param [ Document ] document A document to match or true if wanting - # skip and limit to be factored into the count. + # @param [ Hash ] options The options, such as skip and limit to be factored + # into the count. # # @return [ Integer ] The number of matches. # # @since 3.0.0 - def count(document = false, &block) + def count(options = {}, &block) return super(&block) if block_given? - if document.is_a?(Document) - return collection.find(criteria.and(_id: document._id).selector).count - end - return query.count(document) if document - try_cache(:count) { query.count } + try_cache(:count) { view.count(options) } end # Delete all documents in the database that match the selector. @@ -70,7 +64,7 @@ def count(document = false, &block) # @since 3.0.0 def delete self.count.tap do - query.remove_all + view.delete_many end end alias :delete_all :delete @@ -103,7 +97,7 @@ def destroy # # @since 3.0.0 def distinct(field) - query.distinct(klass.database_field_name(field)) + view.distinct(klass.database_field_name(field)) end # Iterate over the context. If provided a block, yield to a Mongoid @@ -146,7 +140,7 @@ def exists? return @count > 0 if instance_variable_defined?(:@count) try_cache(:exists) do - !!(query.dup.select(_id: 1).limit(1).first) + !!(view.projection(_id: 1).limit(1).first) end end @@ -159,28 +153,65 @@ def exists? # # @since 3.0.0 def explain - query.explain + view.explain end # Execute the find and modify command, used for MongoDB's # $findAndModify. # # @example Execute the command. - # context.find_and_modify({ "$inc" => { likes: 1 }}, new: true) + # context.find_one_and_update({ "$inc" => { likes: 1 }}) # # @param [ Hash ] update The updates. # @param [ Hash ] options The command options. # - # @option options [ true, false ] :new Return the updated document. - # @option options [ true, false ] :remove Delete the first document. + # @option options [ :before, :after ] :return_document Return the updated document + # from before or after update. # @option options [ true, false ] :upsert Create the document if it doesn't exist. # # @return [ Document ] The result of the command. # - # @since 3.0.0 - def find_and_modify(update, options = {}) - if doc = FindAndModify.new(collection, criteria, update, options).result - Factory.from_db(klass, doc) if doc.any? + # @since 5.0.0 + def find_one_and_update(update, options = {}) + if doc = view.find_one_and_update(update, options) + Factory.from_db(klass, doc) + end + end + + # Execute the find and modify command, used for MongoDB's + # $findAndModify. + # + # @example Execute the command. + # context.find_one_and_update({ likes: 1 }) + # + # @param [ Hash ] update The updates. + # @param [ Hash ] options The command options. + # + # @option options [ :before, :after ] :return_document Return the updated document + # from before or after update. + # @option options [ true, false ] :upsert Create the document if it doesn't exist. + # + # @return [ Document ] The result of the command. + # + # @since 5.0.0 + def find_one_and_replace(replacement, options = {}) + if doc = view.find_one_and_replace(replacement, options) + Factory.from_db(klass, doc) + end + end + + # Execute the find and modify command, used for MongoDB's + # $findAndModify. This deletes the found document. + # + # @example Execute the command. + # context.find_one_and_delete + # + # @return [ Document ] The result of the command. + # + # @since 5.0.0 + def find_one_and_delete + if doc = view.find_one_and_delete + Factory.from_db(klass, doc) end end @@ -196,7 +227,7 @@ def first return documents.first if cached? && cache_loaded? try_cache(:first) do with_sorting do - with_eager_loading(query.first) + with_eager_loading(view.first) end end end @@ -209,7 +240,7 @@ def first # @since 4.0.2 def find_first return documents.first if cached? && cache_loaded? - with_eager_loading(query.first) + with_eager_loading(view.first) end # Execute a $geoNear command against the database. @@ -272,7 +303,7 @@ def initialize(criteria) @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache] @collection = @klass.with(criteria.persistence_options || {}).collection criteria.send(:merge_type_selection) - @query = collection.find(criteria.selector) + @view = collection.find(criteria.selector) apply_options end @@ -289,7 +320,7 @@ def initialize(criteria) def last try_cache(:last) do with_inverse_sorting do - with_eager_loading(query.first) + with_eager_loading(view.first) end end end @@ -318,7 +349,7 @@ def length # # @since 3.0.0 def limit(value) - query.limit(value) and self + @view = view.limit(value) and self end # Initiate a map/reduce operation from the context. @@ -356,7 +387,7 @@ def pluck(*fields) hash end - query.dup.select(normalized_select).map do |doc| + view.projection(normalized_select).map do |doc| if normalized_select.size == 1 doc[normalized_select.keys.first] else @@ -376,7 +407,7 @@ def pluck(*fields) # # @since 3.0.0 def skip(value) - query.skip(value) and self + @view = view.skip(value) and self end # Sorts the documents by the provided spec. @@ -401,20 +432,6 @@ def sort(values = nil, &block) end end - # Execute a text command against the database. - # - # @example Find documents with the text "phase" - # context.text_search("phase") - # - # @param [ String ] query The text search query. - # - # @return [ TextSearch ] The TextSearch command. - # - # @since 4.0.0 - def text_search(query) - TextSearch.new(collection, criteria, query) - end - # Update the first matching document atomically. # # @example Update the first matching document. @@ -440,7 +457,7 @@ def update(attributes = nil) # # @since 3.0.0 def update_all(attributes = nil) - update_documents(attributes, :update_all) + update_documents(attributes, :update_many) end private @@ -476,10 +493,10 @@ def try_cache(key, &block) # @return [ true, false ] If the update succeeded. # # @since 3.0.4 - def update_documents(attributes, method = :update) + def update_documents(attributes, method = :update_one) return false unless attributes attributes = Hash[attributes.map { |k, v| [klass.database_field_name(k.to_s), v] }] - query.send(method, attributes.__consolidate__(klass)) + view.send(method, attributes.__consolidate__(klass)) end # Apply the field limitations. @@ -492,7 +509,7 @@ def update_documents(attributes, method = :update) # @since 3.0.0 def apply_fields if spec = criteria.options[:fields] - query.select(spec) + @view = view.projection(spec) end end @@ -510,7 +527,7 @@ def apply_options apply_option(name) end if criteria.options[:timeout] == false - query.no_timeout + @view = view.no_cursor_timeout end end @@ -524,7 +541,7 @@ def apply_options # @since 3.1.0 def apply_option(name) if spec = criteria.options[name] - query.send(name, spec) + @view = view.send(name, spec) end end @@ -540,7 +557,7 @@ def apply_option(name) def with_sorting begin unless criteria.options.has_key?(:sort) - query.sort(_id: 1) + @view = view.sort(_id: 1) end yield ensure @@ -559,9 +576,9 @@ def with_sorting def with_inverse_sorting begin if spec = criteria.options[:sort] - query.sort(Hash[spec.map{|k, v| [k, -1*v]}]) + @view = view.sort(Hash[spec.map{|k, v| [k, -1*v]}]) else - query.sort(_id: -1) + @view = view.sort(_id: -1) end yield ensure @@ -632,11 +649,11 @@ def documents_for_iteration if cached? && !documents.empty? documents elsif eager_loadable? - docs = query.map{ |doc| Factory.from_db(klass, doc, criteria.options[:fields]) } + docs = view.map{ |doc| Factory.from_db(klass, doc, criteria.options[:fields]) } eager_load(docs) docs else - query + view end end diff --git a/lib/mongoid/contextual/text_search.rb b/lib/mongoid/contextual/text_search.rb deleted file mode 100644 index 1e5677118b..0000000000 --- a/lib/mongoid/contextual/text_search.rb +++ /dev/null @@ -1,178 +0,0 @@ -# encoding: utf-8 -module Mongoid - module Contextual - - # Wraps behaviour around a lazy text search command. - # - # @since 4.0.0 - class TextSearch - include Enumerable - include Command - - delegate :[], to: :results - delegate :==, :empty?, to: :entries - - # Iterate over the results of the text search command. - # - # @example Iterate over the results. - # text_search.each do |doc| - # #... - # end - # - # @return [ Enumerator ] The enumerator. - # - # @since 4.0.0 - def each - if block_given? - documents.each do |doc| - yield doc - end - else - to_enum - end - end - - # Instantiate a new text search lazy proxy. - # - # @example Instantiate the text search. - # TextSearch.new(collection, criteria, "test") - # - # @param [ Moped::Collection ] collection The collection to execute on. - # @param [ Criteria ] criteria The criteria to filter results. - # @param [ String ] search_string The search string. - # - # @since 4.0.0 - def initialize(collection, criteria, search_string) - @collection, @criteria = collection, criteria - command[:text] = collection.name.to_s - command[:search] = search_string - apply_criteria_options - end - - # Inspect the text search object. - # - # @example Inspect the text search. - # text_search.inspect - # - # @return [ String ] The inspection. - # - # @since 4.0.0 - def inspect -%Q{# -} - end - - # Execute the text search command, and return the raw results (in hash - # form). - # - # @example Execute the command. - # text_search.execute - # - # @return [ Hash ] The raw results. - # - # @since 4.0.0 - def execute - results - end - - # Set the language of the text search. - # - # @example Set the text search language. - # text_search.language("deutsch") - # - # @param [ String ] value The name of the language. - # - # @return [ TextSearch ] The modified text search. - # - # @since 4.0.0 - def language(value) - command[:language] = value - self - end - - # Limits the fields returned by the text search for each document. By - # default, _id is always included. - # - # @example Limit the returned fields. - # text_search.project(name: 1, title: 1) - # - # @param [ Hash ] value The fields to project. - # - # @return [ TextSearch ] The modified text search. - # - # @since 4.0.0 - def project(value) - command[:project] = value - self - end - - # Get the raw statistics returned from the text search. - # - # @example Get the stats. - # text_search.stats - # - # @return [ Hash ] The raw statistics. - # - # @since 4.0.0 - def stats - results["stats"] - end - - private - - # Apply the options from the criteria to the text search command. - # - # @api private - # - # @example Apply the criteria options, filter and limit only. - # text_search.apply_criteria_options - # - # @return [ nil ] Nothing. - # - # @since 4.0.0 - def apply_criteria_options - command[:filter] = criteria.selector - if limit = criteria.options[:limit] - command[:limit] = limit - end - end - - # Get the results of the text search as documents. - # - # @api private - # - # @example Get the results as documents. - # text_search.documents - # - # @return [ Array ] The documents. - # - # @since 4.0.0 - def documents - results["results"].map do |attributes| - Factory.from_db(criteria.klass, attributes["obj"], command[:project]) - end - end - - # Get the raw results. - # - # @api private - # - # @example Get the raw results. - # text_search.results - # - # @return [ Hash ] The raw results. - # - # @since 4.0.0 - def results - @results ||= session.command(command) - end - end - end -end diff --git a/lib/mongoid/findable.rb b/lib/mongoid/findable.rb index 824c33200b..02657e6884 100644 --- a/lib/mongoid/findable.rb +++ b/lib/mongoid/findable.rb @@ -19,7 +19,9 @@ module Findable :each, :each_with_index, :extras, - :find_and_modify, + :find_one_and_delete, + :find_one_and_replace, + :find_one_and_update, :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, diff --git a/lib/mongoid/indexable.rb b/lib/mongoid/indexable.rb index dc0af6b977..a6c1c6d883 100644 --- a/lib/mongoid/indexable.rb +++ b/lib/mongoid/indexable.rb @@ -31,10 +31,10 @@ def create_indexes index_specifications.each do |spec| key, options = spec.key, spec.options if database = options[:database] - with(read: :primary, database: database). - collection.indexes.create(key, options.except(:database)) + with(read: { mode: :primary }, database: database). + collection.indexes.create_one(key, options.except(:database)) else - with(read: :primary).collection.indexes.create(key, options) + with(read: { mode: :primary }).collection.indexes.create_one(key, options) end end and true end @@ -50,12 +50,14 @@ def create_indexes # @since 3.0.0 def remove_indexes indexed_database_names.each do |database| - collection = with(read: :primary, database: database).collection - collection.indexes.each do |spec| - unless spec["name"] == "_id_" - collection.indexes.drop(spec["key"]) + collection = with(read: { mode: :primary }, database: database).collection + begin + collection.indexes.each do |spec| + unless spec["name"] == "_id_" + collection.indexes.drop_one(spec["key"]) + end end - end + rescue Mongo::Error::OperationFailure; end end and true end diff --git a/lib/mongoid/log_subscriber.rb b/lib/mongoid/log_subscriber.rb deleted file mode 100644 index 9493da2dc9..0000000000 --- a/lib/mongoid/log_subscriber.rb +++ /dev/null @@ -1,55 +0,0 @@ -# encoding: utf-8 -module Mongoid - # A Log subscriber to the moped queries - # - # @since 4.0.0 - class LogSubscriber < ActiveSupport::LogSubscriber - - # Log the query operation on moped - # - # @since 4.0.0 - def query(event) - return unless logger.debug? - - payload = event.payload - runtime = ("%.4fms" % event.duration) - debug(payload[:prefix], payload[:ops], runtime) - end - - def query_cache(event) - return unless logger.debug? - - database, collection, selector = event.payload[:key] - operation = "%-12s database=%s collection=%s selector=%s" % ["QUERY CACHE", database, collection, selector.inspect] - logger.debug operation - end - # Log the provided operations. - # - # @example Delegates the operation to moped so it can log it. - # subscriber.debug("MOPED", {}, 30) - # - # @param [ String ] prefix The prefix for all operations in the log. - # @param [ Array ] ops The operations. - # @param [ String ] runtime The runtime in formatted ms. - # - # @since 4.0.0 - def debug(prefix, operations, runtime) - Moped::Loggable.log_operations(prefix, operations, runtime) - end - - # Get the logger. - # - # @example Get the logger. - # subscriber.logger - # - # @return [ Logger ] The logger. - # - # @since 4.0.0 - def logger - Moped.logger - end - end -end - -Mongoid::LogSubscriber.attach_to :moped -Mongoid::LogSubscriber.attach_to :mongoid diff --git a/lib/mongoid/persistable.rb b/lib/mongoid/persistable.rb index a846b87025..16e52ddcd6 100644 --- a/lib/mongoid/persistable.rb +++ b/lib/mongoid/persistable.rb @@ -209,7 +209,7 @@ def persist_or_delay_atomic_operation(operation) def persist_atomic_operations(operations) if persisted? selector = atomic_selector - _root.collection.find(selector).update(positionally(selector, operations)) + _root.collection.find(selector).update_one(positionally(selector, operations)) end end end diff --git a/lib/mongoid/persistable/creatable.rb b/lib/mongoid/persistable/creatable.rb index 1d5501753e..afbe23c780 100644 --- a/lib/mongoid/persistable/creatable.rb +++ b/lib/mongoid/persistable/creatable.rb @@ -61,7 +61,7 @@ def insert_as_embedded _parent.insert else selector = _parent.atomic_selector - _root.collection.find(selector).update(positionally(selector, atomic_inserts)) + _root.collection.find(selector).update_one(positionally(selector, atomic_inserts)) end end @@ -76,7 +76,7 @@ def insert_as_embedded # # @since 4.0.0 def insert_as_root - collection.insert(as_document) + collection.insert_one(as_document) end # Post process an insert, which sets the new record attribute to false diff --git a/lib/mongoid/persistable/deletable.rb b/lib/mongoid/persistable/deletable.rb index 1f58ca3d0f..cd227f8763 100644 --- a/lib/mongoid/persistable/deletable.rb +++ b/lib/mongoid/persistable/deletable.rb @@ -62,7 +62,7 @@ def delete_as_embedded(options = {}) _parent.remove_child(self) if notifying_parent?(options) if _parent.persisted? selector = _parent.atomic_selector - _root.collection.find(selector).update(positionally(selector, atomic_deletes)) + _root.collection.find(selector).update_one(positionally(selector, atomic_deletes)) end true end @@ -78,7 +78,7 @@ def delete_as_embedded(options = {}) # # @since 4.0.0 def delete_as_root - collection.find(atomic_selector).remove + collection.find(atomic_selector).delete_one true end @@ -140,7 +140,7 @@ def delete_all(conditions = nil) selector.merge!(_type: name) if hereditary? coll = collection deleted = coll.find(selector).count - coll.find(selector).remove_all + coll.find(selector).delete_many deleted end end diff --git a/lib/mongoid/persistable/updatable.rb b/lib/mongoid/persistable/updatable.rb index 1633c1cc24..b995f8f052 100644 --- a/lib/mongoid/persistable/updatable.rb +++ b/lib/mongoid/persistable/updatable.rb @@ -141,9 +141,9 @@ def update_document(options = {}) unless updates.empty? coll = _root.collection selector = atomic_selector - coll.find(selector).update(positionally(selector, updates)) + coll.find(selector).update_one(positionally(selector, updates)) conflicts.each_pair do |key, value| - coll.find(selector).update(positionally(selector, { key => value })) + coll.find(selector).update_one(positionally(selector, { key => value })) end end end diff --git a/lib/mongoid/persistable/upsertable.rb b/lib/mongoid/persistable/upsertable.rb index 3a606b8b3b..175878d2a5 100644 --- a/lib/mongoid/persistable/upsertable.rb +++ b/lib/mongoid/persistable/upsertable.rb @@ -21,7 +21,7 @@ module Upsertable # @since 3.0.0 def upsert(options = {}) prepare_upsert(options) do - collection.find(atomic_selector).update(as_document, [ :upsert ]) + collection.find(atomic_selector).update_one(as_document, upsert: true) end end diff --git a/lib/mongoid/query_cache.rb b/lib/mongoid/query_cache.rb index d1cb7a72d3..2198c4e419 100644 --- a/lib/mongoid/query_cache.rb +++ b/lib/mongoid/query_cache.rb @@ -107,149 +107,143 @@ def call(env) end end - module Base # :nodoc: - - def alias_query_cache_clear(*method_names) - method_names.each do |method_name| - class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{method_name}_with_clear_cache(*args) # def upsert_with_clear_cache(*args) - QueryCache.clear_cache # QueryCache.clear_cache - #{method_name}_without_clear_cache(*args) # upsert_without_clear_cache(*args) - end # end - CODE + # A Cursor that attempts to load documents from memory first before hitting + # the database if the same query has already been executed. + # + # @since 5.0.0 + class CachedCursor < Mongo::Cursor - alias_method_chain method_name, :clear_cache + # We iterate over the cached documents if they exist already in the + # cursor otherwise proceed as normal. + # + # @example Iterate over the documents. + # cursor.each do |doc| + # # ... + # end + # + # @since 5.0.0 + def each + if @cached_documents + @cached_documents.each{ |doc| yield doc } + else + super end end + + # Get a human-readable string representation of +Cursor+. + # + # @example Inspect the cursor. + # cursor.inspect + # + # @return [ String ] A string representation of a +Cursor+ instance. + # + # @since 2.0.0 + def inspect + "#" + end + + private + + def process(result) + @remaining -= result.returned_count if limited? + @cursor_id = result.cursor_id + @coll_name ||= result.namespace.sub("#{database.name}.", '') if result.namespace + documents = result.documents + (@cached_documents ||= []).concat(documents) + documents + end end - # Module to include in objects which need to wrap caching behaviour around - # them. + # Included to add behaviour for clearing out the query cache on certain + # operations. # # @since 4.0.0 - module Cacheable + module Base - private + def alias_query_cache_clear(*method_names) + method_names.each do |method_name| + class_eval <<-CODE, __FILE__, __LINE__ + 1 + def #{method_name}_with_clear_cache(*args) + QueryCache.clear_cache + #{method_name}_without_clear_cache(*args) + end + CODE - def with_cache(context = :cursor, more = false, &_block) - return yield unless QueryCache.enabled? - return yield if system_collection? - key = cache_key.push(context) - - if more - docs = yield - QueryCache.cache_table[key].push(*docs) - docs - elsif QueryCache.cache_table.key?(key) - instrument(key) { QueryCache.cache_table[key] } - else - QueryCache.cache_table[key] = yield + alias_method_chain method_name, :clear_cache end end - - def instrument(key, &block) - ActiveSupport::Notifications.instrument("query_cache.mongoid", key: key, &block) - end end - # Adds behaviour around caching to a Moped Query object. + # Contains enhancements to the Mongo::Collection::View in order to get a + # cached cursor or a regular cursor on iteration. # - # @since 4.0.0 - module Query + # @since 5.0.0 + module View extend ActiveSupport::Concern - include Cacheable included do extend QueryCache::Base - alias_method_chain :cursor, :cache - alias_method_chain :first, :cache - alias_query_cache_clear :remove, :remove_all, :update, :update_all, :upsert - end - - # Provide a wrapped query cache cursor. - # - # @example Get the wrapped caching cursor. - # query.cursor_with_cache - # - # @return [ CachedCursor ] The cached cursor. - # - # @since 4.0.0 - def cursor_with_cache - CachedCursor.new(session, operation) - end - - # Override first with caching. - # - # @example Get the first with a cache. - # query.first_with_cache - # - # @return [ Hash ] The first document. - # - # @since 4.0.0 - def first_with_cache - with_cache(:first) do - first_without_cache + alias_query_cache_clear :delete_one, + :delete_many, + :update_one, + :update_many, + :replace_one, + :find_one_and_delete, + :find_one_and_replace, + :find_one_and_update + end + + # Override the default enumeration to handle if the cursor can be cached + # or not. + # + # @example Iterate over the view. + # view.each do |doc| + # # ... + # end + # + # @since 5.0.0 + def each + if system_collection? || !QueryCache.enabled? + super + else + key = cache_key + cursor = QueryCache.cache_table[key] + unless cursor + server = read.select_server(cluster) + cursor = CachedCursor.new(view, send_initial_query(server), server) + QueryCache.cache_table[key] = cursor + end + cursor.each do |doc| + yield doc + end if block_given? + cursor end end private def cache_key - [ operation.database, operation.collection, operation.selector, operation.limit, operation.skip, operation.fields ] + [ collection.namespace, selector, limit, skip, projection ] end def system_collection? - operation.collection =~ /^system./ + collection.namespace =~ /^system./ end end # Adds behaviour to the query cache for collections. # - # @since 4.0.0 + # @since 5.0.0 module Collection extend ActiveSupport::Concern included do extend QueryCache::Base - alias_query_cache_clear :insert - end - end - - # A Cursor that attempts to load documents from memory first before hitting - # the database if the same query has already been executed. - # - # @since 4.0.0 - class CachedCursor < Moped::Cursor - include Cacheable - - # Override the loading of docs to attempt to fetch from the cache. - # - # @example Load the documents. - # cursor.load_docs - # - # @return [ Array ] The documents. - # - # @since 4.0.0 - def load_docs - with_cache { super } - end - - def get_more - with_cache(:cursor, true) { super } - end - - private - - def cache_key - [ @database, @collection, @selector, @options[:limit], @options[:skip], @options[:fields] ] - end - - def system_collection? - @collection =~ /^system./ + alias_query_cache_clear :insert_one, :insert_many end end end end -Moped::Query.__send__(:include, Mongoid::QueryCache::Query) -Moped::Collection.__send__(:include, Mongoid::QueryCache::Collection) +Mongo::Collection.__send__(:include, Mongoid::QueryCache::Collection) +Mongo::Collection::View.__send__(:include, Mongoid::QueryCache::View) diff --git a/lib/mongoid/railtie.rb b/lib/mongoid/railtie.rb index b3b76f1e91..9a8b885be6 100644 --- a/lib/mongoid/railtie.rb +++ b/lib/mongoid/railtie.rb @@ -95,24 +95,6 @@ def self.rescue_responses end end - config.after_initialize do - # Unicorn clears the START_CTX when a worker is forked, so if we have - # data in START_CTX then we know we're being preloaded. Unicorn does - # not provide application-level hooks for executing code after the - # process has forked, so we reconnect lazily. - if defined?(Unicorn) && !Unicorn::HttpServer::START_CTX.empty? - ::Mongoid.default_session.disconnect if ::Mongoid.configured? - end - - # Passenger provides the :starting_worker_process event for executing - # code after it has forked, so we use that and reconnect immediately. - if ::Mongoid::Config.running_with_passenger? - PhusionPassenger.on_event(:starting_worker_process) do |forked| - ::Mongoid.default_session.disconnect if forked - end - end - end - # Rails runs all initializers first before getting into any generator # code, so we have no way in the intitializer to know if we are # generating a mongoid.yml. So instead of failing, we catch all the diff --git a/lib/mongoid/relations/embedded/batchable.rb b/lib/mongoid/relations/embedded/batchable.rb index 09749cd0f9..59bf000c0d 100644 --- a/lib/mongoid/relations/embedded/batchable.rb +++ b/lib/mongoid/relations/embedded/batchable.rb @@ -37,7 +37,7 @@ def batch_insert(docs) def batch_clear(docs) pre_process_batch_remove(docs, :delete) unless docs.empty? - collection.find(selector).update( + collection.find(selector).update_one( positionally(selector, "$unset" => { path => true }) ) post_process_batch_remove(docs, :delete) @@ -57,7 +57,7 @@ def batch_clear(docs) def batch_remove(docs, method = :delete) removals = pre_process_batch_remove(docs, method) if !docs.empty? - collection.find(selector).update( + collection.find(selector).update_one( positionally(selector, "$pullAll" => { path => removals }) ) post_process_batch_remove(docs, method) @@ -130,7 +130,7 @@ def execute_batch_insert(docs, operation) self.inserts_valid = true inserts = pre_process_batch_insert(docs) if insertable? - collection.find(selector).update( + collection.find(selector).update_one( positionally(selector, operation => { path => inserts }) ) post_process_batch_insert(docs) diff --git a/lib/mongoid/relations/referenced/many.rb b/lib/mongoid/relations/referenced/many.rb index 38a8532182..4194120530 100644 --- a/lib/mongoid/relations/referenced/many.rb +++ b/lib/mongoid/relations/referenced/many.rb @@ -428,7 +428,7 @@ def method_missing(name, *args, &block) # @since 3.0.0 def persist_delayed(docs, inserts) unless docs.empty? - collection.insert(inserts) + collection.insert_many(inserts) docs.each do |doc| doc.new_record = false doc.run_after_callbacks(:create, :save) diff --git a/lib/mongoid/relations/touchable.rb b/lib/mongoid/relations/touchable.rb index f6f473fa6a..72e55a21b1 100644 --- a/lib/mongoid/relations/touchable.rb +++ b/lib/mongoid/relations/touchable.rb @@ -31,7 +31,7 @@ def touch(field = nil) touches = touch_atomic_updates(field) unless touches.empty? selector = atomic_selector - _root.collection.where(selector).update(positionally(selector, touches)) + _root.collection.find(selector).update_one(positionally(selector, touches)) end run_callbacks(:touch) true diff --git a/lib/mongoid/reloadable.rb b/lib/mongoid/reloadable.rb index 9333aaa5a5..8a20cec3c0 100644 --- a/lib/mongoid/reloadable.rb +++ b/lib/mongoid/reloadable.rb @@ -57,7 +57,7 @@ def _reload # # @since 2.3.2 def reload_root_document - {}.merge(with(read: :primary).collection.find(_id: _id).one || {}) + {}.merge(with(read: { mode: :primary }).collection.find(_id: _id).first || {}) end # Reload the embedded document. @@ -70,7 +70,7 @@ def reload_root_document # @since 2.3.2 def reload_embedded_document extract_embedded_attributes({}.merge( - _root.with(read: :primary).collection.find(_id: _root._id).one + _root.with(read: { mode: :primary }).collection.find(_id: _root._id).first )) end diff --git a/lib/mongoid/sessions.rb b/lib/mongoid/sessions.rb index ec030b6f7a..e034401108 100644 --- a/lib/mongoid/sessions.rb +++ b/lib/mongoid/sessions.rb @@ -46,7 +46,9 @@ def default # # @since 3.1.0 def disconnect - Threaded.sessions.values.each(&:disconnect) + Threaded.sessions.values.each do |session| + # session.close + end end # Get a session with the provided name. @@ -62,6 +64,10 @@ def disconnect def with_name(name) Threaded.sessions[name.to_sym] ||= Sessions::Factory.create(name) end + + def set(name, session) + Threaded.sessions[name.to_sym] = session + end end # Get the collection for this model from the session. Will check for an @@ -101,8 +107,9 @@ module ClassMethods # @since 3.0.0 def mongo_session session = Sessions.with_name(session_name) - session.use(database_name) - self.persistence_options ? session.with(self.persistence_options) : session + session = session.use(database_name) + session = self.persistence_options.blank? ? session : session.with(self.persistence_options) + Sessions.set(session_name, session) end # Get the collection for this model from the session. Will check for an diff --git a/lib/mongoid/sessions/factory.rb b/lib/mongoid/sessions/factory.rb index b1641c4886..6d8d9f4ed3 100644 --- a/lib/mongoid/sessions/factory.rb +++ b/lib/mongoid/sessions/factory.rb @@ -1,5 +1,4 @@ # encoding: utf-8 -require "mongoid/sessions/mongo_uri" module Mongoid module Sessions @@ -59,72 +58,16 @@ def default # @since 3.0.0 def create_session(configuration) raise Errors::NoSessionsConfig.new unless configuration - config, options = parse(configuration) - configuration.merge!(config) if configuration.delete(:uri) - - options[:instrumenter] = ActiveSupport::Notifications - session = Moped::Session.new(config[:hosts], options) - session.use(config[:database]) - if authenticated?(config) - session.login(config[:username], config[:password]) - end - session - end - - # Are we authenticated with this session config? - # - # @api private - # - # @example Is this session authenticated? - # Factory.authenticated?(config) - # - # @param [ Hash ] config The session config. - # - # @return [ true, false ] If we are authenticated. - # - # @since 3.0.0 - def authenticated?(config) - config.has_key?(:username) && config.has_key?(:password) - end - - # Parse the configuration. If a uri is provided we need to extract the - # elements of it, otherwise the options are left alone. - # - # @api private - # - # @example Parse the config. - # Factory.parse(config) - # - # @param [ Hash ] config The configuration. - # - # @return [ Array ] The configuration, parsed. - # - # @since 3.0.0 - def parse(config) - options = config[:options].try(:dup) || {} - parsed = if config.has_key?(:uri) - MongoUri.new(config[:uri]).to_hash + if configuration[:uri] + Mongo::Client.new(configuration[:uri], options(configuration)) else - inject_ports(config) + Mongo::Client.new(configuration[:hosts], options(configuration)) end - [ parsed, options.symbolize_keys ] end - # Will inject the default port of 27017 if not supplied. - # - # @example Inject default ports. - # factory.inject_ports(config) - # - # @param [ Hash ] config The session configuration. - # - # @return [ Hash ] The altered configuration. - # - # @since 3.1.0 - def inject_ports(config) - config["hosts"] = config["hosts"].map do |host| - host =~ /:/ ? host : "#{host}:27017" - end - config + def options(configuration) + options = configuration[:options] || {} + options.merge(configuration.reject{ |k, v| k == :hosts }).to_hash.symbolize_keys! end end end diff --git a/lib/mongoid/sessions/storage_options.rb b/lib/mongoid/sessions/storage_options.rb index 9ef6f8b9e4..cfad4d874b 100644 --- a/lib/mongoid/sessions/storage_options.rb +++ b/lib/mongoid/sessions/storage_options.rb @@ -75,7 +75,7 @@ def storage_options_defaults { collection: name.collectionize.to_sym, session: :default, - database: -> { Mongoid.sessions[session_name][:database] } + database: -> { configured_database } } end @@ -134,6 +134,17 @@ def __evaluate__(name) return nil unless name name.respond_to?(:call) ? name.call.to_sym : name.to_sym end + + def configured_database + session = Mongoid.sessions[session_name] + if db = session[:database] + db + elsif uri = session[:uri] + session[:database] = Mongo::URI.new(uri).database + else + nil + end + end end end end diff --git a/lib/mongoid/support/query_counter.rb b/lib/mongoid/support/query_counter.rb deleted file mode 100644 index cd5b3cdc39..0000000000 --- a/lib/mongoid/support/query_counter.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Mongoid - - class QueryCounter - attr_reader :events - - def initialize - @events = [] - end - - def instrument - subscriber = ActiveSupport::Notifications.subscribe('query.moped') do |*args| - @events << ActiveSupport::Notifications::Event.new(*args) - end - yield - ensure - ActiveSupport::Notifications.unsubscribe(subscriber) - end - - def inspect - @events.map { |e| e.payload[:ops].map(&:log_inspect) }.join("\n") - end - end -end diff --git a/lib/mongoid/tasks/database.rake b/lib/mongoid/tasks/database.rake index fc80f41a0f..4d7c132c20 100644 --- a/lib/mongoid/tasks/database.rake +++ b/lib/mongoid/tasks/database.rake @@ -20,7 +20,7 @@ namespace :db do desc "Drops the default session" task :drop => :environment do - ::Mongoid::Sessions.default.drop + ::Mongoid::Sessions.default.database.drop end desc "Drop all collections except the system collections" diff --git a/lib/mongoid/tasks/database.rb b/lib/mongoid/tasks/database.rb index f3fa3b4574..41fa337d14 100644 --- a/lib/mongoid/tasks/database.rb +++ b/lib/mongoid/tasks/database.rb @@ -42,18 +42,20 @@ def undefined_indexes(models = ::Mongoid.models) models.each do |model| unless model.embedded? - model.collection.indexes.each do |index| - # ignore default index - unless index['name'] == '_id_' - key = index['key'].symbolize_keys - spec = model.index_specification(key) - unless spec - # index not specified - undefined_by_model[model] ||= [] - undefined_by_model[model] << index + begin + model.collection.indexes.each do |index| + # ignore default index + unless index['name'] == '_id_' + key = index['key'].symbolize_keys + spec = model.index_specification(key) + unless spec + # index not specified + undefined_by_model[model] ||= [] + undefined_by_model[model] << index + end end end - end + rescue Mongo::Error::OperationFailure; end end end @@ -73,7 +75,7 @@ def remove_undefined_indexes(models = ::Mongoid.models) undefined_indexes(models).each do |model, indexes| indexes.each do |index| key = index['key'].symbolize_keys - model.collection.indexes.drop(key) + model.collection.indexes.drop_one(key) logger.info("MONGOID: Removing index: #{index['name']} on #{model}.") end end @@ -90,10 +92,14 @@ def remove_undefined_indexes(models = ::Mongoid.models) def remove_indexes(models = ::Mongoid.models) models.each do |model| next if model.embedded? - indexes = model.collection.indexes.map{ |doc| doc["name"] } - indexes.delete_one("_id_") - model.remove_indexes - logger.info("MONGOID: Removing indexes on: #{model} for: #{indexes.join(', ')}.") + begin + indexes = model.collection.indexes.map{ |doc| doc["name"] } + indexes.delete_one("_id_") + model.remove_indexes + logger.info("MONGOID: Removing indexes on: #{model} for: #{indexes.join(', ')}.") + rescue Mongo::Error::OperationFailure + next + end model end.compact end diff --git a/lib/mongoid/validatable/uniqueness.rb b/lib/mongoid/validatable/uniqueness.rb index 9964dcdc5b..4eb8b2db91 100644 --- a/lib/mongoid/validatable/uniqueness.rb +++ b/lib/mongoid/validatable/uniqueness.rb @@ -310,7 +310,7 @@ def validation_required?(document, attribute) # # @since 3.0.23 def persistence_options(criteria) - (criteria.persistence_options || {}).merge!(read: :primary) + (criteria.persistence_options || {}).merge!(read: { mode: :primary }) end # Is the attribute localized? diff --git a/lib/mongoid/version.rb b/lib/mongoid/version.rb index d7dad92d20..ea58815fc6 100644 --- a/lib/mongoid/version.rb +++ b/lib/mongoid/version.rb @@ -1,4 +1,4 @@ # encoding: utf-8 module Mongoid - VERSION = "4.0.2" + VERSION = "5.0.0" end diff --git a/mongoid.gemspec b/mongoid.gemspec index e4262b9520..b44cc207fd 100644 --- a/mongoid.gemspec +++ b/mongoid.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.add_dependency("activemodel", ["~> 4.0"]) s.add_dependency("tzinfo", [">= 0.3.37"]) - s.add_dependency("moped", ["~> 2.0.0"]) + s.add_dependency("mongo", ["~> 2.0"]) s.add_dependency("origin", ["~> 2.1"]) s.files = Dir.glob("lib/**/*") + %w(CHANGELOG.md LICENSE README.md Rakefile) diff --git a/spec/config/mongoid.yml b/spec/config/mongoid.yml index dd5b54ea25..30f165ec80 100644 --- a/spec/config/mongoid.yml +++ b/spec/config/mongoid.yml @@ -5,30 +5,11 @@ test: hosts: - <%=ENV["MONGOID_SPEC_HOST"]%>:<%=ENV["MONGOID_SPEC_PORT"]%> options: - read: primary - mongohq_single: - database: <%=ENV["MONGOHQ_SINGLE_NAME"]%> - username: <%=ENV["MONGOHQ_SINGLE_USER"]%> - password: <%=ENV["MONGOHQ_SINGLE_PASS"]%> - hosts: - - <%=ENV["MONGOHQ_SINGLE_URL"]%> - options: - write: - w: 1 - read: primary - mongohq_repl: - database: <%=ENV["MONGOHQ_REPL_NAME"]%> - username: <%=ENV["MONGOHQ_REPL_USER"]%> - password: <%=ENV["MONGOHQ_REPL_PASS"]%> - hosts: - - <%=ENV["MONGOHQ_REPL_1_URL"]%> - - <%=ENV["MONGOHQ_REPL_2_URL"]%> - options: - read: primary - write: - w: majority - mongohq_repl_uri: - uri: <%= ENV["MONGOHQ_REPL_URI"]%> + user: "mongoid-user" + password: "password" + auth_source: "admin" + read: + mode: primary options: include_root_in_json: false include_type_for_serialization: false diff --git a/spec/helpers.rb b/spec/helpers.rb deleted file mode 100644 index f40a86ab76..0000000000 --- a/spec/helpers.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'mongoid/support/query_counter' - -module Mongoid - module SpecHelpers - def expect_query(number, &block) - query_counter = Mongoid::QueryCounter.new - query_counter.instrument(&block) - expect(query_counter.events.size).to(eq(number), %[ -Expected to receive #{number} queries, it received #{query_counter.events.size} -#{query_counter.inspect} -]) - end - - def expect_no_queries(&block) - expect_query(0, &block) - end - end -end diff --git a/spec/mongoid/attributes/nested_spec.rb b/spec/mongoid/attributes/nested_spec.rb index 4b550821ad..ecf7b93ffa 100644 --- a/spec/mongoid/attributes/nested_spec.rb +++ b/spec/mongoid/attributes/nested_spec.rb @@ -2936,11 +2936,11 @@ class BandWithAllowDestroyedRecords < Band context "when reloading the document" do it "updates the first existing document" do - expect(person.posts(true).first.title).to eq("First") + expect(person.posts(true)[0].title).to eq("First") end it "updates the second existing document" do - expect(person.posts(true).last.title).to eq("Second") + expect(person.posts(true)[1].title).to eq("Second") end it "does not add new documents" do @@ -3094,11 +3094,11 @@ class BandWithAllowDestroyedRecords < Band context "when reloading the document" do it "does not ignore the marked document" do - expect(person.posts(true).first.title).to eq("Another Title") + expect(person.posts(true)[0].title).to eq("Another Title") end it "does not delete the unmarked document" do - expect(person.posts(true).last.title).to eq("New Title") + expect(person.posts(true)[1].title).to eq("New Title") end it "does not add additional documents" do @@ -3127,7 +3127,7 @@ class BandWithAllowDestroyedRecords < Band end it "does not delete the unmarked document" do - expect(person.posts(true).last.title).to eq("New Title") + expect(person.posts(true)[1].title).to eq("New Title") end end end @@ -3198,7 +3198,7 @@ class BandWithAllowDestroyedRecords < Band end it "does not delete the unmarked document" do - expect(person.posts(true).last.title).to eq("New Title") + expect(person.posts(true)[1].title).to eq("New Title") end end end @@ -3224,15 +3224,15 @@ class BandWithAllowDestroyedRecords < Band end it "builds a new first document" do - expect(person.posts.first.title).to eq("First") + expect(person.posts[0].title).to eq("First") end it "builds a new second document" do - expect(person.posts.second.title).to eq("Second") + expect(person.posts[1].title).to eq("Second") end it "builds a new third document" do - expect(person.posts.third.title).to eq("Third") + expect(person.posts[2].title).to eq("Third") end it "does not add extra documents" do @@ -3776,7 +3776,7 @@ class BandWithAllowDestroyedRecords < Band end it "does not delete the unmarked document" do - expect(person.preferences(true).last.name).to eq("My Blog") + expect(person.preferences(true)[1].name).to eq("My Blog") end end end @@ -3811,11 +3811,11 @@ class BandWithAllowDestroyedRecords < Band context "when reloading the document" do it "does not ignore the marked document" do - expect(person.preferences(true).first.name).to eq("Another Title") + expect(person.preferences(true)[0].name).to eq("Another Title") end it "does not delete the unmarked document" do - expect(person.preferences(true).last.name).to eq("New Title") + expect(person.preferences(true)[1].name).to eq("New Title") end it "does not add additional documents" do @@ -3844,7 +3844,7 @@ class BandWithAllowDestroyedRecords < Band end it "does not delete the unmarked document" do - expect(person.preferences(true).last.name).to eq("New Title") + expect(person.preferences(true)[1].name).to eq("New Title") end end end @@ -3874,11 +3874,11 @@ class BandWithAllowDestroyedRecords < Band context "when reloading" do it "does not ignore the marked document" do - expect(person.preferences(true).first.name).to eq("Another Title") + expect(person.preferences(true)[0].name).to eq("Another Title") end it "does not delete the unmarked document" do - expect(person.preferences(true).last.name).to eq("New Title") + expect(person.preferences(true)[1].name).to eq("New Title") end it "does not add additional documents" do @@ -3907,7 +3907,7 @@ class BandWithAllowDestroyedRecords < Band end it "does not delete the unmarked document" do - expect(person.preferences(true).last.name).to eq("New Title") + expect(person.preferences(true)[1].name).to eq("New Title") end end end diff --git a/spec/mongoid/attributes_spec.rb b/spec/mongoid/attributes_spec.rb index 3fe0fc2fd7..369e0a337d 100644 --- a/spec/mongoid/attributes_spec.rb +++ b/spec/mongoid/attributes_spec.rb @@ -172,7 +172,7 @@ before do person.collection .find({ _id: person.id }) - .update({ "$unset" => { age: 1 }}) + .update_one({ "$unset" => { age: 1 }}) end context "when found" do @@ -742,7 +742,7 @@ before do person.collection .find({ _id: person.id }) - .update({ "$unset" => { age: 1 }}) + .update_one({ "$unset" => { age: 1 }}) Mongoid.raise_not_found_error = false person.reload Mongoid.raise_not_found_error = true @@ -829,7 +829,7 @@ before do person.collection .find({ _id: person.id }) - .update({ "$unset" => { age: 1 }}) + .update_one({ "$unset" => { age: 1 }}) Mongoid.raise_not_found_error = false person.reload Mongoid.raise_not_found_error = true diff --git a/spec/mongoid/config_spec.rb b/spec/mongoid/config_spec.rb index 89a99da792..c4cbec547f 100644 --- a/spec/mongoid/config_spec.rb +++ b/spec/mongoid/config_spec.rb @@ -23,13 +23,13 @@ { default: { database: database_id, - hosts: [ "localhost:27017" ] + hosts: [ "127.0.0.1:27017" ] } } end before do - described_class.sessions = config + described_class.send(:sessions=, config) end it "returns true" do @@ -76,7 +76,7 @@ context "when existing sessions exist in the configuration" do let(:session) do - Moped::Session.new([ "127.0.0.1:27017" ]) + Mongo::Client.new([ "127.0.0.1:27017" ]) end before do @@ -197,25 +197,10 @@ end it "sets the read option" do - expect(options["read"]).to eq("primary") + expect(options["read"]).to eq({ "mode" => "primary" }) end end end - - context "when a secondary is provided", config: :mongohq do - - before do - described_class.load!(file) - end - - let(:secondary) do - described_class.sessions[:mongohq_single] - end - - it "sets the secondary host" do - expect(secondary["hosts"]).to eq([ ENV["MONGOHQ_SINGLE_URL"] ]) - end - end end end end @@ -249,7 +234,7 @@ it "raises an error" do expect { - described_class.sessions = nil + described_class.send(:sessions=, nil) }.to raise_error(Mongoid::Errors::NoSessionsConfig) end end @@ -258,7 +243,7 @@ it "raises an error" do expect { - described_class.sessions = {} + described_class.send(:sessions=, {}) }.to raise_error(Mongoid::Errors::NoDefaultSession) end end @@ -273,7 +258,7 @@ it "raises an error" do expect { - described_class.sessions = sessions + described_class.send(:sessions=, sessions) }.to raise_error(Mongoid::Errors::NoSessionHosts) end end @@ -281,12 +266,12 @@ context "when no database is provided" do let(:sessions) do - { "default" => { hosts: [ "localhost:27017" ] }} + { "default" => { hosts: [ "127.0.0.1:27017" ] }} end it "raises an error" do expect { - described_class.sessions = sessions + described_class.send(:sessions=, sessions) }.to raise_error(Mongoid::Errors::NoSessionDatabase) end end @@ -295,13 +280,13 @@ let(:sessions) do { "default" => - { hosts: [ "localhost:27017" ], uri: "mongodb://localhost:27017" } + { hosts: [ "127.0.0.1:27017" ], uri: "mongodb://127.0.0.1:27017" } } end it "raises an error" do expect { - described_class.sessions = sessions + described_class.send(:sessions=, sessions) }.to raise_error(Mongoid::Errors::MixedSessionConfiguration) end end diff --git a/spec/mongoid/contextual/atomic_spec.rb b/spec/mongoid/contextual/atomic_spec.rb index 09e50ee607..5e9d643da2 100644 --- a/spec/mongoid/contextual/atomic_spec.rb +++ b/spec/mongoid/contextual/atomic_spec.rb @@ -81,10 +81,6 @@ Band.create(likes: 60) end - let!(:smiths) do - Band.create - end - let(:criteria) do Band.all end @@ -102,10 +98,6 @@ it "performs the bitwise operation on initialized fields" do expect(depeche_mode.reload.likes).to eq(12) end - - it "does not error on non initialized fields" do - expect(smiths.reload.likes).to eq(0) - end end context "when performing a bitwise or" do @@ -117,10 +109,6 @@ it "performs the bitwise operation on initialized fields" do expect(depeche_mode.reload.likes).to eq(61) end - - it "does not error on non initialized fields" do - expect(smiths.reload.likes).to eq(13) - end end context "when chaining bitwise operations" do @@ -132,12 +120,8 @@ it "performs the bitwise operation on initialized fields" do expect(depeche_mode.reload.likes).to eq(14) end - - it "does not error on non initialized fields" do - expect(smiths.reload.likes).to eq(10) - end end - end if mongodb_version > "2.5" + end describe "#inc" do diff --git a/spec/mongoid/contextual/find_and_modify_spec.rb b/spec/mongoid/contextual/find_and_modify_spec.rb deleted file mode 100644 index 7fb5e35ef4..0000000000 --- a/spec/mongoid/contextual/find_and_modify_spec.rb +++ /dev/null @@ -1,220 +0,0 @@ -require "spec_helper" - -describe Mongoid::Contextual::FindAndModify do - - describe "#result" do - - let!(:depeche) do - Band.create(name: "Depeche Mode") - end - - let!(:tool) do - Band.create(name: "Tool") - end - - let!(:collection) do - Band.collection - end - - context "when the selector matches" do - - context "when not providing options" do - - let(:criteria) do - Band.where(name: "Depeche Mode") - end - - let(:context) do - described_class.new(collection, criteria, { "$inc" => { likes: 1 }}) - end - - let!(:result) do - context.result - end - - it "returns the first matching document" do - expect(result["name"]).to eq("Depeche Mode") - end - - it "updates the document in the database" do - expect(depeche.reload.likes).to eq(1) - end - end - - context "when providing values that needs to be cast" do - - let(:date_time) do - DateTime.new(1978, 1, 1) - end - - let(:criteria) do - Band.where(name: "Depeche Mode") - end - - let(:context) do - described_class.new(collection, criteria, { "$set" => { created: date_time }}) - end - - let!(:result) do - context.result - end - - it "returns the first matching document" do - expect(result["name"]).to eq("Depeche Mode") - end - - it "updates the document in the database" do - expect(depeche.reload.created).to eq(date_time) - end - end - - context "when sorting" do - - let(:criteria) do - Band.desc(:name) - end - - let(:context) do - described_class.new(collection, criteria, { "$inc" => { likes: 1 }}) - end - - let!(:result) do - context.result - end - - it "returns the first matching document" do - expect(result["name"]).to eq("Tool") - end - - it "updates the document in the database" do - expect(tool.reload.likes).to eq(1) - end - end - - context "when limiting fields" do - - let(:criteria) do - Band.only(:_id) - end - - let(:context) do - described_class.new(collection, criteria, { "$inc" => { likes: 1 }}) - end - - let!(:result) do - context.result - end - - it "returns the first matching document" do - expect(result["_id"]).to eq(depeche.id) - end - - it "limits the returned fields" do - expect(result["name"]).to be_nil - end - - it "updates the document in the database" do - expect(depeche.reload.likes).to eq(1) - end - end - - context "when returning new" do - - let(:criteria) do - Band.where(name: "Depeche Mode") - end - - let(:context) do - described_class.new(collection, criteria, { "$inc" => { likes: 1 }}, new: true) - end - - let!(:result) do - context.result - end - - it "returns the first matching document" do - expect(result["name"]).to eq("Depeche Mode") - end - - it "returns the updated document" do - expect(result["likes"]).to eq(1) - end - end - - context "when removing" do - - let(:criteria) do - Band.where(name: "Depeche Mode") - end - - let(:context) do - described_class.new(collection, criteria, {}, remove: true) - end - - let!(:result) do - context.result - end - - it "returns the first matching document" do - expect(result["name"]).to eq("Depeche Mode") - end - - it "deletes the document from the database" do - expect { - depeche.reload - }.to raise_error(Mongoid::Errors::DocumentNotFound) - end - end - - context "when upserting" do - - let(:criteria) do - Band.where(name: "The Mars Volta") - end - - let(:context) do - described_class.new(collection, criteria, { "$inc" => { likes: 1 }}, upsert: true) - end - - let(:result) do - context.result - end - - it "creates the document if it does not exist" do - expect { - result - }.to change{Band.where(name: "The Mars Volta").count}.from(0).to(1) - end - - it "updates the document in the database if it does exist" do - the_mars_volta = Band.create(name: "The Mars Volta") - - expect { - result - }.to_not change{Band.where(name: "The Mars Volta").count} - - expect(the_mars_volta.reload.likes).to eq(1) - end - end - end - - context "when the selector does not match" do - - let(:criteria) do - Band.where(name: "Placebo") - end - - let(:context) do - described_class.new(collection, criteria, { "$inc" => { likes: 1 }}) - end - - let(:result) do - context.result - end - - it "returns nil" do - expect(result).to be_nil - end - end - end -end diff --git a/spec/mongoid/contextual/mongo_spec.rb b/spec/mongoid/contextual/mongo_spec.rb index d1261f85f2..8cd05b1f46 100644 --- a/spec/mongoid/contextual/mongo_spec.rb +++ b/spec/mongoid/contextual/mongo_spec.rb @@ -107,7 +107,7 @@ end before do - expect(context.query).to receive(:count).once.and_return(1) + expect(context.view).to receive(:count).once.and_return(1) end it "returns the count cached value after first call" do @@ -164,18 +164,18 @@ end end - context "when provided limit true" do + context "when provided limit" do before do 2.times { Band.create(name: "Depeche Mode") } end let(:context) do - described_class.new(criteria.limit(2)) + described_class.new(criteria) end let(:count) do - context.count(true) + context.count(limit: 2) end it "returns the number of documents that match" do @@ -497,7 +497,7 @@ end it "hits the database again" do - expect(context).to receive(:query).once.and_call_original + expect(context).to receive(:view).once.and_call_original expect(context).to be_exists end end @@ -520,7 +520,7 @@ end it "does not hit the database" do - expect(context).to receive(:query).never + expect(context).to receive(:view).never expect(context).to be_exists end end @@ -534,7 +534,7 @@ end it "does not hit the database" do - expect(context).to receive(:query).never + expect(context).to receive(:view).never expect(context).to be_exists end end @@ -553,11 +553,11 @@ end it "returns the criteria explain path" do - expect(context.explain["cursor"]).to eq("BasicCursor") + expect(context.explain).to_not be_empty end end - describe "#find_and_modify" do + describe "#find_one_and_update" do let!(:depeche) do Band.create(name: "Depeche Mode") @@ -580,7 +580,7 @@ end let!(:result) do - context.find_and_modify("$inc" => { likes: 1 }) + context.find_one_and_update("$inc" => { likes: 1 }) end it "returns the first matching document" do @@ -603,7 +603,7 @@ end let!(:result) do - context.find_and_modify("$inc" => { likes: 1 }) + context.find_one_and_update("$inc" => { likes: 1 }) end it "returns the first matching document" do @@ -626,7 +626,7 @@ end let!(:result) do - context.find_and_modify("$inc" => { likes: 1 }) + context.find_one_and_update("$inc" => { likes: 1 }) end it "returns the first matching document" do @@ -653,7 +653,7 @@ end let!(:result) do - context.find_and_modify({ "$inc" => { likes: 1 }}, new: true) + context.find_one_and_update({ "$inc" => { likes: 1 }}, return_document: :after) end it "returns the first matching document" do @@ -676,7 +676,7 @@ end let!(:result) do - context.find_and_modify({}, remove: true) + context.find_one_and_delete end it "returns the first matching document" do @@ -702,7 +702,7 @@ end let(:result) do - context.find_and_modify("$inc" => { likes: 1 }) + context.find_one_and_update("$inc" => { likes: 1 }) end it "returns nil" do @@ -807,7 +807,7 @@ end it "returns the first document without touching the database" do - expect(context).to receive(:query).never + expect(context).to receive(:view).never expect(context.send(method)).to eq(depeche_mode) end end @@ -819,7 +819,7 @@ end it "returns the first document without touching the database" do - expect(context).to receive(:query).never + expect(context).to receive(:view).never expect(context.send(method)).to eq(depeche_mode) end end @@ -845,20 +845,16 @@ expect(context.klass).to eq(Band) end - it "sets the query" do - expect(context.query).to be_a(Moped::Query) - end - - it "sets the query selector" do - expect(context.query.selector).to eq({ "name" => "Depeche Mode" }) + it "sets the view" do + expect(context.view).to be_a(Mongo::Collection::View) end - it "sets timeout options" do - expect(context.query.operation.flags).to eq([ :no_cursor_timeout ]) + it "sets the view selector" do + expect(context.view.selector).to eq({ "name" => "Depeche Mode" }) end end - describe "#last" do + pending "#last" do context "when no default scope" do @@ -957,7 +953,7 @@ context "when calling more than once" do before do - expect(context.query).to receive(:count).once.and_return(2) + expect(context.view).to receive(:count).once.and_return(2) end it "returns the cached value for subsequent calls" do @@ -969,7 +965,7 @@ before do context.entries - expect(context.query).to receive(:count).once.and_return(2) + expect(context.view).to receive(:count).once.and_return(2) end it "returns the cached value for all calls" do @@ -1006,7 +1002,7 @@ context "when calling more than once" do before do - expect(context.query).to receive(:count).once.and_return(1) + expect(context.view).to receive(:count).once.and_return(1) end it "returns the cached value for subsequent calls" do @@ -1018,7 +1014,7 @@ before do context.entries - expect(context.query).to receive(:count).once.and_return(1) + expect(context.view).to receive(:count).once.and_return(1) end it "returns the cached value for all calls" do @@ -1517,59 +1513,6 @@ end end - describe "#text_search" do - - let(:criteria) do - Word.all - end - - let(:context) do - described_class.new(criteria) - end - - before do - Word.with(database: "admin").mongo_session.command(setParameter: 1, textSearchEnabled: true) - Word.create_indexes - Word.create!(name: "phase", origin: "latin") - end - - after(:all) do - Word.remove_indexes - end - - context "when the search is projecting" do - - let(:search) do - context.text_search("phase").project(name: 1) - end - - let(:documents) do - search.entries - end - - it "limits the fields to the projection" do - expect { - documents.first.origin - }.to raise_error(ActiveModel::MissingAttributeError) - end - end - - context "when the search is not projecting" do - - let(:search) do - context.text_search("phase") - end - - let(:documents) do - search.entries - end - - it "returns all fields" do - expect(documents.first.origin).to eq("latin") - end - end - end - describe "#update" do let!(:depeche_mode) do diff --git a/spec/mongoid/contextual/text_search_spec.rb b/spec/mongoid/contextual/text_search_spec.rb deleted file mode 100644 index 4535a6e6dc..0000000000 --- a/spec/mongoid/contextual/text_search_spec.rb +++ /dev/null @@ -1,209 +0,0 @@ -require "spec_helper" - -describe Mongoid::Contextual::TextSearch do - - before do - Word.with(database: "admin").mongo_session.command(setParameter: 1, textSearchEnabled: true) - Word.create_indexes - end - - after(:all) do - Word.remove_indexes - end - - describe "#each" do - - let(:collection) do - Word.collection - end - - let(:criteria) do - Word.all - end - - before do - Word.create!(name: "phase", origin: "latin") - Word.create!(name: "phazed", origin: "latin") - end - - context "when the search is projecting" do - - let(:search) do - described_class.new(collection, criteria, "phase").project(name: 1) - end - - let(:documents) do - search.entries - end - - it "limits the fields to the projection" do - expect { - documents.first.origin - }.to raise_error(ActiveModel::MissingAttributeError) - end - end - - context "when the search is not projecting" do - - let(:search) do - described_class.new(collection, criteria, "phase") - end - - let(:documents) do - search.entries - end - - it "returns all fields" do - expect(documents.first.origin).to eq("latin") - end - end - end - - describe "#execute" do - - let(:collection) do - Word.collection - end - - let(:criteria) do - Word.all - end - - let(:search) do - described_class.new(collection, criteria, "phase") - end - - before do - Word.create!(name: "phase", origin: "latin") - Word.create!(name: "phazed", origin: "latin") - end - - let(:results) do - search.execute - end - - it "returns the raw results" do - expect(results).to_not be_empty - end - end - - describe "#initialize" do - - let(:collection) do - Word.collection - end - - let(:criteria) do - Word.limit(100) - end - - let(:search) do - described_class.new(collection, criteria, "phase") - end - - it "sets the collection" do - expect(search.collection).to eq(collection) - end - - it "sets the criteria" do - expect(search.criteria).to eq(criteria) - end - - it "sets the text command" do - expect(search.command[:text]).to eq(collection.name) - end - - it "sets the text search parameter" do - expect(search.command[:search]).to eq("phase") - end - - it "sets the criteria" do - expect(search.command[:filter]).to be_empty - end - - it "sets the limit" do - expect(search.command[:limit]).to eq(100) - end - end - - describe "#language" do - - let(:collection) do - Word.collection - end - - let(:criteria) do - Word.limit(100) - end - - let(:search) do - described_class.new(collection, criteria, "phase") - end - - let!(:text_search) do - search.language("deutsch") - end - - it "sets the search language" do - expect(search.command[:language]).to eq("deutsch") - end - - it "returns the text search" do - expect(text_search).to equal(search) - end - end - - describe "#project" do - - let(:collection) do - Word.collection - end - - let(:criteria) do - Word.limit(100) - end - - let(:search) do - described_class.new(collection, criteria, "phase") - end - - let!(:text_search) do - search.project(name: 1, title: 1) - end - - it "sets the search field limitations" do - expect(search.command[:project]).to eq(name: 1, title: 1) - end - - it "returns the text search" do - expect(text_search).to equal(search) - end - end - - describe "#stats" do - - let(:collection) do - Word.collection - end - - let(:criteria) do - Word.all - end - - let(:search) do - described_class.new(collection, criteria, "phase") - end - - before do - Word.create!(name: "phase", origin: "latin") - end - - let(:stats) do - search.stats - end - - it "returns the raw stats" do - expect(stats["nscanned"]).to eq(1) - end - end -end diff --git a/spec/mongoid/copyable_spec.rb b/spec/mongoid/copyable_spec.rb index 4e9da29471..7008ea74f1 100644 --- a/spec/mongoid/copyable_spec.rb +++ b/spec/mongoid/copyable_spec.rb @@ -42,7 +42,7 @@ end before do - Band.collection.find(_id: band.id).update("$set" => { "id" => 1234 }) + Band.collection.find(_id: band.id).update_one("$set" => { "id" => 1234 }) end let!(:cloned) do diff --git a/spec/mongoid/criteria/modifiable_spec.rb b/spec/mongoid/criteria/modifiable_spec.rb index 1aa74f0ada..0541087450 100644 --- a/spec/mongoid/criteria/modifiable_spec.rb +++ b/spec/mongoid/criteria/modifiable_spec.rb @@ -954,7 +954,7 @@ end it "does not update the last document" do - expect(from_db.posts.last.title).to eq("Second") + expect(from_db.posts[1].title).to eq("Second") end end @@ -999,11 +999,11 @@ end it "updates the first document" do - expect(from_db.preferences.first.name).to eq("London") + expect(from_db.preferences[0].name).to eq("London") end it "does not update the last document" do - expect(from_db.preferences.last.name).to eq("Second") + expect(from_db.preferences[1].name).to eq("Second") end end @@ -1014,11 +1014,11 @@ end it "updates the matching documents" do - expect(from_db.preferences.first.name).to eq("Berlin") + expect(from_db.preferences[0].name).to eq("Berlin") end it "does not update non matching documents" do - expect(from_db.preferences.last.name).to eq("Second") + expect(from_db.preferences[1].name).to eq("Second") end end end @@ -1217,36 +1217,14 @@ end it "updates the matching documents" do - expect(from_db.preferences.first.name).to eq("Berlin") + expect(from_db.preferences[0].name).to eq("Berlin") end it "does not update non matching documents" do - expect(from_db.preferences.last.name).to eq("Second") + expect(from_db.preferences[1].name).to eq("Second") end end end end - - context "when update document structure" do - - before do - person = Person.new(username: "user_title", score: 25) - person.save - end - - let(:from_db) do - Person.last - end - - it "rename document string field" do - Person.where(username: "user_title").update_all("$rename" => { username: "title" }) - expect(from_db.title).to eq("user_title") - end - - it "rename document integer field" do - Person.where(score: 25).update_all("$rename" => { score: "age" }) - expect(from_db.age).to eq( 25 ) - end - end end end diff --git a/spec/mongoid/criteria_spec.rb b/spec/mongoid/criteria_spec.rb index dbb56287e0..8f1bfe26cf 100644 --- a/spec/mongoid/criteria_spec.rb +++ b/spec/mongoid/criteria_spec.rb @@ -362,7 +362,7 @@ end it "does not hit the database after first iteration" do - expect(criteria.context.query).to receive(:each).never + expect(criteria.context.view).to receive(:each).never criteria.each do |doc| expect(doc).to eq(person) end @@ -380,7 +380,7 @@ end it "does not hit the database after first iteration" do - expect(criteria.context.query).to receive(:each).never + expect(criteria.context.view).to receive(:each).never criteria.each do |doc| expect(doc).to eq(person) end @@ -709,7 +709,7 @@ end it "returns the criteria explain path" do - expect(criteria.explain["cursor"]).to eq("BasicCursor") + expect(criteria.explain).to_not be_empty end end @@ -757,7 +757,7 @@ end end - describe "#find_and_modify" do + describe "#find_one_and_update" do let!(:depeche) do Band.create(name: "Depeche Mode") @@ -778,7 +778,7 @@ end let(:result) do - criteria.find_and_modify({ "$inc" => { likes: 1 }}, new: true) + criteria.find_one_and_update({ "$inc" => { likes: 1 }}, return_document: :after) end it "returns the first matching document" do @@ -793,7 +793,7 @@ end let!(:result) do - criteria.find_and_modify("$inc" => { likes: 1 }) + criteria.find_one_and_update("$inc" => { likes: 1 }) end before do @@ -813,7 +813,7 @@ end let!(:result) do - criteria.find_and_modify("$inc" => { likes: 1 }) + criteria.find_one_and_update("$inc" => { likes: 1 }) end it "returns the first matching document" do @@ -832,7 +832,7 @@ end let!(:result) do - criteria.find_and_modify("$inc" => { likes: 1 }) + criteria.find_one_and_update("$inc" => { likes: 1 }) end it "returns the first matching document" do @@ -851,7 +851,7 @@ end let!(:result) do - criteria.find_and_modify("$inc" => { likes: 1 }) + criteria.find_one_and_update("$inc" => { likes: 1 }) end it "returns the first matching document" do @@ -874,7 +874,7 @@ end let!(:result) do - criteria.find_and_modify({ "$inc" => { likes: 1 }}, new: true) + criteria.find_one_and_update({ "$inc" => { likes: 1 }}, return_document: :after) end it "returns the first matching document" do @@ -893,7 +893,7 @@ end let!(:result) do - criteria.find_and_modify({}, remove: true) + criteria.find_one_and_delete end it "returns the first matching document" do @@ -914,21 +914,14 @@ Band.where(name: "Placebo") end - context "with upsert" do - - let(:result) do - criteria.find_and_modify({"$inc" => { likes: 1 }}, upsert: true) - end - - it 'returns nil' do - expect(result).to be_nil - end + let(:result) do + criteria.find_one_and_update("$inc" => { likes: 1 }) end context "without upsert" do let(:result) do - criteria.find_and_modify("$inc" => { likes: 1 }) + criteria.find_one_and_update("$inc" => { likes: 1 }) end it "returns nil" do @@ -2240,17 +2233,6 @@ class D ]) end end - - context "when timeout options are provided" do - - let(:map_reduce) do - Band.limit(2).no_timeout.map_reduce(map, reduce).out(replace: "test_bands") - end - - it "sets the timeout option on the query" do - expect(map_reduce.send(:documents).operation.flags).to eq([ :no_cursor_timeout ]) - end - end end describe "#max" do @@ -3069,36 +3051,6 @@ def self.ages; self; end end end - describe "#extras with a hint" do - - let!(:band) do - Band.create(name: "Depeche Mode") - end - - let(:criteria) do - Band.where(name: "Depeche Mode").extras(:hint => {:bad_hint => 1}) - end - - it "executes the criteria while properly giving the hint to Mongo" do - expect { criteria.to_ary }.to raise_error(Moped::Errors::QueryFailure) - end - end - - describe "#hint" do - - let!(:band) do - Band.create(name: "Depeche Mode") - end - - let(:criteria) do - Band.where(name: "Depeche Mode").hint(bad_hint: 1) - end - - it "executes the criteria while properly giving the hint to Mongo" do - expect { criteria.to_ary }.to raise_error(Moped::Errors::QueryFailure) - end - end - describe "#max_scan" do let!(:band) do Band.create(name: "Depeche Mode") @@ -3117,31 +3069,6 @@ def self.ages; self; end end end - describe "#text_search" do - - let(:criteria) do - Word.all - end - - before do - Word.with(database: "admin").mongo_session.command(setParameter: 1, textSearchEnabled: true) - Word.create_indexes - Word.create!(name: "phase", origin: "latin") - end - - after(:all) do - Word.remove_indexes - end - - let(:search) do - criteria.text_search("phase") - end - - it "returns all fields" do - expect(search.first.origin).to eq("latin") - end - end - describe "#to_criteria" do let(:criteria) do diff --git a/spec/mongoid/errors/no_session_database_spec.rb b/spec/mongoid/errors/no_session_database_spec.rb index 378ee0ad79..b8511c1839 100644 --- a/spec/mongoid/errors/no_session_database_spec.rb +++ b/spec/mongoid/errors/no_session_database_spec.rb @@ -5,7 +5,7 @@ describe "#message" do let(:error) do - described_class.new(:secondary, { hosts: [ "localhost:27017" ] }) + described_class.new(:secondary, { hosts: [ "127.0.0.1:27017" ] }) end it "contains the problem in the message" do diff --git a/spec/mongoid/findable_spec.rb b/spec/mongoid/findable_spec.rb index 59e6a00f71..b40f0ce930 100644 --- a/spec/mongoid/findable_spec.rb +++ b/spec/mongoid/findable_spec.rb @@ -40,14 +40,14 @@ end end - describe ".find_and_modify" do + describe ".find_one_and_update" do let!(:person) do Person.create(title: "Senior") end it "returns the document" do - expect(Person.find_and_modify(title: "Junior")).to eq(person) + expect(Person.find_one_and_update(title: "Junior")).to eq(person) end end @@ -485,25 +485,4 @@ end end end - - describe "#text_search" do - - before do - Word.with(database: "admin").mongo_session.command(setParameter: 1, textSearchEnabled: true) - Word.create_indexes - Word.create!(name: "phase", origin: "latin") - end - - after(:all) do - Word.remove_indexes - end - - let(:search) do - Word.text_search("phase") - end - - it "returns all fields" do - expect(search.first.origin).to eq("latin") - end - end end diff --git a/spec/mongoid/indexable_spec.rb b/spec/mongoid/indexable_spec.rb index 5f7780acb7..747c11a737 100644 --- a/spec/mongoid/indexable_spec.rb +++ b/spec/mongoid/indexable_spec.rb @@ -41,13 +41,13 @@ end end - context "when database specific options exist" do + context "when database specific options exist", if: non_legacy_server? do let(:klass) do Class.new do include Mongoid::Document store_in collection: "test_db_remove" - index({ test: 1 }, { database: "mia_2" }) + index({ test: 1 }, { database: "mongoid_optional" }) index({ name: 1 }, { background: true }) end end @@ -58,7 +58,7 @@ end let(:indexes) do - klass.with(database: "mia_2").collection.indexes + klass.with(database: "mongoid_optional").collection.indexes end it "creates the indexes" do @@ -84,17 +84,17 @@ end it "creates the indexes" do - expect(klass.collection.indexes[_type: 1]).to_not be_nil + expect(klass.collection.indexes.get(_type: 1)).to_not be_nil end end - context "when database options are specified" do + context "when database options are specified", if: non_legacy_server? do let(:klass) do Class.new do include Mongoid::Document store_in collection: "test_db_indexes" - index({ _type: 1 }, { database: "mia_1" }) + index({ _type: 1 }, { database: "mongoid_optional" }) end end @@ -102,12 +102,16 @@ klass.create_indexes end + after do + klass.remove_indexes + end + let(:indexes) do - klass.with(database: "mia_1").collection.indexes + klass.with(database: "mongoid_optional").collection.indexes end it "creates the indexes" do - expect(indexes[_type: 1]).to_not be_nil + expect(indexes.get(_type: 1)).to_not be_nil end end end diff --git a/spec/mongoid/log_subscriber_spec.rb b/spec/mongoid/log_subscriber_spec.rb deleted file mode 100644 index c9c333d06a..0000000000 --- a/spec/mongoid/log_subscriber_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -require "spec_helper" - -describe Mongoid::LogSubscriber do - - describe ".query" do - - let!(:subscribe) do - Mongoid::LogSubscriber.log_subscribers.first - end - - before do - @old_level, Moped.logger.level = Moped.logger.level, 0 - end - - after do - Moped.logger.level = @old_level - end - - context "when quering the database" do - - it "logs the operation" do - expect(subscribe).to receive(:debug).once - Band.all.to_a - end - end - - context "when creating a new subscriber" do - - class TestLogSubscriber < ActiveSupport::LogSubscriber - attr_reader :debugs - - def initialize - super - @debugs = [] - end - - def query(event) - @debugs << event - end - - def logger - Moped.logger - end - end - - let(:test_subscriber) do - TestLogSubscriber.new - end - - before do - ActiveSupport::LogSubscriber.attach_to :moped, test_subscriber - end - - after do - TestLogSubscriber.log_subscribers.pop - end - - it "pushes the new log subscriber" do - expect(Mongoid::LogSubscriber.subscribers.last).to be_a TestLogSubscriber - end - - context "when quering the database" do - - before do - expect(subscribe).to receive(:debug).once - PetOwner.all.to_a - end - - it "sends operations logs to TestLogSubscriber" do - expect(test_subscriber.debugs.size).to eq(1) - end - end - end - end -end diff --git a/spec/mongoid/persistable/updatable_spec.rb b/spec/mongoid/persistable/updatable_spec.rb index 5874dc1bc9..11ffec7dfb 100644 --- a/spec/mongoid/persistable/updatable_spec.rb +++ b/spec/mongoid/persistable/updatable_spec.rb @@ -284,7 +284,7 @@ it "raises an error" do expect { person.update_attributes(map: { "bad.key" => "value" }) - }.to raise_error(Moped::Errors::OperationFailure) + }.to raise_error(Mongo::Error::OperationFailure) end end @@ -320,7 +320,7 @@ it "raises an error" do expect { person.send(method, map: { "bad.key" => "value" }) - }.to raise_error(Moped::Errors::OperationFailure) + }.to raise_error(Mongo::Error::OperationFailure) end end diff --git a/spec/mongoid/persistable_spec.rb b/spec/mongoid/persistable_spec.rb index dfa8d4bf02..3b5ebcd066 100644 --- a/spec/mongoid/persistable_spec.rb +++ b/spec/mongoid/persistable_spec.rb @@ -61,7 +61,7 @@ end before do - expect_any_instance_of(Moped::Query).to receive(:update).with(operations).and_call_original + expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(operations).and_call_original end let!(:update) do @@ -88,7 +88,7 @@ end before do - expect_any_instance_of(Moped::Query).to receive(:update).with(operations).and_call_original + expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(operations).and_call_original end let!(:update) do @@ -116,7 +116,7 @@ end before do - expect_any_instance_of(Moped::Query).to receive(:update).with(operations).and_call_original + expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(operations).and_call_original end let!(:update) do @@ -153,7 +153,7 @@ end before do - expect_any_instance_of(Moped::Query).to receive(:update).with(operations).and_call_original + expect_any_instance_of(Mongo::Collection::View).to receive(:update_one).with(operations).and_call_original end let!(:update) do diff --git a/spec/mongoid/query_cache_spec.rb b/spec/mongoid/query_cache_spec.rb index ba1e392b09..d1bb9798b1 100644 --- a/spec/mongoid/query_cache_spec.rb +++ b/spec/mongoid/query_cache_spec.rb @@ -15,7 +15,7 @@ Band.all.send(method) end - context "when query cache disable" do + context "when query cache is disabled" do before do Mongoid::QueryCache.enabled = false @@ -54,7 +54,7 @@ Band.all.to_a end - context "when query cache disable" do + context "when query cache is disabled" do before do Mongoid::QueryCache.enabled = false @@ -76,20 +76,24 @@ end context "when querying only the first" do - let(:game) { Game.create!(name: "2048") } + + let(:game) do + Game.create!(name: "2048") + end before do game.ratings.where(:value.gt => 5).asc(:id).all.to_a end - it "queries again" do - expect_query(1) do + it "does not query again" do + expect_no_queries do game.ratings.where(:value.gt => 5).asc(:id).first end end end - context "limiting the result" do + context "when limiting the result" do + it "queries again" do expect_query(1) do Band.limit(2).all.to_a @@ -97,7 +101,8 @@ end end - context "specifying a different skip value" do + context "when specifying a different skip value" do + before do Band.limit(2).skip(1).all.to_a end @@ -213,7 +218,7 @@ it "does not cache the query" do expect(Mongoid::QueryCache).to receive(:cache_table).never - Band.collection.indexes.create(name: 1) + Band.collection.indexes.create_one(name: 1) end end end diff --git a/spec/mongoid/relations/auto_save_spec.rb b/spec/mongoid/relations/auto_save_spec.rb index f866258f56..bd33cd0d9f 100644 --- a/spec/mongoid/relations/auto_save_spec.rb +++ b/spec/mongoid/relations/auto_save_spec.rb @@ -150,7 +150,7 @@ end end - context "when updating the child" do + pending "when updating the child" do before do person.account = account diff --git a/spec/mongoid/relations/embedded/many_spec.rb b/spec/mongoid/relations/embedded/many_spec.rb index 48d48c7f10..1373454744 100644 --- a/spec/mongoid/relations/embedded/many_spec.rb +++ b/spec/mongoid/relations/embedded/many_spec.rb @@ -3873,7 +3873,7 @@ class TrackingIdValidationHistory before do band.collection. find(_id: band.id). - update("$set" => { records: [{ name: "Moderat" }]}) + update_one("$set" => { records: [{ name: "Moderat" }]}) end context "when loading the documents" do diff --git a/spec/mongoid/relations/embedded/one_spec.rb b/spec/mongoid/relations/embedded/one_spec.rb index 55051a0027..6c44a53c28 100644 --- a/spec/mongoid/relations/embedded/one_spec.rb +++ b/spec/mongoid/relations/embedded/one_spec.rb @@ -947,7 +947,7 @@ class << person context "when a parent was removed outside of mongoid" do before do - person.collection.where(_id: person.id).update( + person.collection.find(_id: person.id).update_one( "$pull" => { "addresses" => { _id: address_one.id }} ) end @@ -982,7 +982,7 @@ class << person before do band.collection. find(_id: band.id). - update("$set" => { label: { name: "Mute" }}) + update_one("$set" => { label: { name: "Mute" }}) end context "when loading the documents" do diff --git a/spec/mongoid/relations/referenced/in_spec.rb b/spec/mongoid/relations/referenced/in_spec.rb index 8c2a36f414..9dceecae08 100644 --- a/spec/mongoid/relations/referenced/in_spec.rb +++ b/spec/mongoid/relations/referenced/in_spec.rb @@ -1240,7 +1240,7 @@ class C before do Person.collection.find({ _id: person_one.id }). - update({ "$set" => { title: "Madam" }}) + update_one({ "$set" => { title: "Madam" }}) end let(:reloaded) do diff --git a/spec/mongoid/relations/referenced/many_spec.rb b/spec/mongoid/relations/referenced/many_spec.rb index 23eb208b4b..17134a96f0 100644 --- a/spec/mongoid/relations/referenced/many_spec.rb +++ b/spec/mongoid/relations/referenced/many_spec.rb @@ -292,7 +292,7 @@ it "raises an error" do expect { person.posts.send(method, post) - }.to raise_error(Moped::Errors::OperationFailure) + }.to raise_error(Mongo::Error::OperationFailure) end end end @@ -1536,7 +1536,7 @@ person.posts.create do |doc| doc._id = existing.id end - }.to raise_error(Moped::Errors::OperationFailure) + }.to raise_error(Mongo::Error::OperationFailure) end end end @@ -3344,7 +3344,7 @@ before do Post.collection.find({ _id: post_one.id }). - update({ "$set" => { title: "reloaded" }}) + update_one({ "$set" => { title: "reloaded" }}) end let(:reloaded) do diff --git a/spec/mongoid/relations/referenced/many_to_many_spec.rb b/spec/mongoid/relations/referenced/many_to_many_spec.rb index 7711cfc4ff..ecb506fe31 100644 --- a/spec/mongoid/relations/referenced/many_to_many_spec.rb +++ b/spec/mongoid/relations/referenced/many_to_many_spec.rb @@ -3274,7 +3274,7 @@ before do Preference.collection.find({ _id: preference_one.id }). - update({ "$set" => { name: "reloaded" }}) + update_one({ "$set" => { name: "reloaded" }}) end let(:reloaded) do diff --git a/spec/mongoid/relations/referenced/one_spec.rb b/spec/mongoid/relations/referenced/one_spec.rb index 4de199d6f5..8aa5649796 100644 --- a/spec/mongoid/relations/referenced/one_spec.rb +++ b/spec/mongoid/relations/referenced/one_spec.rb @@ -1178,7 +1178,7 @@ before do Game.collection.find({ _id: game_one.id }). - update({ "$set" => { name: "Diablo 2" }}) + update_one({ "$set" => { name: "Diablo 2" }}) end let(:reloaded) do diff --git a/spec/mongoid/reloadable_spec.rb b/spec/mongoid/reloadable_spec.rb index 8e5b3d5c07..065750179d 100644 --- a/spec/mongoid/reloadable_spec.rb +++ b/spec/mongoid/reloadable_spec.rb @@ -115,7 +115,7 @@ before do Person.collection.find( { "_id" => person.id } - ).update({ "$set" => { "addresses.0.number" => 3 }}) + ).update_one({ "$set" => { "addresses.0.number" => 3 }}) end let!(:reloaded) do @@ -143,7 +143,7 @@ before do Person.collection.find({ "_id" => person.id }). - update({ "$set" => { "name.last_name" => "Vicious" }}) + update_one({ "$set" => { "name.last_name" => "Vicious" }}) end let!(:reloaded) do @@ -176,7 +176,7 @@ before do Person.collection.find({ "_id" => person.id }). - update({ "$set" => { "addresses.0.locations.0.name" => "work" }}) + update_one({ "$set" => { "addresses.0.locations.0.name" => "work" }}) end let!(:reloaded) do @@ -209,7 +209,7 @@ before do Person.collection.find({ "_id" => person.id }). - update({ "$set" => { "addresses" => [] }}) + update_one({ "$set" => { "addresses" => [] }}) person.reload end @@ -232,7 +232,7 @@ before do Game.collection.find({ "_id" => game.id }). - update({ "$set" => { "score" => 75 }}) + update_one({ "$set" => { "score" => 75 }}) person.reload end @@ -251,7 +251,7 @@ before do Person.collection.find({ "_id" => person.id }). - update({ "$set" => { "title" => "Mam" }}) + update_one({ "$set" => { "title" => "Mam" }}) game.reload end diff --git a/spec/mongoid/sessions/factory_spec.rb b/spec/mongoid/sessions/factory_spec.rb index 94668f8635..60541359b9 100644 --- a/spec/mongoid/sessions/factory_spec.rb +++ b/spec/mongoid/sessions/factory_spec.rb @@ -12,13 +12,13 @@ let(:config) do { - default: { hosts: [ "localhost:27017" ], database: database_id }, - secondary: { hosts: [ "localhost:27017" ], database: database_id } + default: { hosts: [ "127.0.0.1:27017" ], database: database_id }, + secondary: { hosts: [ "127.0.0.1:27017" ], database: database_id } } end before do - Mongoid::Config.sessions = config + Mongoid::Config.send(:sessions=, config) end let(:session) do @@ -30,11 +30,11 @@ end it "returns a session" do - expect(session).to be_a(Moped::Session) + expect(session).to be_a(Mongo::Client) end it "sets the cluster's seeds" do - expect(cluster.seeds.first.address.resolved).to eq("127.0.0.1:27017") + expect(cluster.addresses.first.to_s).to eq("127.0.0.1:27017") end end @@ -43,12 +43,12 @@ let(:config) do { default: { hosts: [ "127.0.0.1" ], database: database_id }, - secondary: { hosts: [ "localhost" ], database: database_id } + secondary: { hosts: [ "127.0.0.1" ], database: database_id } } end before do - Mongoid::Config.sessions = config + Mongoid::Config.send(:sessions=, config) end let(:session) do @@ -64,15 +64,15 @@ end it "returns a session" do - expect(session).to be_a(Moped::Session) + expect(session).to be_a(Mongo::Client) end it "sets the cluster's seed ports to 27017" do - expect(cluster.seeds.first.address.original).to eq("localhost:27017") + expect(cluster.addresses.first.to_s).to eq("127.0.0.1:27017") end it "sets ips with no ports to 27017" do - expect(default.cluster.seeds.first.address.original).to eq("127.0.0.1:27017") + expect(default.cluster.addresses.first.to_s).to eq("127.0.0.1:27017") end end @@ -82,13 +82,13 @@ let(:config) do { - default: { hosts: [ "localhost:27017" ], database: database_id }, - secondary: { uri: "mongodb://localhost:27017/mongoid_test" } + default: { hosts: [ "127.0.0.1:27017" ], database: database_id }, + secondary: { uri: "mongodb://127.0.0.1:27017/mongoid_test" } } end before do - Mongoid::Config.sessions = config + Mongoid::Config.send(:sessions=, config) end let(:session) do @@ -100,44 +100,29 @@ end it "returns a session" do - expect(session).to be_a(Moped::Session) + expect(session).to be_a(Mongo::Client) end it "sets the cluster's seeds" do - expect(cluster.seeds.first.address.original).to eq("localhost:27017") + expect(cluster.addresses.first.to_s).to eq("127.0.0.1:27017") end it "sets the database" do expect(session.options[:database]).to eq("mongoid_test") end - - it "sets the database in the configuration" do - session - expect(Mongoid.sessions[:secondary]).to include(:database) - end - - it "sets the hosts in the configuration" do - session - expect(Mongoid.sessions[:secondary]).to include(:hosts) - end - - it "removes the uri from the configuration" do - session - expect(Mongoid.sessions[:secondary]).to_not include(:uri) - end end context "when the uri has multiple host:port pairs" do let(:config) do { - default: { hosts: [ "localhost:27017" ], database: database_id }, - secondary: { uri: "mongodb://localhost:27017,localhost:27017/mongoid_test" } + default: { hosts: [ "127.0.0.1:27017" ], database: database_id }, + secondary: { uri: "mongodb://127.0.0.1:27017,127.0.0.1:27018/mongoid_test" } } end before do - Mongoid::Config.sessions = config + Mongoid::Config.send(:sessions=, config) end let(:session) do @@ -149,34 +134,15 @@ end let(:seeds) do - cluster.seeds.map{ |node| node.address.original } + cluster.addresses.map{ |address| address.to_s } end it "returns a session" do - expect(session).to be_a(Moped::Session) + expect(session).to be_a(Mongo::Client) end it "sets the cluster's seeds" do - expect(seeds).to eq([ "localhost:27017", "localhost:27017" ]) - end - - it "sets the database" do - expect(session.options[:database]).to eq("mongoid_test") - end - - it "sets the database in the configuration" do - session - expect(Mongoid.sessions[:secondary]).to include(:database) - end - - it "sets the hosts in the configuration" do - session - expect(Mongoid.sessions[:secondary]).to include(:hosts) - end - - it "removes the uri from the configuration" do - session - expect(Mongoid.sessions[:secondary]).to_not include(:uri) + expect(seeds).to eq([ "127.0.0.1:27017", "127.0.0.1:27018" ]) end end end @@ -195,11 +161,11 @@ context "when no name is provided" do let(:config) do - { default: { hosts: ["localhost:27017"], database: database_id }} + { default: { hosts: ["127.0.0.1:27017"], database: database_id }} end before do - Mongoid::Config.sessions = config + Mongoid::Config.send(:sessions=, config) end let(:session) do @@ -211,15 +177,15 @@ end let(:seeds) do - cluster.seeds.map{ |node| node.address.original } + cluster.addresses.map{ |address| address.to_s } end it "returns the default session" do - expect(session).to be_a(Moped::Session) + expect(session).to be_a(Mongo::Client) end it "sets the cluster's seeds" do - expect(seeds).to eq([ "localhost:27017" ]) + expect(seeds).to eq([ "127.0.0.1:27017" ]) end end @@ -240,11 +206,11 @@ describe ".default" do let(:config) do - { default: { hosts: ["localhost:27017"], database: database_id }} + { default: { hosts: ["127.0.0.1:27017"], database: database_id }} end before do - Mongoid::Config.sessions = config + Mongoid::Config.send(:sessions=, config) end let(:session) do @@ -256,15 +222,15 @@ end let(:seeds) do - cluster.seeds.map{ |node| node.address.original } + cluster.addresses.map{ |address| address.to_s } end it "returns the default session" do - expect(session).to be_a(Moped::Session) + expect(session).to be_a(Mongo::Client) end it "sets the cluster's seeds" do - expect(seeds).to eq([ "localhost:27017" ]) + expect(seeds).to eq([ "127.0.0.1:27017" ]) end end @@ -273,13 +239,10 @@ let(:config) do { default: { - hosts: [ "localhost:27017" ], + hosts: [ "127.0.0.1:27017" ], database: database_id, options: { - "down_interval" => 10, - "max_retries" => 5, - "refresh_interval" => 30, - "retry_interval" => 0.1, + "server_selection_timeout" => 10, "write" => { "w" => 1 } } } @@ -287,7 +250,7 @@ end before do - Mongoid::Config.sessions = config + Mongoid::Config.send(:sessions=, config) end let(:session) do @@ -299,35 +262,23 @@ end let(:seeds) do - cluster.seeds.map{ |node| node.address.original } + cluster.addresses.map{ |address| address.to_s } end it "returns the default session" do - expect(session).to be_a(Moped::Session) + expect(session).to be_a(Mongo::Client) end it "sets the cluster's seeds" do - expect(seeds).to eq([ "localhost:27017" ]) - end - - it "sets the cluster down interval" do - expect(cluster.down_interval).to eq(10) - end - - it "sets the cluster max retries" do - expect(cluster.max_retries).to eq(5) - end - - it "sets the cluster refresh interval" do - expect(cluster.refresh_interval).to eq(30) + expect(seeds).to eq([ "127.0.0.1:27017" ]) end - it "sets the cluster retry interval" do - expect(cluster.retry_interval).to eq(0.1) + it "sets the server selection timeout" do + expect(cluster.options[:server_selection_timeout]).to eq(10) end it "sets the write concern" do - expect(session.write_concern).to be_a(Moped::WriteConcern::Propagate) + expect(session.write_concern).to be_a(Mongo::WriteConcern::Acknowledged) end end end diff --git a/spec/mongoid/sessions/mongo_uri_spec.rb b/spec/mongoid/sessions/mongo_uri_spec.rb deleted file mode 100644 index b4c417cbfe..0000000000 --- a/spec/mongoid/sessions/mongo_uri_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -require "spec_helper" - -describe Mongoid::Sessions::MongoUri do - - let(:single) do - "mongodb://user:pass@localhost:27017/mongoid_test" - end - - let(:multiple) do - "mongodb://localhost:27017,localhost:27017/mongoid_test" - end - - describe "#database" do - - let(:uri) do - described_class.new(single) - end - - it "returns the database name" do - expect(uri.database).to eq("mongoid_test") - end - end - - describe "#hosts" do - - context "when a single node is provided" do - - let(:uri) do - described_class.new(single) - end - - it "returns an array with 1 node" do - expect(uri.hosts).to eq([ "localhost:27017" ]) - end - end - - context "when multiple nodes are provided" do - - let(:uri) do - described_class.new(multiple) - end - - it "returns an array with 2 nodes" do - expect(uri.hosts).to eq([ "localhost:27017", "localhost:27017" ]) - end - end - end - - describe "#password" do - - let(:uri) do - described_class.new(single) - end - - it "returns the password" do - expect(uri.password).to eq("pass") - end - end - - describe "#to_hash" do - - context "when a user and password are not provided" do - - let(:uri) do - described_class.new(multiple) - end - - it "does not include the username and password" do - expect(uri.to_hash).to eq({ - hosts: [ "localhost:27017", "localhost:27017" ], - database: "mongoid_test" - }) - end - end - - context "when a user and password are provided" do - - let(:uri) do - described_class.new(single) - end - - it "includes the username and password" do - expect(uri.to_hash).to eq({ - hosts: [ "localhost:27017" ], - database: "mongoid_test", - username: "user", - password: "pass" - }) - end - end - end - - describe "#username" do - - let(:uri) do - described_class.new(single) - end - - it "returns the userame" do - expect(uri.username).to eq("user") - end - end -end diff --git a/spec/mongoid/sessions/options_spec.rb b/spec/mongoid/sessions/options_spec.rb index 980238c473..d716c1ab98 100644 --- a/spec/mongoid/sessions/options_spec.rb +++ b/spec/mongoid/sessions/options_spec.rb @@ -2,7 +2,7 @@ describe Mongoid::Sessions::Options do - describe "#with" do + describe "#with", if: non_legacy_server? do context "when passing some options" do @@ -52,7 +52,7 @@ end end - describe ".with" do + describe ".with", if: non_legacy_server? do let(:options) { { database: 'test' } } @@ -65,9 +65,7 @@ end it "passes down the options to collection" do - session = Band.mongo_session - expect_any_instance_of(Moped::Session).to receive(:with).with(options).and_return(session) - instance.collection + expect(instance.collection.database.name).to eq('test') end end diff --git a/spec/mongoid/sessions_spec.rb b/spec/mongoid/sessions_spec.rb index c697bc6e6c..3e809091c8 100644 --- a/spec/mongoid/sessions_spec.rb +++ b/spec/mongoid/sessions_spec.rb @@ -11,7 +11,7 @@ end it "returns the collection for the model" do - expect(band.collection).to be_a(Moped::Collection) + expect(band.collection).to be_a(Mongo::Collection) end it "sets the correct collection name" do @@ -21,7 +21,7 @@ context "when accessing from the class level" do it "returns the collection for the model" do - expect(klass.collection).to be_a(Moped::Collection) + expect(klass.collection).to be_a(Mongo::Collection) end it "sets the correct collection name" do @@ -124,7 +124,7 @@ end it "returns the collection for the model" do - expect(band.collection).to be_a(Moped::Collection) + expect(band.collection).to be_a(Mongo::Collection) end it "sets the correct collection name" do @@ -134,7 +134,7 @@ context "when accessing from the class level" do it "returns the collection for the model" do - expect(Band.collection).to be_a(Moped::Collection) + expect(Band.collection).to be_a(Mongo::Collection) end it "sets the correct collection name" do @@ -266,7 +266,7 @@ end end - describe "#database_name" do + describe "#database_name", if: non_legacy_server? do shared_examples_for "an overridden database name" do @@ -372,7 +372,7 @@ end end - describe "#mongo_session" do + describe "#mongo_session", if: non_legacy_server? do let(:file) do File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml") @@ -409,157 +409,6 @@ end end - context "when overridden the database with store_in" do - - before do - Band.store_in(database: database_id_alt) - end - - after do - Band.store_in(database: database_id) - end - - context "on instance level" do - - let(:band) do - Band.new.with({:read=>:primary}) - end - - it "uses the new database" do - expect(band.mongo_session.send(:current_database).name).to eq database_id_alt - end - - context "when using another database before" do - - before do - band - User.create! - end - - it "uses the new database" do - expect(band.mongo_session.send(:current_database).name).to eq database_id_alt - end - end - end - end - - context "when overriding to a monghq single server", config: :mongohq do - - shared_examples_for "an overridden session to a mongohq single server" do - - let(:band) do - Band.new - end - - let(:single_session) do - band.mongo_session - end - - it "returns the default session" do - expect(single_session.options[:database].to_s).to eq(ENV["MONGOHQ_SINGLE_NAME"]) - end - end - - context "when overriding with a proc" do - - before do - Band.store_in(session: ->{ :mongohq_single }) - end - - it_behaves_like "an overridden session to a mongohq single server" - end - - context "when overriding with a string" do - - before do - Band.store_in(session: "mongohq_single") - end - - it_behaves_like "an overridden session to a mongohq single server" - end - - context "when overriding with a symbol" do - - before do - Band.store_in(session: :mongohq_single) - end - - it_behaves_like "an overridden session to a mongohq single server" - end - end - - context "when overriding to a mongohq replica set", config: :mongohq do - - let(:band) do - Band.new - end - - let(:replica_session) do - band.mongo_session - end - - shared_examples_for "an overridden session to a mongohq replica set" do - - let(:seeds) do - replica_session.cluster.seeds.map{ |node| node.address.original } - end - - it "returns the overridden session" do - expect(seeds).to eq([ ENV["MONGOHQ_REPL_1_URL"], ENV["MONGOHQ_REPL_2_URL"] ]) - end - end - - context "when overriding with a proc" do - - before do - Band.store_in(session: ->{ :mongohq_repl }) - end - - it_behaves_like "an overridden session to a mongohq replica set" - end - - context "when overriding with a string" do - - before do - Band.store_in(session: "mongohq_repl") - end - - it_behaves_like "an overridden session to a mongohq replica set" - end - - context "when overriding with a symbol" do - - before do - Band.store_in(session: :mongohq_repl) - end - - it_behaves_like "an overridden session to a mongohq replica set" - end - end - - context "when overriding to a mongohq replica set with uri config", config: :mongohq do - - before(:all) do - Band.store_in(session: :mongohq_repl_uri) - end - - let(:band) do - Band.new - end - - let(:repl_session) do - band.mongo_session - end - - let(:seeds) do - repl_session.cluster.seeds.map{ |node| node.address.original } - end - - it "returns the overridden session" do - expect(seeds).to eq([ ENV["MONGOHQ_REPL_1_URL"], ENV["MONGOHQ_REPL_2_URL"] ]) - end - end - context "when no session exists with the key" do before(:all) do @@ -578,7 +427,7 @@ end end - describe ".mongo_session" do + describe ".mongo_session", if: non_legacy_server? do let(:file) do File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml") @@ -616,40 +465,6 @@ end end - context "when overriding to a monghq single server", config: :mongohq do - - before(:all) do - Band.store_in(session: :mongohq_single) - end - - let(:session) do - Band.mongo_session - end - - it "returns the default session" do - expect(session.options[:database].to_s).to eq(ENV["MONGOHQ_SINGLE_NAME"]) - end - end - - context "when overriding to a mongohq replica set", config: :mongohq do - - before(:all) do - Band.store_in(session: :mongohq_repl) - end - - let(:repl_session) do - Band.mongo_session - end - - let(:seeds) do - repl_session.cluster.seeds.map{ |node| node.address.original } - end - - it "returns the overridden session" do - expect(seeds).to eq([ ENV["MONGOHQ_REPL_1_URL"], ENV["MONGOHQ_REPL_2_URL"] ]) - end - end - context "when no session exists with the key" do before(:all) do @@ -664,7 +479,7 @@ end end - describe ".store_in" do + describe ".store_in", if: non_legacy_server? do context "when provided a non hash" do @@ -701,7 +516,7 @@ end end - describe ".with" do + describe ".with", if: non_legacy_server? do context "when sending operations to a different database" do @@ -733,65 +548,6 @@ expect(Band.with(database: database_id_alt).count).to eq(1) end end - - describe ".map_reduce", config: :mongohq do - - let(:map) do - %Q{ - function() { - emit(this.name, { likes: this.likes }); - }} - end - - let(:reduce) do - %Q{ - function(key, values) { - var result = { likes: 0 }; - values.forEach(function(value) { - result.likes += value.likes; - }); - return result; - }} - end - - before do - Band.with(database: database_id_alt).delete_all - end - - let!(:depeche_mode) do - Band.with(database: database_id_alt). - create(name: "Depeche Mode", likes: 200) - end - - let!(:tool) do - Band.with(database: database_id_alt). - create(name: "Tool", likes: 100) - end - - context "when outputting in memory" do - - let(:results) do - Band.with(database: database_id_alt). - map_reduce(map, reduce).out(inline: 1) - end - - it "executes the map/reduce on the correct database" do - expect(results.first["value"]).to eq({ "likes" => 200 }) - end - end - - context "when outputting to a collection" do - - let(:results) do - Band.with(database: database_id_alt). - map_reduce(map, reduce).out(replace: "bands_output") - end - - it "executes the map/reduce on the correct database" do - expect(results.first["value"]).to eq({ "likes" => 200 }) - end - end - end end context "when sending operations to a different collection" do @@ -820,190 +576,6 @@ expect(Band.with(collection: "artists").count).to eq(1) end end - - describe ".map_reduce", config: :mongohq do - - let(:map) do - %Q{ - function() { - emit(this.name, { likes: this.likes }); - }} - end - - let(:reduce) do - %Q{ - function(key, values) { - var result = { likes: 0 }; - values.forEach(function(value) { - result.likes += value.likes; - }); - return result; - }} - end - - before do - Band.with(collection: "artists").delete_all - end - - let!(:depeche_mode) do - Band.with(collection: "artists"). - create(name: "Depeche Mode", likes: 200) - end - - let!(:tool) do - Band.with(collection: "artists"). - create(name: "Tool", likes: 100) - end - - let(:results) do - Band.with(collection: "artists"). - map_reduce(map, reduce).out(inline: 1) - end - - it "executes the map/reduce on the correct collection" do - expect(results.first["value"]).to eq({ "likes" => 200 }) - end - end - end - - context "when sending operations to a different session" do - - describe ".create" do - - let(:file) do - File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml") - end - - before do - described_class.clear - Mongoid.load!(file, :test) - end - - context "when sending to a mongohq single server", config: :mongohq do - - let!(:band) do - Band.with( - session: "mongohq_single", - database: database_id - ).create - end - - let(:from_db) do - Band.with( - session: "mongohq_single", - database: database_id - ).find(band.id) - end - - it "persists to the specified database" do - expect(from_db).to eq(band) - end - end - - context "when sending to a mongohq replica set", config: :mongohq do - - let!(:band) do - Band.with( - session: "mongohq_repl", - database: "mongoid_replica" - ).create - end - - let(:from_db) do - Band.with( - session: "mongohq_repl", - database: "mongoid_replica" - ).find(band.id) - end - - it "persists to the specified database" do - expect(from_db).to eq(band) - end - end - - context "when sending to a mongohq replica set with uri config", config: :mongohq do - - let!(:band) do - Band.with( - session: "mongohq_repl_uri", - database: "mongoid_replica" - ).create - end - - let(:from_db) do - Band.with( - session: "mongohq_repl_uri", - database: "mongoid_replica" - ).find(band.id) - end - - it "persists to the specified database" do - expect(from_db).to eq(band) - end - end - end - - describe ".map_reduce", config: :mongohq do - - let(:file) do - File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml") - end - - before do - described_class.clear - Mongoid.load!(file, :test) - end - - let(:map) do - %Q{ - function() { - emit(this.name, { likes: this.likes }); - }} - end - - let(:reduce) do - %Q{ - function(key, values) { - var result = { likes: 0 }; - values.forEach(function(value) { - result.likes += value.likes; - }); - return result; - }} - end - - before do - Band.with( - session: "mongohq_repl", - database: "mongoid_replica" - ).delete_all - end - - let!(:depeche_mode) do - Band.with( - session: "mongohq_repl", - database: "mongoid_replica" - ).create(name: "Depeche Mode", likes: 200) - end - - let!(:tool) do - Band.with( - session: "mongohq_repl", - database: "mongoid_replica" - ).create(name: "Tool", likes: 100) - end - - let(:results) do - Band.with( - session: "mongohq_repl", - database: "mongoid_replica" - ).map_reduce(map, reduce).out(inline: 1) - end - - it "executes the map/reduce on the correct session" do - expect(results.first["value"]).to eq({ "likes" => 200 }) - end - end end context "when sending operations with safe mode" do @@ -1027,18 +599,7 @@ it "bubbles up to the caller" do expect { Person.create(ssn: "432-97-1111") - }.to raise_error(Moped::Errors::OperationFailure) - end - end - - context "when using write -1" do - - let(:new_person) do - Person.with(write: {w: -1}).create(ssn: "432-97-1111") - end - - it "ignores mongodb error" do - expect(new_person).to_not be nil + }.to raise_error(Mongo::Error::OperationFailure) end end end @@ -1065,7 +626,7 @@ it "bubbles up to the caller" do expect { Person.create!(ssn: "432-97-1112") - }.to raise_error(Moped::Errors::OperationFailure) + }.to raise_error(Mongo::Error::OperationFailure) end end @@ -1098,7 +659,7 @@ it "bubbles up to the caller" do expect { person.save - }.to raise_error(Moped::Errors::OperationFailure) + }.to raise_error(Mongo::Error::OperationFailure) end end end @@ -1122,7 +683,7 @@ it "bubbles up to the caller" do expect { person.save! - }.to raise_error(Moped::Errors::OperationFailure) + }.to raise_error(Mongo::Error::OperationFailure) end end @@ -1142,34 +703,7 @@ end end - context "when the default database uses a uri" do - - let(:file) do - File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml") - end - - let(:config) do - { default: { uri: "mongodb://localhost:#{PORT}/#{database_id}" }} - end - - before do - Mongoid::Threaded.sessions.clear - Mongoid.sessions = config - end - - context "when creating a document" do - - let!(:band) do - Band.create(name: "Placebo") - end - - it "persists the document to the correct database" do - expect(Band.find(band.id)).to eq(band) - end - end - end - - context "when overriding the default database "do + context "when overriding the default database", if: non_legacy_server? do let(:file) do File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml") @@ -1201,56 +735,4 @@ end end end - - context "when overriding the default session", config: :mongohq do - - context "when the override is configured with a uri" do - - let(:file) do - File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml") - end - - before do - Mongoid::Config.load!(file, :test) - Mongoid.override_session(:mongohq_repl_uri) - end - - after do - Mongoid.override_session(nil) - end - - it "has some database name on session" do - expect(Band.mongo_session.options[:database]).to eq(:mongoid_replica) - end - end - - context "when the override is global" do - - let(:file) do - File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml") - end - - before do - Mongoid::Config.load!(file, :test) - Mongoid.override_session(:mongohq_single) - end - - after do - Band.with(database: database_id).delete_all - Mongoid.override_session(nil) - end - - let!(:band) do - Band.with(database: database_id).create(name: "Tool") - end - - let(:persisted) do - Band.with(session: :mongohq_single, database: database_id).where(name: "Tool").first - end - - it "persists to the overridden session" do - expect(persisted).to eq(band) - end - end - end end diff --git a/spec/mongoid/tasks/database_rake_spec.rb b/spec/mongoid/tasks/database_rake_spec.rb index 1418991b8b..b4e16ca595 100644 --- a/spec/mongoid/tasks/database_rake_spec.rb +++ b/spec/mongoid/tasks/database_rake_spec.rb @@ -45,7 +45,7 @@ module Rails end end -describe "db:drop" do +describe "db:drop", if: non_legacy_server? do include_context "rake task" include_context "rails rake task" @@ -58,7 +58,7 @@ module Rails end end -describe "db:purge" do +describe "db:purge", if: non_legacy_server? do include_context "rake task" include_context "rails rake task" @@ -71,7 +71,7 @@ module Rails end end -describe "db:seed" do +describe "db:seed", if: non_legacy_server? do include_context "rake task" include_context "rails rake task" @@ -85,7 +85,7 @@ module Rails end end -describe "db:setup" do +describe "db:setup", if: non_legacy_server? do include_context "rake task" include_context "rails rake task" @@ -117,7 +117,7 @@ module Rails end end -describe "db:reset" do +describe "db:reset", if: non_legacy_server? do include_context "rake task" include_context "rails rake task" @@ -135,7 +135,7 @@ module Rails end end -describe "db:create" do +describe "db:create", if: non_legacy_server? do include_context "rake task" include_context "rails rake task" @@ -144,7 +144,7 @@ module Rails end end -describe "db:migrate" do +describe "db:migrate", if: non_legacy_server? do include_context "rake task" include_context "rails rake task" @@ -153,7 +153,7 @@ module Rails end end -describe "db:test:prepare" do +describe "db:test:prepare", if: non_legacy_server? do include_context "rake task" include_context "rails rake task" @@ -174,7 +174,7 @@ module Rails end end -describe "db:mongoid:create_indexes" do +describe "db:mongoid:create_indexes", if: non_legacy_server? do include_context "rake task" it_behaves_like "create_indexes" @@ -198,7 +198,7 @@ module Rails end end -describe "db:mongoid:remove_undefined_indexes" do +describe "db:mongoid:remove_undefined_indexes", if: non_legacy_server? do include_context "rake task" it "receives remove_undefined_indexes" do @@ -224,7 +224,7 @@ module Rails end end -describe "db:mongoid:remove_indexes" do +describe "db:mongoid:remove_indexes", if: non_legacy_server? do include_context "rake task" it "receives remove_indexes" do @@ -250,7 +250,7 @@ module Rails end end -describe "db:mongoid:drop" do +describe "db:mongoid:drop", if: non_legacy_server? do include_context "rake task" it "works" do @@ -266,7 +266,7 @@ module Rails end end -describe "db:mongoid:purge" do +describe "db:mongoid:purge", if: non_legacy_server? do include_context "rake task" it "receives a purge" do diff --git a/spec/mongoid/tasks/database_spec.rb b/spec/mongoid/tasks/database_spec.rb index d2c7c87edb..9483bef5ad 100644 --- a/spec/mongoid/tasks/database_spec.rb +++ b/spec/mongoid/tasks/database_spec.rb @@ -100,7 +100,7 @@ context "with extra index on model collection" do before(:each) do - User.collection.indexes.create(account_expires: 1) + User.collection.indexes.create_one(account_expires: 1) end let(:names) do @@ -121,7 +121,7 @@ before(:each) do Mongoid::Tasks::Database.create_indexes(models) - indexes.create(account_expires: 1) + indexes.create_one(account_expires: 1) Mongoid::Tasks::Database.remove_undefined_indexes(models) end diff --git a/spec/mongoid_spec.rb b/spec/mongoid_spec.rb index 1c36fc4700..0d51194d20 100644 --- a/spec/mongoid_spec.rb +++ b/spec/mongoid_spec.rb @@ -46,15 +46,13 @@ before do Band.all.entries - Mongoid.disconnect_sessions end - it "disconnects from all active sessions" do + pending "disconnects from all active sessions" do sessions.each do |session| - session.cluster.nodes.each do |node| - expect(node.send(:connected?)).to be false - end + expect(session.cluster).to receive(:disconnect!).and_call_original end + Mongoid.disconnect_sessions end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 87d374b635..a09b0928d6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -14,18 +14,17 @@ require "action_controller" require "mongoid" require "rspec" -require "helpers" # These environment variables can be set if wanting to test against a database # that is not on the local machine. -ENV["MONGOID_SPEC_HOST"] ||= "localhost" +ENV["MONGOID_SPEC_HOST"] ||= "127.0.0.1" ENV["MONGOID_SPEC_PORT"] ||= "27017" # These are used when creating any connection in the test suite. HOST = ENV["MONGOID_SPEC_HOST"] PORT = ENV["MONGOID_SPEC_PORT"].to_i -# Moped.logger.level = Logger::DEBUG +Mongo::Logger.logger.level = Logger::INFO # Mongoid.logger.level = Logger::DEBUG # When testing locally we use the database named mongoid_test. However when @@ -40,20 +39,40 @@ def database_id_alt "mongoid_test_alt" end +require 'support/authorization' +require 'support/expectations' + +# Give MongoDB time to start up on the travis ci environment. +if (ENV['CI'] == 'travis') + starting = true + client = Mongo::Client.new(['127.0.0.1:27017']) + while starting + begin + client.command(Mongo::Server::Monitor::STATUS) + break + rescue Mongo::Error::OperationFailure => e + sleep(2) + client.cluster.scan! + end + end +end + CONFIG = { sessions: { default: { database: database_id, - hosts: [ "#{HOST}:#{PORT}" ] + hosts: [ "#{HOST}:#{PORT}" ], + options: { + server_selection_timeout: 0.5, + max_pool_size: 1, + user: MONGOID_ROOT_USER.name, + password: MONGOID_ROOT_USER.password, + auth_source: Mongo::Database::ADMIN + } } } } -# Can we connect to MongoHQ from this box? -def mongohq_connectable? - ENV["MONGOHQ_REPL_PASS"].present? -end - def purge_database_alt! session = Mongoid::Sessions.default session.use(database_id_alt) @@ -62,9 +81,8 @@ def purge_database_alt! end end -def mongodb_version - session = Mongoid::Sessions.default - session.command(buildinfo: 1)["version"] +def non_legacy_server? + Mongoid::Sessions.default.cluster.servers.first.features.write_command_enabled? end # Set the database that the spec suite connects to. @@ -96,16 +114,46 @@ class Application < Rails::Application I18n.config.enforce_available_locales = false RSpec.configure do |config| - config.include Mongoid::SpecHelpers config.raise_errors_for_deprecations! + config.include(Mongoid::Expectations) + + config.before(:suite) do + client = Mongo::Client.new(["#{HOST}:#{PORT}"]) + begin + # Create the root user administrator as the first user to be added to the + # database. This user will need to be authenticated in order to add any + # more users to any other databases. + client.database.users.create(MONGOID_ROOT_USER) + rescue Exception => e + end + begin + # Adds the test user to the test database with permissions on all + # databases that will be used in the test suite. + client.with( + user: MONGOID_ROOT_USER.name, + password: MONGOID_ROOT_USER.password + ).database.users.create(MONGOID_TEST_USER) + rescue Exception => e + # If we are on versions less than 2.6, we need to create a user for + # each database, since the users are not stored in the admin database + # but in the system.users collection on the datbases themselves. Also, + # roles in versions lower than 2.6 can only be strings, not hashes. + unless client.cluster.servers.first.features.write_command_enabled? + begin + client.with( + user: MONGOID_ROOT_USER.name, + password: MONGOID_ROOT_USER.password, + auth_source: Mongo::Database::ADMIN, + database: database_id + ).database.users.create(MONGOID_LEGACY_TEST_USER) + rescue Exception => e + end + end + end + end # Drop all collections and clear the identity map before each spec. config.before(:each) do Mongoid.purge! end - - # Filter out MongoHQ specs if we can't connect to it. - config.filter_run_excluding(config: ->(value){ - return true if value == :mongohq && !mongohq_connectable? - }) end diff --git a/spec/support/authorization.rb b/spec/support/authorization.rb new file mode 100644 index 0000000000..0661ea1235 --- /dev/null +++ b/spec/support/authorization.rb @@ -0,0 +1,37 @@ +# Set up a root user so we can set up authentication on a database level. +MONGOID_ROOT_USER = Mongo::Auth::User.new( + database: Mongo::Database::ADMIN, + user: 'mongoid-user', + password: 'password', + roles: [ + Mongo::Auth::Roles::USER_ADMIN_ANY_DATABASE, + Mongo::Auth::Roles::DATABASE_ADMIN_ANY_DATABASE, + Mongo::Auth::Roles::READ_WRITE_ANY_DATABASE, + Mongo::Auth::Roles::HOST_MANAGER + ] +) + +# Test user for the suite for versions 2.6 and higher. +MONGOID_TEST_USER = Mongo::Auth::User.new( + database: Mongo::Database::ADMIN, + user: 'mongoid-test-user', + password: 'password', + roles: [ + { role: Mongo::Auth::Roles::READ_WRITE, db: database_id }, + { role: Mongo::Auth::Roles::DATABASE_ADMIN, db: database_id }, + { role: Mongo::Auth::Roles::READ_WRITE, db: database_id_alt }, + { role: Mongo::Auth::Roles::DATABASE_ADMIN, db: database_id_alt }, + { role: Mongo::Auth::Roles::READ_WRITE, db: 'mongoid_optional' }, + { role: Mongo::Auth::Roles::DATABASE_ADMIN, db: 'mongoid_optional' }, + { role: Mongo::Auth::Roles::READ_WRITE, db: 'test' }, + { role: Mongo::Auth::Roles::DATABASE_ADMIN, db: 'test' } + ] +) + +# Test user for the suite for version 2.4. +MONGOID_LEGACY_TEST_USER = Mongo::Auth::User.new( + database: database_id, + user: 'mongoid-test-user', + password: 'password', + roles: [ Mongo::Auth::Roles::READ_WRITE, Mongo::Auth::Roles::DATABASE_ADMIN ] +) diff --git a/spec/support/expectations.rb b/spec/support/expectations.rb new file mode 100644 index 0000000000..2e545515cf --- /dev/null +++ b/spec/support/expectations.rb @@ -0,0 +1,13 @@ +module Mongoid + module Expectations + + def expect_query(number) + expect(Mongo::Logger).to receive(:debug).exactly(number).times + yield + end + + def expect_no_queries(&block) + expect_query(0, &block) + end + end +end