mongo_mapper 0.6.10 → 0.7.0

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 (106) hide show
  1. data/README.rdoc +5 -14
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongo_mapper.rb +48 -56
  5. data/lib/mongo_mapper/document.rb +136 -164
  6. data/lib/mongo_mapper/embedded_document.rb +29 -354
  7. data/lib/mongo_mapper/plugins.rb +31 -0
  8. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  9. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  10. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  11. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  12. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  13. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  14. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  15. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  16. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  17. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  18. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  19. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  20. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  21. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  22. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  23. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  24. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  25. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  26. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  27. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  28. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  29. data/lib/mongo_mapper/plugins/keys.rb +324 -0
  30. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  31. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  32. data/lib/mongo_mapper/plugins/pagination/proxy.rb +68 -0
  33. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  34. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  35. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  36. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  37. data/lib/mongo_mapper/query.rb +130 -0
  38. data/lib/mongo_mapper/support.rb +40 -17
  39. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  40. data/lib/mongo_mapper/support/find.rb +77 -0
  41. data/mongo_mapper.gemspec +55 -38
  42. data/performance/read_write.rb +52 -0
  43. data/specs.watchr +23 -2
  44. data/test/functional/associations/test_belongs_to_proxy.rb +12 -10
  45. data/test/functional/associations/test_many_documents_as_proxy.rb +4 -21
  46. data/test/functional/associations/test_many_documents_proxy.rb +2 -8
  47. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +59 -39
  48. data/test/functional/associations/test_many_embedded_proxy.rb +145 -81
  49. data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -40
  50. data/test/functional/associations/test_one_proxy.rb +25 -10
  51. data/test/functional/test_binary.rb +2 -8
  52. data/test/functional/test_callbacks.rb +1 -5
  53. data/test/functional/test_dirty.rb +27 -23
  54. data/test/functional/test_document.rb +224 -165
  55. data/test/functional/test_embedded_document.rb +72 -82
  56. data/test/functional/test_identity_map.rb +508 -0
  57. data/test/functional/test_modifiers.rb +15 -5
  58. data/test/functional/test_pagination.rb +1 -3
  59. data/test/functional/test_protected.rb +155 -0
  60. data/test/functional/test_string_id_compatibility.rb +7 -12
  61. data/test/functional/test_validations.rb +26 -58
  62. data/test/models.rb +0 -39
  63. data/test/test_helper.rb +37 -3
  64. data/test/unit/associations/test_base.rb +5 -5
  65. data/test/unit/associations/test_proxy.rb +8 -6
  66. data/test/unit/test_descendant_appends.rb +71 -0
  67. data/test/unit/test_document.rb +71 -76
  68. data/test/unit/test_dynamic_finder.rb +27 -29
  69. data/test/unit/test_embedded_document.rb +555 -601
  70. data/test/unit/{test_key.rb → test_keys.rb} +2 -5
  71. data/test/unit/test_mongo_mapper.rb +69 -9
  72. data/test/unit/test_pagination.rb +40 -32
  73. data/test/unit/test_plugins.rb +50 -0
  74. data/test/unit/{test_finder_options.rb → test_query.rb} +74 -65
  75. data/test/unit/test_rails.rb +123 -0
  76. data/test/unit/{test_serializations.rb → test_serialization.rb} +1 -2
  77. data/test/unit/test_support.rb +23 -7
  78. data/test/unit/test_time_zones.rb +3 -4
  79. data/test/unit/test_validations.rb +58 -17
  80. metadata +53 -36
  81. data/lib/mongo_mapper/associations.rb +0 -78
  82. data/lib/mongo_mapper/associations/base.rb +0 -119
  83. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
  84. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
  85. data/lib/mongo_mapper/associations/collection.rb +0 -19
  86. data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
  87. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
  88. data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
  89. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
  90. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
  91. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
  92. data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
  93. data/lib/mongo_mapper/associations/proxy.rb +0 -116
  94. data/lib/mongo_mapper/callbacks.rb +0 -61
  95. data/lib/mongo_mapper/dirty.rb +0 -117
  96. data/lib/mongo_mapper/dynamic_finder.rb +0 -74
  97. data/lib/mongo_mapper/finder_options.rb +0 -145
  98. data/lib/mongo_mapper/key.rb +0 -36
  99. data/lib/mongo_mapper/mongo_mapper.rb +0 -125
  100. data/lib/mongo_mapper/pagination.rb +0 -66
  101. data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
  102. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
  103. data/lib/mongo_mapper/serialization.rb +0 -54
  104. data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
  105. data/lib/mongo_mapper/validations.rb +0 -39
  106. data/test/functional/test_rails_compatibility.rb +0 -25
@@ -1,74 +0,0 @@
1
- module MongoMapper
2
- # @api private
3
- module Finders
4
- def dynamic_find(finder, args)
5
- attributes = {}
6
- finder.attributes.each_with_index do |attr, index|
7
- attributes[attr] = args[index]
8
- end
9
-
10
- options = args.extract_options!.merge(attributes)
11
-
12
- if result = find(finder.finder, options)
13
- result
14
- else
15
- if finder.raise?
16
- raise DocumentNotFound, "Couldn't find Document with #{attributes.inspect} in collection named #{collection.name}"
17
- end
18
-
19
- if finder.instantiator
20
- self.send(finder.instantiator, attributes)
21
- end
22
- end
23
- end
24
-
25
- protected
26
- def method_missing(method, *args, &block)
27
- finder = DynamicFinder.new(method)
28
-
29
- if finder.found?
30
- dynamic_find(finder, args)
31
- else
32
- super
33
- end
34
- end
35
- end
36
-
37
- class DynamicFinder
38
- attr_reader :method, :attributes, :finder, :bang, :instantiator
39
-
40
- def initialize(method)
41
- @method = method
42
- @finder = :first
43
- @bang = false
44
- match
45
- end
46
-
47
- def found?
48
- @finder.present?
49
- end
50
-
51
- def raise?
52
- bang == true
53
- end
54
-
55
- protected
56
- def match
57
- case method.to_s
58
- when /^find_(all_by|by)_([_a-zA-Z]\w*)$/
59
- @finder = :all if $1 == 'all_by'
60
- names = $2
61
- when /^find_by_([_a-zA-Z]\w*)\!$/
62
- @bang = true
63
- names = $1
64
- when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/
65
- @instantiator = $1 == 'initialize' ? :new : :create
66
- names = $2
67
- else
68
- @finder = nil
69
- end
70
-
71
- @attributes = names && names.split('_and_')
72
- end
73
- end
74
- end
@@ -1,145 +0,0 @@
1
- module MongoMapper
2
- # = Important Note
3
- # This class is private to MongoMapper and should not be considered part of
4
- # MongoMapper's public API.
5
- #
6
- class FinderOptions
7
- OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
8
-
9
- def self.normalized_field(field)
10
- field.to_s == 'id' ? :_id : field
11
- end
12
-
13
- def self.normalized_order_direction(direction)
14
- direction ||= 'ASC'
15
- direction.upcase == 'ASC' ? 1 : -1
16
- end
17
-
18
- def initialize(model, options)
19
- raise ArgumentError, "Options must be a hash" unless options.is_a?(Hash)
20
- options = options.symbolize_keys
21
-
22
- @model = model
23
- @options = {}
24
- @conditions = options.delete(:conditions) || {}
25
-
26
- options.each_pair do |key, value|
27
- if OptionKeys.include?(key)
28
- @options[key] = value
29
- else
30
- @conditions[key] = value
31
- end
32
- end
33
-
34
- add_sci_scope
35
- end
36
-
37
- def criteria
38
- to_mongo_criteria(@conditions)
39
- end
40
-
41
- def options
42
- fields = @options.delete(:fields) || @options.delete(:select)
43
- skip = @options.delete(:skip) || @options.delete(:offset) || 0
44
- limit = @options.delete(:limit) || 0
45
- sort = @options.delete(:sort) || convert_order_to_sort(@options.delete(:order))
46
-
47
- {:fields => to_mongo_fields(fields), :skip => skip.to_i, :limit => limit.to_i, :sort => sort}
48
- end
49
-
50
- def to_a
51
- [criteria, options]
52
- end
53
-
54
- private
55
- def to_mongo_criteria(conditions, parent_key=nil)
56
- criteria = {}
57
-
58
- conditions.each_pair do |field, value|
59
- field = self.class.normalized_field(field)
60
-
61
- if @model.object_id_key?(field) && value.is_a?(String)
62
- value = Mongo::ObjectID.from_string(value)
63
- end
64
-
65
- if field.is_a?(FinderOperator)
66
- criteria.update(field.to_criteria(value))
67
- next
68
- end
69
-
70
- case value
71
- when Array
72
- criteria[field] = operator?(field) ? value : {'$in' => value}
73
- when Hash
74
- criteria[field] = to_mongo_criteria(value, field)
75
- when Time
76
- criteria[field] = value.utc
77
- else
78
- criteria[field] = value
79
- end
80
- end
81
-
82
- criteria
83
- end
84
-
85
- def operator?(field)
86
- field.to_s =~ /^\$/
87
- end
88
-
89
- # adds _type single collection inheritance scope for models that need it
90
- def add_sci_scope
91
- if @model.single_collection_inherited?
92
- @conditions[:_type] = @model.to_s
93
- end
94
- end
95
-
96
- def to_mongo_fields(fields)
97
- return if fields.blank?
98
-
99
- if fields.respond_to?(:flatten, :compact)
100
- fields.flatten.compact
101
- else
102
- fields.split(',').map { |field| field.strip }
103
- end
104
- end
105
-
106
- def convert_order_to_sort(sort)
107
- return if sort.blank?
108
-
109
- if sort.respond_to?(:all?) && sort.all? { |s| s.respond_to?(:to_order) }
110
- sort.map { |s| s.to_order }
111
- elsif sort.respond_to?(:to_order)
112
- [sort.to_order]
113
- else
114
- pieces = sort.split(',')
115
- pieces.map { |s| to_mongo_sort_piece(s) }
116
- end
117
- end
118
-
119
- def to_mongo_sort_piece(str)
120
- field, direction = str.strip.split(' ')
121
- direction = FinderOptions.normalized_order_direction(direction)
122
- [field, direction]
123
- end
124
- end
125
-
126
- class FinderOperator
127
- def initialize(field, operator)
128
- @field, @operator = field, operator
129
- end
130
-
131
- def to_criteria(value)
132
- {FinderOptions.normalized_field(@field) => {@operator => value}}
133
- end
134
- end
135
-
136
- class OrderOperator
137
- def initialize(field, direction)
138
- @field, @direction = field, direction
139
- end
140
-
141
- def to_order
142
- [@field.to_s, FinderOptions.normalized_order_direction(@direction)]
143
- end
144
- end
145
- end
@@ -1,36 +0,0 @@
1
- module MongoMapper
2
- class Key
3
- attr_accessor :name, :type, :options, :default_value
4
-
5
- def initialize(*args)
6
- options = args.extract_options!
7
- @name, @type = args.shift.to_s, args.shift
8
- self.options = (options || {}).symbolize_keys
9
- self.default_value = self.options.delete(:default)
10
- end
11
-
12
- def ==(other)
13
- @name == other.name && @type == other.type
14
- end
15
-
16
- def set(value)
17
- type.to_mongo(value)
18
- end
19
-
20
- def embeddable?
21
- type.respond_to?(:embeddable?) && type.embeddable? ? true : false
22
- end
23
-
24
- def number?
25
- [Integer, Float].include?(type)
26
- end
27
-
28
- def get(value)
29
- if value.nil? && !default_value.nil?
30
- return default_value
31
- end
32
-
33
- type.from_mongo(value)
34
- end
35
- end
36
- end
@@ -1,125 +0,0 @@
1
- # if Gem is defined i'll assume you are using rubygems and lock specific versions
2
- # call me crazy but a plain old require will just get the latest version you have installed
3
- # so i want to make sure that if you are using gems you do in fact have the correct versions
4
- # if there is a better way to do this, please enlighten me!
5
- if self.class.const_defined?(:Gem)
6
- gem 'activesupport', '>= 2.3'
7
- gem 'mongo', '0.18.2'
8
- gem 'jnunemaker-validatable', '1.8.1'
9
- end
10
-
11
- require 'active_support'
12
- require 'mongo'
13
- require 'validatable'
14
-
15
- module MongoMapper
16
- # generic MM error
17
- class MongoMapperError < StandardError; end
18
-
19
- # raised when key expected to exist but not found
20
- class KeyNotFound < MongoMapperError; end
21
-
22
- # raised when document expected but not found
23
- class DocumentNotFound < MongoMapperError; end
24
-
25
- # raised when document not valid and using !
26
- class DocumentNotValid < MongoMapperError
27
- def initialize(document)
28
- super("Validation failed: #{document.errors.full_messages.join(", ")}")
29
- end
30
- end
31
-
32
- # @api public
33
- def self.connection
34
- @@connection ||= Mongo::Connection.new
35
- end
36
-
37
- # @api public
38
- def self.connection=(new_connection)
39
- @@connection = new_connection
40
- end
41
-
42
- # @api public
43
- def self.logger
44
- connection.logger
45
- end
46
-
47
- # @api public
48
- def self.database=(name)
49
- @@database = nil
50
- @@database_name = name
51
- end
52
-
53
- # @api public
54
- def self.database
55
- if @@database_name.blank?
56
- raise 'You forgot to set the default database name: MongoMapper.database = "foobar"'
57
- end
58
-
59
- @@database ||= MongoMapper.connection.db(@@database_name)
60
- end
61
-
62
- # @api private
63
- def self.ensured_indexes
64
- @@ensured_indexes ||= []
65
- end
66
-
67
- # @api private
68
- def self.ensured_indexes=(value)
69
- @@ensured_indexes = value
70
- end
71
-
72
- # @api private
73
- def self.ensure_index(klass, keys, options={})
74
- ensured_indexes << {:klass => klass, :keys => keys, :options => options}
75
- end
76
-
77
- # @api public
78
- def self.ensure_indexes!
79
- ensured_indexes.each do |index|
80
- unique = index[:options].delete(:unique)
81
- index[:klass].collection.create_index(index[:keys], unique)
82
- end
83
- end
84
-
85
- # @api private
86
- def self.use_time_zone?
87
- Time.respond_to?(:zone) && Time.zone ? true : false
88
- end
89
-
90
- # @api private
91
- def self.time_class
92
- use_time_zone? ? Time.zone : Time
93
- end
94
-
95
- # @api private
96
- def self.normalize_object_id(value)
97
- value.is_a?(String) ? Mongo::ObjectID.from_string(value) : value
98
- end
99
- end
100
-
101
- require 'mongo_mapper/support'
102
- require 'mongo_mapper/callbacks'
103
- require 'mongo_mapper/finder_options'
104
- require 'mongo_mapper/dirty'
105
- require 'mongo_mapper/dynamic_finder'
106
- require 'mongo_mapper/key'
107
- require 'mongo_mapper/pagination'
108
- require 'mongo_mapper/serialization'
109
- require 'mongo_mapper/validations'
110
- require 'mongo_mapper/rails_compatibility/document'
111
- require 'mongo_mapper/rails_compatibility/embedded_document'
112
- require 'mongo_mapper/embedded_document'
113
- require 'mongo_mapper/document'
114
- require 'mongo_mapper/associations'
115
- require 'mongo_mapper/associations/base'
116
- require 'mongo_mapper/associations/proxy'
117
- require 'mongo_mapper/associations/collection'
118
- require 'mongo_mapper/associations/many_documents_proxy'
119
- require 'mongo_mapper/associations/belongs_to_proxy'
120
- require 'mongo_mapper/associations/belongs_to_polymorphic_proxy'
121
- require 'mongo_mapper/associations/many_polymorphic_proxy'
122
- require 'mongo_mapper/associations/many_embedded_proxy'
123
- require 'mongo_mapper/associations/many_embedded_polymorphic_proxy'
124
- require 'mongo_mapper/associations/many_documents_as_proxy'
125
- require 'mongo_mapper/associations/one_proxy'
@@ -1,66 +0,0 @@
1
- module MongoMapper
2
- module Pagination
3
- class PaginationProxy
4
- instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
5
-
6
- attr_accessor :subject
7
- attr_reader :total_entries, :per_page, :current_page
8
- alias limit per_page
9
-
10
- def initialize(total_entries, current_page, per_page=nil)
11
- @total_entries = total_entries.to_i
12
- self.per_page = per_page
13
- self.current_page = current_page
14
- end
15
-
16
- def total_pages
17
- (total_entries / per_page.to_f).ceil
18
- end
19
-
20
- def out_of_bounds?
21
- current_page > total_pages
22
- end
23
-
24
- def previous_page
25
- current_page > 1 ? (current_page - 1) : nil
26
- end
27
-
28
- def next_page
29
- current_page < total_pages ? (current_page + 1) : nil
30
- end
31
-
32
- def skip
33
- (current_page - 1) * per_page
34
- end
35
- alias offset skip # for will paginate support
36
-
37
- def send(method, *args, &block)
38
- if respond_to?(method)
39
- super
40
- else
41
- subject.send(method, *args, &block)
42
- end
43
- end
44
-
45
- def ===(other)
46
- other === subject
47
- end
48
-
49
- def method_missing(name, *args, &block)
50
- @subject.send(name, *args, &block)
51
- end
52
-
53
- private
54
- def per_page=(value)
55
- value = 25 if value.blank?
56
- @per_page = value.to_i
57
- end
58
-
59
- def current_page=(value)
60
- value = value.to_i
61
- value = 1 if value < 1
62
- @current_page = value
63
- end
64
- end
65
- end
66
- end