ripple 0.9.5 → 1.0.0.beta

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 (152) hide show
  1. data/.gitignore +32 -0
  2. data/Gemfile +10 -9
  3. data/Guardfile +15 -0
  4. data/Rakefile +11 -40
  5. data/lib/rails/generators/ripple/configuration/configuration_generator.rb +0 -13
  6. data/lib/rails/generators/ripple/configuration/templates/ripple.yml +4 -4
  7. data/lib/rails/generators/ripple/js/js_generator.rb +0 -13
  8. data/lib/rails/generators/ripple/js/templates/js/contrib.js +0 -17
  9. data/lib/rails/generators/ripple/js/templates/js/ripple.js +0 -13
  10. data/lib/rails/generators/ripple/model/model_generator.rb +0 -14
  11. data/lib/rails/generators/ripple/model/templates/model.rb +1 -1
  12. data/lib/rails/generators/ripple/observer/observer_generator.rb +0 -14
  13. data/lib/rails/generators/ripple/test/test_generator.rb +7 -19
  14. data/lib/rails/generators/ripple_generator.rb +1 -14
  15. data/lib/ripple.rb +7 -14
  16. data/lib/ripple/associations.rb +129 -26
  17. data/lib/ripple/associations/embedded.rb +1 -15
  18. data/lib/ripple/associations/instantiators.rb +0 -13
  19. data/lib/ripple/associations/linked.rb +41 -19
  20. data/lib/ripple/associations/many.rb +0 -14
  21. data/lib/ripple/associations/many_embedded_proxy.rb +0 -14
  22. data/lib/ripple/associations/many_linked_proxy.rb +39 -18
  23. data/lib/ripple/associations/many_reference_proxy.rb +93 -0
  24. data/lib/ripple/associations/many_stored_key_proxy.rb +76 -0
  25. data/lib/ripple/associations/one.rb +1 -15
  26. data/lib/ripple/associations/one_embedded_proxy.rb +0 -14
  27. data/lib/ripple/associations/one_key_proxy.rb +58 -0
  28. data/lib/ripple/associations/one_linked_proxy.rb +4 -14
  29. data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
  30. data/lib/ripple/associations/proxy.rb +8 -14
  31. data/lib/ripple/attribute_methods.rb +19 -17
  32. data/lib/ripple/attribute_methods/dirty.rb +19 -15
  33. data/lib/ripple/attribute_methods/query.rb +0 -14
  34. data/lib/ripple/attribute_methods/read.rb +0 -14
  35. data/lib/ripple/attribute_methods/write.rb +0 -14
  36. data/lib/ripple/callbacks.rb +10 -16
  37. data/lib/ripple/conflict/basic_resolver.rb +82 -0
  38. data/lib/ripple/conflict/document_hooks.rb +20 -0
  39. data/lib/ripple/conflict/resolver.rb +71 -0
  40. data/lib/ripple/conflict/test_helper.rb +33 -0
  41. data/lib/ripple/conversion.rb +0 -14
  42. data/lib/ripple/core_ext.rb +1 -14
  43. data/lib/ripple/core_ext/casting.rb +19 -19
  44. data/lib/ripple/core_ext/object.rb +8 -0
  45. data/lib/ripple/document.rb +21 -16
  46. data/lib/ripple/document/bucket_access.rb +0 -14
  47. data/lib/ripple/document/finders.rb +17 -23
  48. data/lib/ripple/document/key.rb +8 -28
  49. data/lib/ripple/document/link.rb +30 -0
  50. data/lib/ripple/document/persistence.rb +12 -20
  51. data/lib/ripple/embedded_document.rb +10 -15
  52. data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
  53. data/lib/ripple/embedded_document/finders.rb +7 -18
  54. data/lib/ripple/embedded_document/persistence.rb +5 -17
  55. data/lib/ripple/i18n.rb +0 -14
  56. data/lib/ripple/inspection.rb +21 -15
  57. data/lib/ripple/locale/en.yml +9 -13
  58. data/lib/ripple/nested_attributes.rb +33 -39
  59. data/lib/ripple/observable.rb +0 -13
  60. data/lib/ripple/properties.rb +1 -14
  61. data/lib/ripple/property_type_mismatch.rb +0 -14
  62. data/lib/ripple/railtie.rb +4 -14
  63. data/lib/ripple/railties/ripple.rake +86 -0
  64. data/lib/ripple/serialization.rb +11 -11
  65. data/lib/ripple/test_server.rb +36 -0
  66. data/lib/ripple/timestamps.rb +0 -13
  67. data/lib/ripple/translation.rb +4 -14
  68. data/lib/ripple/validations.rb +1 -15
  69. data/lib/ripple/validations/associated_validator.rb +26 -17
  70. data/lib/ripple/version.rb +3 -0
  71. data/ripple.gemspec +24 -35
  72. data/spec/integration/ripple/associations_spec.rb +89 -58
  73. data/spec/integration/ripple/conflict_resolution_spec.rb +298 -0
  74. data/spec/integration/ripple/nested_attributes_spec.rb +19 -19
  75. data/spec/integration/ripple/persistence_spec.rb +15 -34
  76. data/spec/integration/ripple/search_associations_spec.rb +31 -0
  77. data/spec/ripple/associations/many_embedded_proxy_spec.rb +23 -36
  78. data/spec/ripple/associations/many_linked_proxy_spec.rb +133 -45
  79. data/spec/ripple/associations/many_reference_proxy_spec.rb +170 -0
  80. data/spec/ripple/associations/many_stored_key_proxy_spec.rb +158 -0
  81. data/spec/ripple/associations/one_embedded_proxy_spec.rb +24 -37
  82. data/spec/ripple/associations/one_key_proxy_spec.rb +82 -0
  83. data/spec/ripple/associations/one_linked_proxy_spec.rb +22 -23
  84. data/spec/ripple/associations/one_stored_key_proxy_spec.rb +72 -0
  85. data/spec/ripple/associations/proxy_spec.rb +21 -15
  86. data/spec/ripple/associations_spec.rb +54 -23
  87. data/spec/ripple/attribute_methods/dirty_spec.rb +56 -5
  88. data/spec/ripple/attribute_methods_spec.rb +47 -21
  89. data/spec/ripple/bucket_access_spec.rb +4 -17
  90. data/spec/ripple/callbacks_spec.rb +52 -15
  91. data/spec/ripple/conflict/resolver_spec.rb +42 -0
  92. data/spec/ripple/conversion_spec.rb +2 -15
  93. data/spec/ripple/core_ext_spec.rb +12 -15
  94. data/spec/ripple/document/link_spec.rb +67 -0
  95. data/spec/ripple/document_spec.rb +34 -19
  96. data/spec/ripple/embedded_document/finders_spec.rb +12 -19
  97. data/spec/ripple/embedded_document/persistence_spec.rb +20 -26
  98. data/spec/ripple/embedded_document_spec.rb +44 -34
  99. data/spec/ripple/finders_spec.rb +58 -29
  100. data/spec/ripple/inspection_spec.rb +40 -37
  101. data/spec/ripple/key_spec.rb +5 -17
  102. data/spec/ripple/observable_spec.rb +3 -16
  103. data/spec/ripple/persistence_spec.rb +134 -18
  104. data/spec/ripple/properties_spec.rb +21 -15
  105. data/spec/ripple/ripple_spec.rb +1 -14
  106. data/spec/ripple/serialization_spec.rb +16 -17
  107. data/spec/ripple/timestamps_spec.rb +73 -52
  108. data/spec/ripple/validations/associated_validator_spec.rb +69 -25
  109. data/spec/ripple/validations_spec.rb +3 -16
  110. data/spec/spec_helper.rb +17 -18
  111. data/spec/support/associations.rb +1 -1
  112. data/spec/support/associations/proxies.rb +0 -13
  113. data/spec/support/integration_setup.rb +11 -0
  114. data/spec/support/mocks.rb +0 -13
  115. data/spec/support/models.rb +33 -2
  116. data/spec/support/models/address.rb +1 -16
  117. data/spec/support/models/box.rb +7 -14
  118. data/spec/support/models/car.rb +27 -1
  119. data/spec/support/models/cardboard_box.rb +0 -14
  120. data/spec/support/models/clock.rb +6 -15
  121. data/spec/support/models/clock_observer.rb +0 -14
  122. data/spec/support/models/credit_card.rb +5 -0
  123. data/spec/support/models/customer.rb +0 -14
  124. data/spec/support/models/email.rb +0 -14
  125. data/spec/support/models/family.rb +1 -13
  126. data/spec/support/models/favorite.rb +0 -14
  127. data/spec/support/models/invoice.rb +0 -14
  128. data/spec/support/models/late_invoice.rb +0 -14
  129. data/spec/support/models/nested.rb +12 -0
  130. data/spec/support/models/ninja.rb +7 -0
  131. data/spec/support/models/note.rb +0 -14
  132. data/spec/support/models/page.rb +1 -15
  133. data/spec/support/models/paid_invoice.rb +0 -14
  134. data/spec/support/models/post.rb +12 -0
  135. data/spec/support/models/profile.rb +7 -0
  136. data/spec/support/models/subscription.rb +26 -0
  137. data/spec/support/models/tasks.rb +0 -18
  138. data/spec/support/models/team.rb +11 -0
  139. data/spec/support/models/transactions.rb +17 -0
  140. data/spec/support/models/tree.rb +2 -16
  141. data/spec/support/models/user.rb +14 -16
  142. data/spec/support/models/widget.rb +8 -14
  143. data/spec/support/search.rb +14 -0
  144. data/spec/support/test_server.rb +22 -12
  145. data/spec/support/test_server.yml.example +14 -2
  146. metadata +223 -59
  147. data/lib/rails/generators/ripple/test/templates/test_server.rb +0 -46
  148. data/spec/support/models/driver.rb +0 -5
  149. data/spec/support/models/engine.rb +0 -4
  150. data/spec/support/models/passenger.rb +0 -5
  151. data/spec/support/models/seat.rb +0 -4
  152. data/spec/support/models/wheel.rb +0 -5
@@ -0,0 +1,58 @@
1
+ require 'ripple/associations/proxy'
2
+ require 'ripple/associations/one'
3
+
4
+ module Ripple
5
+ module Associations
6
+ class OneKeyProxy < Proxy
7
+ include One
8
+
9
+ def replace(doc)
10
+ @reflection.verify_type!(doc, owner)
11
+
12
+ reset_previous_target_key_delegate
13
+ assign_new_target_key_delegate(doc)
14
+
15
+ loaded
16
+ @target = doc
17
+ end
18
+
19
+ def find_target
20
+ klass.find(owner.key)
21
+ end
22
+
23
+ protected
24
+ def instantiate_target(instantiator, attrs={})
25
+ @target = super
26
+ @target.key = owner.key
27
+ @target
28
+ end
29
+
30
+ private
31
+ def reset_previous_target_key_delegate
32
+ @target.key_delegate = @target if @target
33
+ end
34
+
35
+ def assign_new_target_key_delegate(doc)
36
+ doc.class.send(:include, Ripple::Associations::KeyDelegator) unless doc.class.include?(Ripple::Associations::KeyDelegator)
37
+ owner.key_delegate = doc.key_delegate = owner
38
+ end
39
+
40
+ end
41
+
42
+ module KeyDelegator
43
+ attr_accessor :key_delegate
44
+
45
+ def key_delegate
46
+ @key_delegate || self
47
+ end
48
+
49
+ def key
50
+ self === key_delegate ? super : key_delegate.key
51
+ end
52
+
53
+ def key=(value)
54
+ self === key_delegate ? super(value) : key_delegate.key = value
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,17 +1,3 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
1
  require 'ripple/associations/proxy'
16
2
  require 'ripple/associations/one'
17
3
  require 'ripple/associations/linked'
@@ -22,6 +8,10 @@ module Ripple
22
8
  include One
23
9
  include Linked
24
10
 
11
+ def key
12
+ keys.first
13
+ end
14
+
25
15
  protected
26
16
  def find_target
27
17
  return nil if links.blank?
@@ -0,0 +1,43 @@
1
+ require 'ripple/associations/proxy'
2
+ require 'ripple/associations/one'
3
+
4
+ module Ripple
5
+ module Associations
6
+ class OneStoredKeyProxy < Proxy
7
+ include One
8
+
9
+ def replace(value)
10
+ @reflection.verify_type!(value, owner)
11
+
12
+ if value
13
+ assign_key(value.key)
14
+ else
15
+ assign_key(nil)
16
+ end
17
+
18
+ @target = value
19
+ loaded
20
+ end
21
+
22
+ protected
23
+
24
+ def key
25
+ @owner.send(key_name)
26
+ end
27
+
28
+ def assign_key(value)
29
+ @owner.send("#{key_name}=", value)
30
+ end
31
+
32
+ def key_name
33
+ "#{@reflection.name}_key"
34
+ end
35
+
36
+ def find_target
37
+ return nil if key.blank?
38
+
39
+ klass.find(key)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,17 +1,3 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
1
  require 'ripple/associations'
16
2
 
17
3
  module Ripple
@@ -99,6 +85,14 @@ module Ripple
99
85
  other === target
100
86
  end
101
87
 
88
+ def loaded_documents
89
+ loaded? ? Array(target) : []
90
+ end
91
+
92
+ def has_changed_documents?
93
+ loaded_documents.any? { |doc| doc.changed? }
94
+ end
95
+
102
96
  protected
103
97
  def method_missing(method, *args, &block)
104
98
  load_target
@@ -1,17 +1,3 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
1
  require 'ripple/translation'
16
2
  require 'active_support/concern'
17
3
  require 'active_model/attribute_methods'
@@ -35,7 +21,7 @@ module Ripple
35
21
  include Query
36
22
  include Dirty
37
23
  include ActiveModel::MassAssignmentSecurity
38
-
24
+
39
25
  attr_protected :key
40
26
  end
41
27
 
@@ -59,6 +45,10 @@ module Ripple
59
45
  # nor embedded documents.
60
46
  # @return [Hash] all document attributes, by key
61
47
  def attributes
48
+ raw_attributes.reject { |k, v| !respond_to?(k) }
49
+ end
50
+
51
+ def raw_attributes
62
52
  self.class.properties.values.inject(@attributes.with_indifferent_access) do |hash, prop|
63
53
  hash[prop.key] = attribute(prop.key)
64
54
  hash
@@ -67,9 +57,21 @@ module Ripple
67
57
 
68
58
  # Mass assign the document's attributes.
69
59
  # @param [Hash] attrs the attributes to assign
70
- def attributes=(attrs, guard_protected_attrs = true)
60
+ def attributes=(attrs)
61
+ raise ArgumentError, t('attribute_hash') unless Hash === attrs
62
+ sanitize_for_mass_assignment(attrs).each do |k,v|
63
+ if respond_to?("#{k}=")
64
+ __send__("#{k}=",v)
65
+ else
66
+ raise ArgumentError, t('undefined_property', :prop => k, :class => self.class.name)
67
+ end
68
+ end
69
+ end
70
+
71
+ # @private
72
+ def raw_attributes=(attrs)
71
73
  raise ArgumentError, t('attribute_hash') unless Hash === attrs
72
- (guard_protected_attrs ? sanitize_for_mass_assignment(attrs) : attrs).each do |k,v|
74
+ attrs.each do |k,v|
73
75
  next if k.to_sym == :key
74
76
  if respond_to?("#{k}=")
75
77
  __send__("#{k}=",v)
@@ -1,17 +1,3 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
1
  require 'active_support/concern'
16
2
  require 'active_model/dirty'
17
3
 
@@ -21,6 +7,15 @@ module Ripple
21
7
  extend ActiveSupport::Concern
22
8
  include ActiveModel::Dirty
23
9
 
10
+ module ClassMethods
11
+ # @private
12
+ def instantiate(robject)
13
+ super(robject).tap do |o|
14
+ o.changed_attributes.clear
15
+ end
16
+ end
17
+ end
18
+
24
19
  # @private
25
20
  def really_save(*args)
26
21
  if result = super
@@ -43,9 +38,18 @@ module Ripple
43
38
  changed_attributes.clear
44
39
  end
45
40
 
41
+ # Determines if the document has any chnages.
42
+ # @return [Boolean] true if this document, or any of its embedded
43
+ # documents at any level, have changed.
44
+ def changed?
45
+ super || self.class.embedded_associations.any? do |association|
46
+ send(association.name).has_changed_documents?
47
+ end
48
+ end
49
+
46
50
  private
47
51
  def attribute=(attr_name, value)
48
- if self.class.properties.include?(attr_name.intern) && @attributes[attr_name] != value
52
+ if self.class.properties.include?(attr_name.to_sym) && @attributes[attr_name] != value
49
53
  attribute_will_change!(attr_name)
50
54
  end
51
55
  super
@@ -1,17 +1,3 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
1
  require 'active_support/concern'
16
2
 
17
3
  module Ripple
@@ -1,17 +1,3 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
1
  require 'active_support/concern'
16
2
 
17
3
  module Ripple
@@ -1,17 +1,3 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
1
  require 'active_support/concern'
16
2
 
17
3
  module Ripple
@@ -1,17 +1,3 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
1
  require 'active_support/concern'
16
2
  require 'active_model/callbacks'
17
3
 
@@ -21,9 +7,11 @@ module Ripple
21
7
  module Callbacks
22
8
  extend ActiveSupport::Concern
23
9
 
10
+ CALLBACK_TYPES = [:create, :update, :save, :destroy, :validation]
11
+
24
12
  included do
25
13
  extend ActiveModel::Callbacks
26
- define_model_callbacks :create, :update, :save, :destroy
14
+ define_model_callbacks *(CALLBACK_TYPES - [:validation])
27
15
  define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
28
16
  end
29
17
 
@@ -53,10 +41,16 @@ module Ripple
53
41
  module InstanceMethods
54
42
  # @private
55
43
  def really_save(*args, &block)
44
+ run_save_callbacks do
45
+ super
46
+ end
47
+ end
48
+
49
+ def run_save_callbacks
56
50
  state = new? ? :create : :update
57
51
  run_callbacks(:save) do
58
52
  run_callbacks(state) do
59
- super
53
+ yield
60
54
  end
61
55
  end
62
56
  end
@@ -0,0 +1,82 @@
1
+ module Ripple
2
+ module Conflict
3
+ class BasicResolver
4
+ delegate :model_class, :document, :siblings, :to => :@main_resolver
5
+
6
+ def initialize(main_resolver)
7
+ @main_resolver = main_resolver
8
+ end
9
+
10
+ def remaining_conflicts
11
+ @remaining_conflicts ||= []
12
+ end
13
+
14
+ def unexpected_conflicts
15
+ # if the user didn't specify the conflict they expect,
16
+ # then don't consider any conflicts unexpected
17
+ return [] if model_class.expected_conflicts.blank?
18
+
19
+ remaining_conflicts - model_class.expected_conflicts
20
+ end
21
+
22
+ def perform
23
+ process_properties
24
+ process_embedded_associations
25
+ process_linked_associations
26
+ process_stored_key_associations
27
+ end
28
+
29
+ private
30
+
31
+ def process_properties
32
+ model_class.properties.each do |name, property|
33
+ document.send(:"#{name}=", resolved_property_value_for(property))
34
+ end
35
+ end
36
+
37
+ def process_embedded_associations
38
+ model_class.embedded_associations.each do |assoc|
39
+ document.send(:"#{assoc.name}=", resolved_association_value_for(assoc, :load_target))
40
+ end
41
+ end
42
+
43
+ def process_linked_associations
44
+ model_class.linked_associations.each do |assoc|
45
+ document.send(assoc.name).replace_links(resolved_association_value_for(assoc, :links))
46
+ end
47
+ end
48
+
49
+ def process_stored_key_associations
50
+ model_class.stored_key_associations.each do |assoc|
51
+ document.send(assoc.name).reset_owner_keys if (assoc.type == :many)
52
+ end
53
+ end
54
+
55
+ def resolved_property_value_for(property)
56
+ uniq_values = siblings.map(&property.key).uniq
57
+
58
+ value = if uniq_values.size == 1
59
+ uniq_values.first
60
+ elsif property.key == :updated_at
61
+ uniq_values.compact.max
62
+ elsif property.key == :created_at
63
+ uniq_values.compact.min
64
+ else
65
+ remaining_conflicts << property.key
66
+ property.default
67
+ end
68
+ end
69
+
70
+ def resolved_association_value_for(association, proxy_value_method)
71
+ # the association proxy doesn't uniquify well, so we have to use the target or links directly
72
+ uniq_values = siblings.map { |s| s.send(association.name).__send__(proxy_value_method) }.uniq
73
+
74
+ return uniq_values.first if uniq_values.size == 1
75
+ remaining_conflicts << association.name
76
+
77
+ association.many? ? [] : nil # default value
78
+ end
79
+ end
80
+ end
81
+ end
82
+