mongo_mapper 0.14.0.rc1 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +5 -13
  2. data/LICENSE +1 -1
  3. data/{README.rdoc → README.md} +26 -21
  4. data/examples/keys.rb +1 -1
  5. data/examples/modifiers/set.rb +1 -1
  6. data/examples/querying.rb +1 -1
  7. data/examples/safe.rb +2 -2
  8. data/examples/scopes.rb +1 -1
  9. data/lib/mongo_mapper.rb +3 -0
  10. data/lib/mongo_mapper/connection.rb +16 -38
  11. data/lib/mongo_mapper/extensions/object_id.rb +5 -1
  12. data/lib/mongo_mapper/plugins/accessible.rb +1 -1
  13. data/lib/mongo_mapper/plugins/associations/base.rb +10 -2
  14. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +1 -1
  15. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +6 -0
  16. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +36 -6
  17. data/lib/mongo_mapper/plugins/associations/in_foreign_array_proxy.rb +136 -0
  18. data/lib/mongo_mapper/plugins/associations/many_association.rb +4 -2
  19. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +3 -1
  20. data/lib/mongo_mapper/plugins/associations/proxy.rb +11 -3
  21. data/lib/mongo_mapper/plugins/associations/single_association.rb +5 -4
  22. data/lib/mongo_mapper/plugins/dirty.rb +29 -37
  23. data/lib/mongo_mapper/plugins/document.rb +1 -1
  24. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +1 -1
  25. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +1 -0
  26. data/lib/mongo_mapper/plugins/embedded_document.rb +2 -2
  27. data/lib/mongo_mapper/plugins/identity_map.rb +3 -1
  28. data/lib/mongo_mapper/plugins/indexes.rb +13 -6
  29. data/lib/mongo_mapper/plugins/keys.rb +12 -7
  30. data/lib/mongo_mapper/plugins/keys/key.rb +13 -8
  31. data/lib/mongo_mapper/plugins/modifiers.rb +39 -14
  32. data/lib/mongo_mapper/plugins/persistence.rb +6 -2
  33. data/lib/mongo_mapper/plugins/querying.rb +9 -3
  34. data/lib/mongo_mapper/plugins/querying/decorated_plucky_query.rb +6 -6
  35. data/lib/mongo_mapper/plugins/safe.rb +10 -4
  36. data/lib/mongo_mapper/plugins/scopes.rb +19 -3
  37. data/lib/mongo_mapper/plugins/stats.rb +1 -3
  38. data/lib/mongo_mapper/plugins/strong_parameters.rb +26 -0
  39. data/lib/mongo_mapper/railtie.rb +1 -0
  40. data/lib/mongo_mapper/utils.rb +2 -2
  41. data/lib/mongo_mapper/version.rb +1 -1
  42. data/spec/examples.txt +1729 -0
  43. data/spec/functional/accessible_spec.rb +7 -1
  44. data/spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb +2 -2
  45. data/spec/functional/associations/belongs_to_proxy_spec.rb +55 -5
  46. data/spec/functional/associations/in_array_proxy_spec.rb +149 -14
  47. data/spec/functional/associations/in_foreign_array_proxy_spec.rb +321 -0
  48. data/spec/functional/associations/many_documents_as_proxy_spec.rb +6 -6
  49. data/spec/functional/associations/many_documents_proxy_spec.rb +22 -22
  50. data/spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb +2 -2
  51. data/spec/functional/associations/many_polymorphic_proxy_spec.rb +4 -4
  52. data/spec/functional/associations/one_as_proxy_spec.rb +8 -8
  53. data/spec/functional/associations/one_embedded_proxy_spec.rb +28 -0
  54. data/spec/functional/associations/one_proxy_spec.rb +19 -9
  55. data/spec/functional/associations_spec.rb +3 -3
  56. data/spec/functional/binary_spec.rb +2 -2
  57. data/spec/functional/caching_spec.rb +15 -22
  58. data/spec/functional/callbacks_spec.rb +2 -2
  59. data/spec/functional/counter_cache_spec.rb +10 -10
  60. data/spec/functional/dirty_spec.rb +48 -10
  61. data/spec/functional/dirty_with_callbacks_spec.rb +59 -0
  62. data/spec/functional/document_spec.rb +5 -8
  63. data/spec/functional/dumpable_spec.rb +1 -1
  64. data/spec/functional/embedded_document_spec.rb +5 -5
  65. data/spec/functional/identity_map_spec.rb +8 -8
  66. data/spec/functional/indexes_spec.rb +19 -18
  67. data/spec/functional/keys_spec.rb +51 -33
  68. data/spec/functional/logger_spec.rb +2 -2
  69. data/spec/functional/modifiers_spec.rb +81 -19
  70. data/spec/functional/partial_updates_spec.rb +8 -8
  71. data/spec/functional/protected_spec.rb +1 -1
  72. data/spec/functional/querying_spec.rb +70 -22
  73. data/spec/functional/safe_spec.rb +23 -27
  74. data/spec/functional/sci_spec.rb +7 -7
  75. data/spec/functional/scopes_spec.rb +89 -1
  76. data/spec/functional/static_keys_spec.rb +2 -2
  77. data/spec/functional/stats_spec.rb +28 -12
  78. data/spec/functional/strong_parameters_spec.rb +49 -0
  79. data/spec/functional/validations_spec.rb +8 -16
  80. data/spec/quality_spec.rb +1 -1
  81. data/spec/spec_helper.rb +39 -8
  82. data/spec/support/matchers.rb +1 -1
  83. data/spec/unit/associations/proxy_spec.rb +13 -5
  84. data/spec/unit/clone_spec.rb +1 -1
  85. data/spec/unit/document_spec.rb +3 -3
  86. data/spec/unit/embedded_document_spec.rb +4 -5
  87. data/spec/unit/extensions_spec.rb +2 -2
  88. data/spec/unit/identity_map_middleware_spec.rb +65 -96
  89. data/spec/unit/key_spec.rb +16 -17
  90. data/spec/unit/keys_spec.rb +17 -8
  91. data/spec/unit/mongo_mapper_spec.rb +41 -88
  92. data/spec/unit/rails_spec.rb +2 -2
  93. data/spec/unit/validations_spec.rb +18 -18
  94. metadata +53 -31
  95. data/lib/mongo_mapper/extensions/ordered_hash.rb +0 -23
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZDZhYzcyYjE1YmNiYTY4NTVlOGFiZjRlNjk1MTVjOWRkZWViODE3YQ==
5
- data.tar.gz: !binary |-
6
- YjUxMmRlMTUyOTM5ZjgwMTBlM2JlMzFjNWIxNTVjYWY4NDU3NTYxMA==
2
+ SHA256:
3
+ metadata.gz: 5d5192b00f4bce2f16b7ac329a9bdb059c888ebea3c62ba91e9017a42a43371c
4
+ data.tar.gz: 9e3f0dca756cb0e260266fa147800c07d02133dfad74376f3aaa169f56d67f36
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- N2ZhNWM1NmZlOTE3NDYwYjExZTZhODcxMTM1YzM3Yzg4NTY4ZjFlOTk4NDA1
10
- NGJkNDc3YTdhZWRiY2JlOWZjNWZjNDZjYjkzMzZlMmNkY2MxNWNjZTE4M2Q3
11
- OWYzYjBjNjcxNTVkODg4OTliODY5NTZjYWE1NzBjZGE1ZGU0NDA=
12
- data.tar.gz: !binary |-
13
- OWMyYjNmNTY5ZGNhOTM1MGNkNTg0MGFkNzkwMjg3Yjc5Y2M0MzM2ZjUwNTZm
14
- YjU1MjAxODYzOTllYzM4NzBjZjNmYmI2NGUzYWFiODQwMjNmN2E4MDAxYWYz
15
- MjQyNGQ4ZmU1OTcwMmRmOGZlMWQ4NDI1ZTJjYjU4ODViMjM4OWQ=
6
+ metadata.gz: 052506c11e7921c9412fdbbdaeedbc05a199700867502e87c73bb00d4bb649007ed4f5c8f3f57020f96084d26128aaf5ba9973504018a76a1ecf4cd93b014186
7
+ data.tar.gz: fb775b4103f3eaa22ae76c5e4875d6c3117e44db8c2e6cd39189800d0fcafb63a8d8368a91a195ea8380cf9ce0744431e41e303bec0c478d61c5606d4ca8bd14
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 John Nunemaker
1
+ Copyright (c) 2009-2020 MongoMapper: John Nunemaker, Chris Heald, Scott Taylor
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,39 +1,35 @@
1
- = MongoMapper
2
-
3
- {<img src="https://badge.fury.io/rb/mongo_mapper.png" alt="RubyGem" />}[https://rubygems.org/gems/mongo_mapper]
4
- {<img src="https://travis-ci.org/mongomapper/mongomapper.png?branch=master" alt="Build Status" />}[https://travis-ci.org/mongomapper/mongomapper]
5
- {<img src="https://coveralls.io/repos/jnunemaker/mongomapper/badge.png" alt="Coverage Status" />}[https://coveralls.io/r/jnunemaker/mongomapper]
1
+ # MongoMapper
6
2
 
7
3
  A Ruby Object Mapper for Mongo.
8
4
 
9
- == Install
5
+ [<img src="https://badge.fury.io/rb/mongo_mapper.svg" alt="RubyGems">](https://rubygems.org/gems/mongo_mapper)
6
+
7
+ [<img src="https://github.com/mongomapper/mongomapper/workflows/Ruby/badge.svg?branch=master" alt="Build Status" />](https://github.com/mongomapper/mongomapper/actions?query=workflow%3ARuby+branch%3Amaster)
8
+
9
+ [<img src="https://coveralls.io/repos/mongomapper/mongomapper/badge.svg" alt="Coverage Status" />](https://coveralls.io/r/mongomapper/mongomapper)
10
+
11
+ ## Install
10
12
 
11
13
  $ gem install mongo_mapper
12
14
 
13
- == Documentation
15
+ ## Documentation
14
16
 
15
17
  http://mongomapper.com/documentation/
16
18
 
17
19
  http://rdoc.info/github/mongomapper/mongomapper
18
20
 
19
- == Compatibility
21
+ ## Compatibility
20
22
 
21
23
  MongoMapper is tested against:
22
24
 
23
- * MRI 1.8.7
24
- * MRI 1.9.3
25
- * MRI 2.0.0
26
- * MRI 2.1.1
25
+ * MRI 2.4 - 2.7
27
26
  * JRuby (Versions with 1.9 compatibility)
28
27
 
29
28
  Additionally, MongoMapper is tested against:
30
29
 
31
- * Rails 3.0.x
32
- * Rails 3.1.x
33
- * Rails 3.2.x
34
- * Rails 4.0.x
30
+ * Rails 5.0+ - 6.0
35
31
 
36
- == Contributing & Development
32
+ ## Contributing & Development
37
33
 
38
34
  $ git clone https://github.com/mongomapper/mongomapper && cd mongomapper
39
35
  $ bundle install
@@ -45,12 +41,21 @@ Additionally, MongoMapper is tested against:
45
41
  * Commit, do not mess with Rakefile, version, or history. If you want to have your own version, that is fine but bump version in a commit by itself in another branch so a maintainer ignore it when your pull request is merged.
46
42
  * Send a pull request. Bonus points for topic branches.
47
43
 
48
- == Problems or Questions?
44
+ ## Problems or Questions?
49
45
 
50
46
  Hit up the Google group: http://groups.google.com/group/mongomapper
51
47
 
52
- Hop on IRC: irc://chat.freenode.net/#mongomapper
48
+ ## Copyright
49
+
50
+ Copyright (c) 2009-2020 MongoMapper. See LICENSE for details.
51
+
52
+ ## Contributors
53
+
54
+ MongoMapper/Plucky is:
53
55
 
54
- == License & Copyright
56
+ * John Nunemaker
57
+ * Chris Heald
58
+ * Scott Taylor
55
59
 
56
- See LICENSE for details.
60
+ But all open source projects are a team effort and could not happen without
61
+ everyone who has contributed. See `CONTRIBUTORS` for the full list. Thank you!
data/examples/keys.rb CHANGED
@@ -16,7 +16,7 @@ class User
16
16
  key :links, Hash
17
17
  timestamps!
18
18
  end
19
- User.collection.remove # empties collection
19
+ User.collection.drop # empties collection
20
20
 
21
21
  john = User.create({
22
22
  :first_name => 'John',
@@ -10,7 +10,7 @@ class User
10
10
  key :name, String
11
11
  key :tags, Array
12
12
  end
13
- User.collection.remove # empties collection
13
+ User.collection.drop # empties collection
14
14
 
15
15
  john = User.create(:name => 'John', :tags => %w[ruby mongo], :age => 28)
16
16
  bill = User.create(:name => 'Bill', :tags => %w[ruby mongo], :age => 30)
data/examples/querying.rb CHANGED
@@ -10,7 +10,7 @@ class User
10
10
  key :name, String
11
11
  key :tags, Array
12
12
  end
13
- User.collection.remove # empties collection
13
+ User.collection.drop # empties collection
14
14
 
15
15
  User.create(:name => 'John', :tags => %w[ruby mongo], :age => 28)
16
16
  User.create(:name => 'Bill', :tags => %w[ruby mongo], :age => 30)
data/examples/safe.rb CHANGED
@@ -22,7 +22,7 @@ puts
22
22
  begin
23
23
  user = User.new(:email => 'nunemaker@gmail.com')
24
24
  user.save(:safe => true)
25
- rescue Mongo::OperationFailure => e
25
+ rescue Mongo::Error::OperationFailure => e
26
26
  puts 'Mongo Operation failure raised because duplicate email was entered'
27
27
  puts e.inspect
28
28
  puts
@@ -37,7 +37,7 @@ User.safe
37
37
 
38
38
  begin
39
39
  User.create(:email => 'nunemaker@gmail.com')
40
- rescue Mongo::OperationFailure => e
40
+ rescue Mongo::Error::OperationFailure => e
41
41
  puts 'Mongo Operation failure raised because duplicate email was entered'
42
42
  puts e.inspect
43
43
  end
data/examples/scopes.rb CHANGED
@@ -28,7 +28,7 @@ class User
28
28
  key :name, String
29
29
  key :tags, Array
30
30
  end
31
- User.collection.remove # empties collection
31
+ User.collection.drop # empties collection
32
32
 
33
33
  User.create(:name => 'John', :tags => %w[ruby mongo], :age => 28)
34
34
  User.create(:name => 'Bill', :tags => %w[ruby mongo], :age => 30)
data/lib/mongo_mapper.rb CHANGED
@@ -3,6 +3,7 @@ require 'plucky'
3
3
  require 'active_support'
4
4
  require 'active_support/core_ext'
5
5
  require 'active_model'
6
+ require 'activemodel-serializers-xml'
6
7
  require "mongo_mapper/railtie" if defined?(Rails)
7
8
 
8
9
  I18n.load_path << File.expand_path('../mongo_mapper/locale/en.yml', __FILE__)
@@ -61,6 +62,7 @@ module MongoMapper
61
62
  autoload :Scopes, 'mongo_mapper/plugins/scopes'
62
63
  autoload :Serialization, 'mongo_mapper/plugins/serialization'
63
64
  autoload :Stats, 'mongo_mapper/plugins/stats'
65
+ autoload :StrongParameters, 'mongo_mapper/plugins/strong_parameters'
64
66
  autoload :Timestamps, 'mongo_mapper/plugins/timestamps'
65
67
  autoload :Userstamps, 'mongo_mapper/plugins/userstamps'
66
68
  autoload :Validations, 'mongo_mapper/plugins/validations'
@@ -86,6 +88,7 @@ module MongoMapper
86
88
  autoload :OneEmbeddedProxy, 'mongo_mapper/plugins/associations/one_embedded_proxy'
87
89
  autoload :OneEmbeddedPolymorphicProxy, 'mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy'
88
90
  autoload :InArrayProxy, 'mongo_mapper/plugins/associations/in_array_proxy'
91
+ autoload :InForeignArrayProxy, 'mongo_mapper/plugins/associations/in_foreign_array_proxy'
89
92
  end
90
93
  end
91
94
 
@@ -4,13 +4,12 @@ require 'uri'
4
4
  module MongoMapper
5
5
  module Connection
6
6
  @@connection = nil
7
- @@database = nil
8
- @@database_name = nil
9
7
  @@config = nil
8
+ @@database = nil
10
9
 
11
10
  # @api public
12
11
  def connection
13
- @@connection ||= Mongo::MongoClient.new
12
+ @@connection ||= Mongo::Client.new ['127.0.0.1:27017']
14
13
  end
15
14
 
16
15
  def connection?
@@ -29,15 +28,12 @@ module MongoMapper
29
28
 
30
29
  # @api public
31
30
  def database=(name)
32
- @@database = nil
33
- @@database_name = name
31
+ @@database = connection.use(name).database
34
32
  end
35
33
 
36
34
  # @api public
37
35
  def database
38
- return nil if @@database_name.blank?
39
-
40
- @@database ||= MongoMapper.connection.db(@@database_name)
36
+ @@database ||= connection.database
41
37
  end
42
38
 
43
39
  def config=(hash)
@@ -51,46 +47,28 @@ module MongoMapper
51
47
 
52
48
  # @api private
53
49
  def config_for_environment(environment)
54
- env = config[environment.to_s] || {}
55
- return env if env['uri'].blank?
56
-
57
- uri = URI.parse(env['uri'])
58
- raise InvalidScheme.new('must be mongodb') unless uri.scheme == 'mongodb'
59
- {
60
- 'host' => uri.host,
61
- 'port' => uri.port,
62
- 'database' => uri.path.gsub(/^\//, ''),
63
- 'username' => uri.user,
64
- 'password' => uri.password,
65
- }
50
+ config[environment.to_s]
66
51
  end
67
52
 
68
53
  def connect(environment, options={})
69
54
  raise 'Set config before connecting. MongoMapper.config = {...}' if config.blank?
70
- env = config_for_environment(environment)
55
+ env = config_for_environment(environment).dup
56
+ addresses_or_uri = env.delete('hosts') ||
57
+ env.delete('uri') ||
58
+ [env.delete('host')].compact
71
59
 
72
60
  if env['options'].is_a?(Hash)
73
- options = env['options'].symbolize_keys.merge(options)
74
- end
75
- options[:read] = options[:read].to_sym if options[:read].is_a? String
76
-
77
- if env.key?('ssl')
78
- options[:ssl] = env['ssl']
61
+ options = env.delete('options').symbolize_keys.merge(options)
79
62
  end
63
+ #database etc are all options to Mongo::Client.new now
64
+ options = env.symbolize_keys.merge(options)
80
65
 
81
- MongoMapper.connection = if env.key?('hosts')
82
- klass = (env.key?("mongos") || env.key?("sharded")) ? Mongo::MongoShardedClient : Mongo::MongoReplicaSetClient
83
- if env['hosts'].first.is_a?(String)
84
- klass.new( env['hosts'], options )
85
- else
86
- klass.new( *env['hosts'].push(options) )
87
- end
88
- else
89
- Mongo::MongoClient.new(env['host'], env['port'], options)
66
+ if options[:port]
67
+ raise "port should be specified as part of the host or uri"
90
68
  end
91
69
 
92
- MongoMapper.database = env['database']
93
- MongoMapper.database.authenticate(env['username'], env['password']) if env['username'] && env['password']
70
+ options[:read] = options[:read].to_sym if options[:read].is_a? String
71
+ MongoMapper.connection = Mongo::Client.new(addresses_or_uri, options)
94
72
  end
95
73
 
96
74
  def setup(config, environment, options={})
@@ -18,7 +18,7 @@ class ObjectId
18
18
  end
19
19
 
20
20
  class BSON::ObjectId
21
- alias_method :original_to_json, :to_json
21
+ alias_method :original_as_json, :as_json
22
22
 
23
23
  def as_json(options=nil)
24
24
  to_s
@@ -29,4 +29,8 @@ class BSON::ObjectId
29
29
  end
30
30
 
31
31
  alias to_str to_s
32
+
33
+ def original_to_json(*args)
34
+ original_as_json.to_json(*args)
35
+ end
32
36
  end
@@ -59,4 +59,4 @@ module MongoMapper
59
59
  end
60
60
  end
61
61
  end
62
- end
62
+ end
@@ -6,7 +6,7 @@ module MongoMapper
6
6
  attr_reader :name, :options, :query_options
7
7
 
8
8
  # Options that should not be considered MongoDB query options/criteria
9
- AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic, :autosave, :touch, :counter_cache]
9
+ AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :from, :polymorphic, :autosave, :touch, :counter_cache, :ordered]
10
10
 
11
11
  def initialize(name, options={}, &extension)
12
12
  @name, @options, @query_options, @original_options = name.to_sym, {}, {}, options
@@ -28,13 +28,17 @@ module MongoMapper
28
28
  end
29
29
 
30
30
  def as?
31
- !!@options[:as]
31
+ !in_foreign_array? && !!@options[:as]
32
32
  end
33
33
 
34
34
  def in_array?
35
35
  !!@options[:in]
36
36
  end
37
37
 
38
+ def in_foreign_array?
39
+ !!@options[:from]
40
+ end
41
+
38
42
  def embeddable?
39
43
  klass.embeddable?
40
44
  end
@@ -47,6 +51,10 @@ module MongoMapper
47
51
  !!@options[:counter_cache]
48
52
  end
49
53
 
54
+ def ordered?
55
+ !!@options[:ordered]
56
+ end
57
+
50
58
  def type_key_name
51
59
  "_type"
52
60
  end
@@ -29,7 +29,7 @@ module MongoMapper
29
29
 
30
30
  def add_touch_callbacks
31
31
  name = self.name
32
- method_name = "belongs_to_touch_after_save_or_destroy_for_#{name}"
32
+ method_name = :"belongs_to_touch_after_save_or_destroy_for_#{name}"
33
33
  touch = options.fetch(:touch)
34
34
 
35
35
  @model.send(:define_method, method_name) do
@@ -47,6 +47,12 @@ module MongoMapper
47
47
  loaded
48
48
  @target
49
49
  end
50
+
51
+ private
52
+
53
+ def stale_target?
54
+ loaded? && proxy_owner[association.foreign_key] != @target&.id
55
+ end
50
56
  end
51
57
  end
52
58
  end
@@ -6,11 +6,11 @@ module MongoMapper
6
6
  include DynamicQuerying::ClassMethods
7
7
 
8
8
  def find(*args)
9
- query.find(*scoped_ids(args))
9
+ order_results(query.find(*scoped_ids(args)))
10
10
  end
11
11
 
12
12
  def find!(*args)
13
- query.find!(*scoped_ids(args))
13
+ order_results(query.find!(*scoped_ids(args)))
14
14
  end
15
15
 
16
16
  def paginate(options)
@@ -20,17 +20,29 @@ module MongoMapper
20
20
 
21
21
  def all(options={})
22
22
  return [] if ids.blank?
23
- query(options).all
23
+ order_results(query(options).all)
24
24
  end
25
25
 
26
26
  def first(options={})
27
27
  return nil if ids.blank?
28
- query(options).first
28
+
29
+ if ordered?
30
+ ids = find_ordered_ids(options)
31
+ find!(ids.first) if ids.any?
32
+ else
33
+ query(options).first
34
+ end
29
35
  end
30
36
 
31
37
  def last(options={})
32
38
  return nil if ids.blank?
33
- query(options).last
39
+
40
+ if ordered?
41
+ ids = find_ordered_ids(options)
42
+ find!(ids.last) if ids.any?
43
+ else
44
+ query(options).last
45
+ end
34
46
  end
35
47
 
36
48
  def count(options={})
@@ -120,6 +132,13 @@ module MongoMapper
120
132
  valid.empty? ? nil : valid
121
133
  end
122
134
 
135
+ def find_ordered_ids(options={})
136
+ return ids if options.empty?
137
+
138
+ matched_ids = klass.collection.distinct(:_id, query(options).criteria.to_hash)
139
+ matched_ids.sort_by! { |matched_id| ids.index(matched_id) }
140
+ end
141
+
123
142
  def find_target
124
143
  return [] if ids.blank?
125
144
  all
@@ -128,7 +147,18 @@ module MongoMapper
128
147
  def ids
129
148
  proxy_owner[options[:in]]
130
149
  end
150
+
151
+ def order_results(objects)
152
+ return objects if !ordered?
153
+ return objects unless objects.respond_to?(:to_a) && objects.respond_to?(:sort_by)
154
+ objects.sort_by { |obj| ids.index(obj.id) }
155
+ end
156
+
157
+ def ordered?
158
+ association.ordered?
159
+ end
160
+
131
161
  end
132
162
  end
133
163
  end
134
- end
164
+ end