dm-core 0.10.2 → 1.0.0.rc1

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 (183) hide show
  1. data/.gitignore +10 -1
  2. data/Gemfile +143 -0
  3. data/Rakefile +9 -5
  4. data/VERSION +1 -1
  5. data/dm-core.gemspec +160 -57
  6. data/lib/dm-core.rb +131 -56
  7. data/lib/dm-core/adapters.rb +98 -14
  8. data/lib/dm-core/adapters/abstract_adapter.rb +24 -4
  9. data/lib/dm-core/adapters/in_memory_adapter.rb +7 -2
  10. data/lib/dm-core/associations/many_to_many.rb +19 -30
  11. data/lib/dm-core/associations/many_to_one.rb +58 -42
  12. data/lib/dm-core/associations/one_to_many.rb +33 -23
  13. data/lib/dm-core/associations/one_to_one.rb +27 -11
  14. data/lib/dm-core/associations/relationship.rb +4 -4
  15. data/lib/dm-core/collection.rb +23 -16
  16. data/lib/dm-core/core_ext/array.rb +36 -0
  17. data/lib/dm-core/core_ext/hash.rb +30 -0
  18. data/lib/dm-core/core_ext/module.rb +46 -0
  19. data/lib/dm-core/core_ext/object.rb +31 -0
  20. data/lib/dm-core/core_ext/pathname.rb +20 -0
  21. data/lib/dm-core/core_ext/string.rb +22 -0
  22. data/lib/dm-core/core_ext/try_dup.rb +44 -0
  23. data/lib/dm-core/model.rb +88 -27
  24. data/lib/dm-core/model/hook.rb +75 -18
  25. data/lib/dm-core/model/property.rb +50 -9
  26. data/lib/dm-core/model/relationship.rb +31 -31
  27. data/lib/dm-core/model/scope.rb +3 -3
  28. data/lib/dm-core/property.rb +196 -516
  29. data/lib/dm-core/property/binary.rb +7 -0
  30. data/lib/dm-core/property/boolean.rb +35 -0
  31. data/lib/dm-core/property/class.rb +24 -0
  32. data/lib/dm-core/property/date.rb +47 -0
  33. data/lib/dm-core/property/date_time.rb +48 -0
  34. data/lib/dm-core/property/decimal.rb +43 -0
  35. data/lib/dm-core/property/discriminator.rb +48 -0
  36. data/lib/dm-core/property/float.rb +24 -0
  37. data/lib/dm-core/property/integer.rb +32 -0
  38. data/lib/dm-core/property/numeric.rb +43 -0
  39. data/lib/dm-core/property/object.rb +32 -0
  40. data/lib/dm-core/property/serial.rb +8 -0
  41. data/lib/dm-core/property/string.rb +49 -0
  42. data/lib/dm-core/property/text.rb +12 -0
  43. data/lib/dm-core/property/time.rb +48 -0
  44. data/lib/dm-core/property/typecast/numeric.rb +32 -0
  45. data/lib/dm-core/property/typecast/time.rb +28 -0
  46. data/lib/dm-core/property_set.rb +10 -4
  47. data/lib/dm-core/query.rb +14 -37
  48. data/lib/dm-core/query/conditions/comparison.rb +8 -6
  49. data/lib/dm-core/query/conditions/operation.rb +33 -2
  50. data/lib/dm-core/query/operator.rb +2 -5
  51. data/lib/dm-core/query/path.rb +4 -6
  52. data/lib/dm-core/repository.rb +21 -6
  53. data/lib/dm-core/resource.rb +316 -133
  54. data/lib/dm-core/resource/state.rb +79 -0
  55. data/lib/dm-core/resource/state/clean.rb +40 -0
  56. data/lib/dm-core/resource/state/deleted.rb +30 -0
  57. data/lib/dm-core/resource/state/dirty.rb +86 -0
  58. data/lib/dm-core/resource/state/immutable.rb +34 -0
  59. data/lib/dm-core/resource/state/persisted.rb +29 -0
  60. data/lib/dm-core/resource/state/transient.rb +70 -0
  61. data/lib/dm-core/spec/lib/adapter_helpers.rb +52 -0
  62. data/lib/dm-core/spec/lib/collection_helpers.rb +20 -0
  63. data/{spec → lib/dm-core/spec}/lib/counter_adapter.rb +5 -1
  64. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  65. data/lib/dm-core/spec/lib/spec_helper.rb +68 -0
  66. data/lib/dm-core/spec/setup.rb +165 -0
  67. data/lib/dm-core/spec/{adapter_shared_spec.rb → shared/adapter_spec.rb} +21 -7
  68. data/{spec/public/shared/resource_shared_spec.rb → lib/dm-core/spec/shared/resource_spec.rb} +120 -83
  69. data/{spec/public/shared/sel_shared_spec.rb → lib/dm-core/spec/shared/sel_spec.rb} +5 -6
  70. data/lib/dm-core/support/assertions.rb +8 -0
  71. data/lib/dm-core/support/equalizer.rb +1 -0
  72. data/lib/dm-core/support/hook.rb +420 -0
  73. data/lib/dm-core/support/lazy_array.rb +453 -0
  74. data/lib/dm-core/support/local_object_space.rb +12 -0
  75. data/lib/dm-core/support/logger.rb +193 -6
  76. data/lib/dm-core/support/naming_conventions.rb +8 -8
  77. data/lib/dm-core/support/subject.rb +33 -0
  78. data/lib/dm-core/type.rb +4 -0
  79. data/lib/dm-core/types/boolean.rb +2 -0
  80. data/lib/dm-core/types/decimal.rb +9 -0
  81. data/lib/dm-core/types/discriminator.rb +2 -0
  82. data/lib/dm-core/types/object.rb +3 -0
  83. data/lib/dm-core/types/serial.rb +2 -0
  84. data/lib/dm-core/types/text.rb +2 -0
  85. data/lib/dm-core/version.rb +1 -1
  86. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +67 -0
  87. data/spec/public/model/hook_spec.rb +209 -0
  88. data/spec/public/model/property_spec.rb +35 -0
  89. data/spec/public/model/relationship_spec.rb +33 -20
  90. data/spec/public/model_spec.rb +142 -10
  91. data/spec/public/property/binary_spec.rb +14 -0
  92. data/spec/public/property/boolean_spec.rb +14 -0
  93. data/spec/public/property/class_spec.rb +20 -0
  94. data/spec/public/property/date_spec.rb +14 -0
  95. data/spec/public/property/date_time_spec.rb +14 -0
  96. data/spec/public/property/decimal_spec.rb +14 -0
  97. data/spec/public/{types → property}/discriminator_spec.rb +2 -12
  98. data/spec/public/property/float_spec.rb +14 -0
  99. data/spec/public/property/integer_spec.rb +14 -0
  100. data/spec/public/property/object_spec.rb +9 -17
  101. data/spec/public/property/serial_spec.rb +14 -0
  102. data/spec/public/property/string_spec.rb +14 -0
  103. data/spec/public/property/text_spec.rb +52 -0
  104. data/spec/public/property/time_spec.rb +14 -0
  105. data/spec/public/property_spec.rb +28 -87
  106. data/spec/public/resource_spec.rb +101 -0
  107. data/spec/public/sel_spec.rb +5 -15
  108. data/spec/public/shared/collection_shared_spec.rb +16 -30
  109. data/spec/public/shared/finder_shared_spec.rb +2 -4
  110. data/spec/public/shared/property_shared_spec.rb +176 -0
  111. data/spec/semipublic/adapters/abstract_adapter_spec.rb +1 -1
  112. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +2 -2
  113. data/spec/semipublic/associations/many_to_many_spec.rb +89 -0
  114. data/spec/semipublic/associations/many_to_one_spec.rb +24 -1
  115. data/spec/semipublic/associations/one_to_many_spec.rb +51 -0
  116. data/spec/semipublic/associations/one_to_one_spec.rb +49 -0
  117. data/spec/semipublic/associations/relationship_spec.rb +3 -3
  118. data/spec/semipublic/associations_spec.rb +1 -1
  119. data/spec/semipublic/property/binary_spec.rb +13 -0
  120. data/spec/semipublic/property/boolean_spec.rb +65 -0
  121. data/spec/semipublic/property/class_spec.rb +33 -0
  122. data/spec/semipublic/property/date_spec.rb +43 -0
  123. data/spec/semipublic/property/date_time_spec.rb +46 -0
  124. data/spec/semipublic/property/decimal_spec.rb +82 -0
  125. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  126. data/spec/semipublic/property/float_spec.rb +82 -0
  127. data/spec/semipublic/property/integer_spec.rb +82 -0
  128. data/spec/semipublic/property/serial_spec.rb +13 -0
  129. data/spec/semipublic/property/string_spec.rb +13 -0
  130. data/spec/semipublic/property/text_spec.rb +31 -0
  131. data/spec/semipublic/property/time_spec.rb +50 -0
  132. data/spec/semipublic/property_spec.rb +2 -532
  133. data/spec/semipublic/query/conditions/comparison_spec.rb +171 -169
  134. data/spec/semipublic/query/conditions/operation_spec.rb +53 -51
  135. data/spec/semipublic/query/path_spec.rb +17 -17
  136. data/spec/semipublic/query_spec.rb +47 -78
  137. data/spec/semipublic/resource/state/clean_spec.rb +88 -0
  138. data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
  139. data/spec/semipublic/resource/state/dirty_spec.rb +133 -0
  140. data/spec/semipublic/resource/state/immutable_spec.rb +99 -0
  141. data/spec/semipublic/resource/state/transient_spec.rb +128 -0
  142. data/spec/semipublic/resource/state_spec.rb +226 -0
  143. data/spec/semipublic/shared/property_shared_spec.rb +143 -0
  144. data/spec/semipublic/shared/resource_shared_spec.rb +16 -15
  145. data/spec/semipublic/shared/resource_state_shared_spec.rb +78 -0
  146. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  147. data/spec/spec_helper.rb +21 -97
  148. data/spec/support/types/huge_integer.rb +17 -0
  149. data/spec/unit/array_spec.rb +48 -0
  150. data/spec/unit/hash_spec.rb +35 -0
  151. data/spec/unit/hook_spec.rb +1234 -0
  152. data/spec/unit/lazy_array_spec.rb +1959 -0
  153. data/spec/unit/module_spec.rb +70 -0
  154. data/spec/unit/object_spec.rb +37 -0
  155. data/spec/unit/try_dup_spec.rb +45 -0
  156. data/tasks/local_gemfile.rake +18 -0
  157. data/tasks/spec.rake +0 -3
  158. metadata +197 -71
  159. data/deps.rip +0 -2
  160. data/lib/dm-core/adapters/data_objects_adapter.rb +0 -712
  161. data/lib/dm-core/adapters/mysql_adapter.rb +0 -42
  162. data/lib/dm-core/adapters/oracle_adapter.rb +0 -229
  163. data/lib/dm-core/adapters/postgres_adapter.rb +0 -22
  164. data/lib/dm-core/adapters/sqlite3_adapter.rb +0 -17
  165. data/lib/dm-core/adapters/sqlserver_adapter.rb +0 -114
  166. data/lib/dm-core/adapters/yaml_adapter.rb +0 -111
  167. data/lib/dm-core/core_ext/enumerable.rb +0 -28
  168. data/lib/dm-core/migrations.rb +0 -1427
  169. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +0 -366
  170. data/lib/dm-core/transaction.rb +0 -508
  171. data/lib/dm-core/types/paranoid_boolean.rb +0 -42
  172. data/lib/dm-core/types/paranoid_datetime.rb +0 -41
  173. data/spec/lib/adapter_helpers.rb +0 -105
  174. data/spec/lib/collection_helpers.rb +0 -18
  175. data/spec/lib/pending_helpers.rb +0 -46
  176. data/spec/public/migrations_spec.rb +0 -503
  177. data/spec/public/transaction_spec.rb +0 -153
  178. data/spec/semipublic/adapters/mysql_adapter_spec.rb +0 -17
  179. data/spec/semipublic/adapters/oracle_adapter_spec.rb +0 -194
  180. data/spec/semipublic/adapters/postgres_adapter_spec.rb +0 -17
  181. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +0 -17
  182. data/spec/semipublic/adapters/sqlserver_adapter_spec.rb +0 -17
  183. data/spec/semipublic/adapters/yaml_adapter_spec.rb +0 -12
@@ -0,0 +1,12 @@
1
+ module DataMapper
2
+ class Property
3
+ class Text < String
4
+ length 65535
5
+ lazy true
6
+
7
+ def primitive?(value)
8
+ value.kind_of?(::String)
9
+ end
10
+ end # class Text
11
+ end # class Property
12
+ end # module DataMapper
@@ -0,0 +1,48 @@
1
+ require 'dm-core/property/typecast/time'
2
+
3
+ module DataMapper
4
+ class Property
5
+ class Time < Object
6
+ include PassThroughLoadDump
7
+ include Typecast::Time
8
+
9
+ primitive ::Time
10
+
11
+ # Typecasts an arbitrary value to a Time
12
+ # Handles both Hashes and Time instances.
13
+ #
14
+ # @param [#to_mash, #to_s] value
15
+ # value to be typecast
16
+ #
17
+ # @return [Time]
18
+ # Time constructed from value
19
+ #
20
+ # @api private
21
+ def typecast_to_primitive(value)
22
+ if value.respond_to?(:to_time)
23
+ value.to_time
24
+ elsif value.respond_to?(:to_mash)
25
+ typecast_hash_to_time(value)
26
+ else
27
+ ::Time.parse(value.to_s)
28
+ end
29
+ rescue ArgumentError
30
+ value
31
+ end
32
+
33
+ # Creates a Time instance from a Hash with keys :year, :month, :day,
34
+ # :hour, :min, :sec
35
+ #
36
+ # @param [#to_mash] value
37
+ # value to be typecast
38
+ #
39
+ # @return [Time]
40
+ # Time constructed from hash
41
+ #
42
+ # @api private
43
+ def typecast_hash_to_time(value)
44
+ ::Time.local(*extract_time(value))
45
+ end
46
+ end # class Time
47
+ end # class Property
48
+ end # module DataMapper
@@ -0,0 +1,32 @@
1
+ module DataMapper
2
+ class Property
3
+ module Typecast
4
+ module Numeric
5
+ # Match numeric string
6
+ #
7
+ # @param [#to_str, Numeric] value
8
+ # value to typecast
9
+ # @param [Symbol] method
10
+ # method to typecast with
11
+ #
12
+ # @return [Numeric]
13
+ # number if matched, value if no match
14
+ #
15
+ # @api private
16
+ def typecast_to_numeric(value, method)
17
+ if value.respond_to?(:to_str)
18
+ if value.to_str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/
19
+ $1.send(method)
20
+ else
21
+ value
22
+ end
23
+ elsif value.respond_to?(method)
24
+ value.send(method)
25
+ else
26
+ value
27
+ end
28
+ end
29
+ end # Numeric
30
+ end # Typecast
31
+ end # Property
32
+ end # DataMapper
@@ -0,0 +1,28 @@
1
+ module DataMapper
2
+ class Property
3
+ module Typecast
4
+ module Time
5
+ include Numeric
6
+
7
+ # Extracts the given args from the hash. If a value does not exist, it
8
+ # uses the value of Time.now.
9
+ #
10
+ # @param [#to_mash] value
11
+ # value to extract time args from
12
+ #
13
+ # @return [Array]
14
+ # Extracted values
15
+ #
16
+ # @api private
17
+ def extract_time(value)
18
+ mash = value.to_mash
19
+ now = ::Time.now
20
+
21
+ [ :year, :month, :day, :hour, :min, :sec ].map do |segment|
22
+ typecast_to_numeric(mash.fetch(segment, now.send(segment)), :to_i)
23
+ end
24
+ end
25
+ end # Numeric
26
+ end # Typecast
27
+ end # Property
28
+ end # DataMapper
@@ -25,7 +25,7 @@ module DataMapper
25
25
 
26
26
  # @api semipublic
27
27
  def named?(name)
28
- @properties.key?(name)
28
+ @properties.key?(name.to_sym)
29
29
  end
30
30
 
31
31
  # @api semipublic
@@ -68,7 +68,7 @@ module DataMapper
68
68
 
69
69
  # @api semipublic
70
70
  def discriminator
71
- @discriminator ||= detect { |property| property.type == Types::Discriminator }
71
+ @discriminator ||= detect { |property| property.kind_of?(Property::Discriminator) || property.type == Types::Discriminator }
72
72
  end
73
73
 
74
74
  # @api semipublic
@@ -87,7 +87,8 @@ module DataMapper
87
87
 
88
88
  # @api semipublic
89
89
  def get(resource)
90
- map { |property| property.get(resource) }
90
+ return [] if resource.nil?
91
+ map { |property| resource.__send__(property.name) }
91
92
  end
92
93
 
93
94
  # @api semipublic
@@ -97,7 +98,7 @@ module DataMapper
97
98
 
98
99
  # @api semipublic
99
100
  def set(resource, values)
100
- zip(values) { |property, value| property.set(resource, value) }
101
+ zip(values) { |property, value| resource.__send__("#{property.name}=", value) }
101
102
  end
102
103
 
103
104
  # @api semipublic
@@ -147,6 +148,11 @@ module DataMapper
147
148
  properties_in_context.flatten.uniq
148
149
  end
149
150
 
151
+ # @api private
152
+ def field_map
153
+ map { |property| [ property.field, property ] }.to_hash
154
+ end
155
+
150
156
  private
151
157
 
152
158
  # @api semipublic
data/lib/dm-core/query.rb CHANGED
@@ -26,7 +26,7 @@ module DataMapper
26
26
  # Generally Query objects can be found inside Collection objects.
27
27
  #
28
28
  class Query
29
- include Extlib::Assertions
29
+ include DataMapper::Assertions
30
30
  extend Equalizer
31
31
 
32
32
  OPTIONS = [ :fields, :links, :conditions, :offset, :limit, :order, :unique, :add_reversed, :reload ].to_set.freeze
@@ -106,7 +106,7 @@ module DataMapper
106
106
  elsif source.kind_of?(Enumerable)
107
107
  key = model.key(repository.name)
108
108
  conditions = Query.target_conditions(source, key, key)
109
- Query.new(repository, model, :conditions => conditions)
109
+ repository.new_query(model, :conditions => conditions)
110
110
  else
111
111
  raise ArgumentError, "+source+ must respond to #query or be an Enumerable, but was #{source.class}"
112
112
  end
@@ -349,13 +349,12 @@ module DataMapper
349
349
  #
350
350
  # @api semipublic
351
351
  def update(other)
352
- assert_kind_of 'other', other, self.class, Hash
353
-
354
352
  other_options = if kind_of?(other.class)
355
353
  return self if self.eql?(other)
356
354
  assert_valid_other(other)
357
355
  other.options
358
356
  else
357
+ other = other.to_hash
359
358
  return self if other.empty?
360
359
  other
361
360
  end
@@ -401,7 +400,7 @@ module DataMapper
401
400
  #
402
401
  # @api semipublic
403
402
  def relative(options)
404
- assert_kind_of 'options', options, Hash
403
+ options = options.to_hash
405
404
 
406
405
  offset = nil
407
406
  limit = self.limit
@@ -734,7 +733,7 @@ module DataMapper
734
733
  @offset = @options.fetch :offset, 0
735
734
  @limit = @options.fetch :limit, nil
736
735
  @order = @options.fetch :order, @model.default_order(repository_name)
737
- @unique = @options.fetch :unique, false
736
+ @unique = @options.fetch :unique, true
738
737
  @add_reversed = @options.fetch :add_reversed, false
739
738
  @reload = @options.fetch :reload, false
740
739
  @raw = false
@@ -763,7 +762,7 @@ module DataMapper
763
762
  #
764
763
  # @api private
765
764
  def assert_valid_options(options)
766
- assert_kind_of 'options', options, Hash
765
+ options = options.to_hash
767
766
 
768
767
  options.each do |attribute, value|
769
768
  case attribute
@@ -785,7 +784,7 @@ module DataMapper
785
784
  #
786
785
  # @api private
787
786
  def assert_valid_fields(fields, unique)
788
- assert_kind_of 'options[:fields]', fields, Array
787
+ fields = fields.to_ary
789
788
 
790
789
  model = self.model
791
790
 
@@ -814,7 +813,7 @@ module DataMapper
814
813
  #
815
814
  # @api private
816
815
  def assert_valid_links(links)
817
- assert_kind_of 'options[:links]', links, Array
816
+ links = links.to_ary
818
817
 
819
818
  if links.empty?
820
819
  raise ArgumentError, '+options[:links]+ should not be empty'
@@ -854,7 +853,7 @@ module DataMapper
854
853
  inspect = subject.inspect
855
854
 
856
855
  case subject
857
- when Symbol, String
856
+ when Symbol, ::String
858
857
  unless subject.to_s.include?('.') || @properties.named?(subject) || @relationships.key?(subject)
859
858
  raise ArgumentError, "condition #{inspect} does not map to a property or relationship in #{model}"
860
859
  end
@@ -899,7 +898,7 @@ module DataMapper
899
898
  # Verifies that query offset is non-negative and only used together with limit
900
899
  # @api private
901
900
  def assert_valid_offset(offset, limit)
902
- assert_kind_of 'options[:offset]', offset, Integer
901
+ offset = offset.to_int
903
902
 
904
903
  unless offset >= 0
905
904
  raise ArgumentError, "+options[:offset]+ must be greater than or equal to 0, but was #{offset.inspect}"
@@ -917,7 +916,7 @@ module DataMapper
917
916
  #
918
917
  # @api private
919
918
  def assert_valid_limit(limit)
920
- assert_kind_of 'options[:limit]', limit, Integer
919
+ limit = limit.to_int
921
920
 
922
921
  unless limit >= 0
923
922
  raise ArgumentError, "+options[:limit]+ must be greater than or equal to 0, but was #{limit.inspect}"
@@ -1105,28 +1104,6 @@ module DataMapper
1105
1104
  if relationship.respond_to?(:links)
1106
1105
  stack.concat(relationship.links)
1107
1106
  elsif !@links.include?(relationship)
1108
- repository_name = relationship.relative_target_repository_name
1109
- model = relationship.target_model
1110
-
1111
- # TODO: see if this can handle extracting the :order option and sort the
1112
- # resulting collection using the order specified by through relationships
1113
-
1114
- model.current_scope.merge(relationship.query).each do |subject, value|
1115
- # TODO: figure out how to merge Query options from links
1116
- if OPTIONS.include?(subject)
1117
- next # skip for now
1118
- end
1119
-
1120
- # set @repository when appending conditions
1121
- original, @repository = @repository, DataMapper.repository(repository_name)
1122
-
1123
- begin
1124
- append_condition(subject, value, model)
1125
- ensure
1126
- @repository = original
1127
- end
1128
- end
1129
-
1130
1107
  @links << relationship
1131
1108
  end
1132
1109
  end
@@ -1424,7 +1401,7 @@ module DataMapper
1424
1401
  model,
1425
1402
  model,
1426
1403
  self_relationship_options
1427
- )
1404
+ )
1428
1405
  end
1429
1406
  end
1430
1407
 
@@ -1440,8 +1417,8 @@ module DataMapper
1440
1417
  {
1441
1418
  :child_key => keys,
1442
1419
  :parent_key => keys,
1443
- :child_repository_name => repository,
1444
- :parent_repository_name => repository,
1420
+ :child_repository_name => repository.name,
1421
+ :parent_repository_name => repository.name,
1445
1422
  }
1446
1423
  end
1447
1424
 
@@ -340,7 +340,7 @@ module DataMapper
340
340
 
341
341
  # @api private
342
342
  def dump_property(value)
343
- subject.value(value)
343
+ subject.dump(value)
344
344
  end
345
345
 
346
346
  # Returns a value for the comparison +subject+
@@ -385,7 +385,7 @@ module DataMapper
385
385
  def record_value_from_hash(hash, subject, key_type)
386
386
  hash.fetch subject, case subject
387
387
  when Property
388
- hash[subject.field]
388
+ subject.load(hash[subject.field])
389
389
  when Associations::Relationship
390
390
  subject.send(key_type).map { |property|
391
391
  record_value_from_hash(hash, property, key_type)
@@ -471,8 +471,10 @@ module DataMapper
471
471
  #
472
472
  # @api semipublic
473
473
  def foreign_key_mapping
474
- inverse = subject.inverse
475
- Query.target_conditions(value, inverse.source_key, inverse.target_key)
474
+ relationship = subject.inverse
475
+ relationship = relationship.links.first if relationship.respond_to?(:links)
476
+
477
+ Query.target_conditions(value, relationship.source_key, relationship.target_key)
476
478
  end
477
479
 
478
480
  private
@@ -624,7 +626,7 @@ module DataMapper
624
626
 
625
627
  # @api private
626
628
  def valid_range?(range)
627
- (!range.empty? || negated?) && valid_for_subject?(range.first) && valid_for_subject?(range.last)
629
+ (range.any? || negated?) && valid_for_subject?(range.first) && valid_for_subject?(range.last)
628
630
  end
629
631
 
630
632
  # @api private
@@ -697,7 +699,7 @@ module DataMapper
697
699
  # @api private
698
700
  def dump
699
701
  loaded_value = self.loaded_value
700
- if subject.respond_to?(:value) && loaded_value.respond_to?(:map) && !loaded_value.kind_of?(Range)
702
+ if subject.respond_to?(:dump) && loaded_value.respond_to?(:map) && !loaded_value.kind_of?(Range)
701
703
  dumped_value = loaded_value.map { |value| dump_property(value) }
702
704
  dumped_value.uniq!
703
705
  dumped_value
@@ -66,7 +66,7 @@ module DataMapper
66
66
  end # class Operation
67
67
 
68
68
  class AbstractOperation
69
- include Extlib::Assertions
69
+ include DataMapper::Assertions
70
70
  include Enumerable
71
71
  extend Equalizer
72
72
 
@@ -132,6 +132,17 @@ module DataMapper
132
132
  self.class.slug
133
133
  end
134
134
 
135
+ # Get the first operand
136
+ #
137
+ # @return [AbstractOperation, AbstractComparison, Array]
138
+ # returns the first operand
139
+ #
140
+ # @api semipublic
141
+ def first
142
+ each { |operand| return operand }
143
+ nil
144
+ end
145
+
135
146
  # Iterate through each operand in the operation
136
147
  #
137
148
  # @yield [operand]
@@ -149,6 +160,26 @@ module DataMapper
149
160
  self
150
161
  end
151
162
 
163
+ # Test to see if there are operands
164
+ #
165
+ # @return [Boolean]
166
+ # returns true if there are operands
167
+ #
168
+ # @api semipublic
169
+ def empty?
170
+ @operands.empty?
171
+ end
172
+
173
+ # Test to see if there is one operand
174
+ #
175
+ # @return [Boolean]
176
+ # true if there is only one operand
177
+ #
178
+ # @api semipublic
179
+ def one?
180
+ @operands.size == 1
181
+ end
182
+
152
183
  # Test if the operation is valid
153
184
  #
154
185
  # @return [Boolean]
@@ -359,7 +390,7 @@ module DataMapper
359
390
  # @return [AbstractOperation, AbstractComparison, Array]
360
391
  # the operand that was related to self
361
392
  #
362
- # @api privTE
393
+ # @api private
363
394
  def relate_operand(operand)
364
395
  operand.parent = self if operand.respond_to?(:parent=)
365
396
  operand
@@ -8,7 +8,7 @@
8
8
  module DataMapper
9
9
  class Query
10
10
  class Operator
11
- include Extlib::Assertions
11
+ include DataMapper::Assertions
12
12
  extend Equalizer
13
13
 
14
14
  equalize :target, :operator
@@ -28,10 +28,7 @@ module DataMapper
28
28
 
29
29
  # @api private
30
30
  def initialize(target, operator)
31
- assert_kind_of 'operator', operator, Symbol
32
-
33
- @target = target
34
- @operator = operator
31
+ @target, @operator = target, operator.to_sym
35
32
  end
36
33
  end # class Operator
37
34
  end # class Query