sbf-dm-core 1.3.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 (259) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +29 -0
  3. data/.document +5 -0
  4. data/.gitignore +44 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +468 -0
  7. data/.travis.yml +57 -0
  8. data/.yardopts +1 -0
  9. data/Gemfile +70 -0
  10. data/LICENSE +20 -0
  11. data/README.md +269 -0
  12. data/Rakefile +4 -0
  13. data/dm-core.gemspec +21 -0
  14. data/lib/dm-core/adapters/abstract_adapter.rb +233 -0
  15. data/lib/dm-core/adapters/in_memory_adapter.rb +110 -0
  16. data/lib/dm-core/adapters.rb +249 -0
  17. data/lib/dm-core/associations/many_to_many.rb +477 -0
  18. data/lib/dm-core/associations/many_to_one.rb +282 -0
  19. data/lib/dm-core/associations/one_to_many.rb +332 -0
  20. data/lib/dm-core/associations/one_to_one.rb +84 -0
  21. data/lib/dm-core/associations/relationship.rb +650 -0
  22. data/lib/dm-core/backwards.rb +11 -0
  23. data/lib/dm-core/collection.rb +1486 -0
  24. data/lib/dm-core/core_ext/kernel.rb +21 -0
  25. data/lib/dm-core/core_ext/pathname.rb +4 -0
  26. data/lib/dm-core/core_ext/symbol.rb +10 -0
  27. data/lib/dm-core/identity_map.rb +6 -0
  28. data/lib/dm-core/model/hook.rb +99 -0
  29. data/lib/dm-core/model/is.rb +30 -0
  30. data/lib/dm-core/model/property.rb +244 -0
  31. data/lib/dm-core/model/relationship.rb +366 -0
  32. data/lib/dm-core/model/scope.rb +87 -0
  33. data/lib/dm-core/model.rb +876 -0
  34. data/lib/dm-core/property/binary.rb +19 -0
  35. data/lib/dm-core/property/boolean.rb +35 -0
  36. data/lib/dm-core/property/class.rb +23 -0
  37. data/lib/dm-core/property/date.rb +45 -0
  38. data/lib/dm-core/property/date_time.rb +44 -0
  39. data/lib/dm-core/property/decimal.rb +47 -0
  40. data/lib/dm-core/property/discriminator.rb +40 -0
  41. data/lib/dm-core/property/float.rb +27 -0
  42. data/lib/dm-core/property/integer.rb +32 -0
  43. data/lib/dm-core/property/invalid_value_error.rb +17 -0
  44. data/lib/dm-core/property/lookup.rb +26 -0
  45. data/lib/dm-core/property/numeric.rb +35 -0
  46. data/lib/dm-core/property/object.rb +33 -0
  47. data/lib/dm-core/property/serial.rb +13 -0
  48. data/lib/dm-core/property/string.rb +47 -0
  49. data/lib/dm-core/property/text.rb +12 -0
  50. data/lib/dm-core/property/time.rb +46 -0
  51. data/lib/dm-core/property/typecast/numeric.rb +32 -0
  52. data/lib/dm-core/property/typecast/time.rb +33 -0
  53. data/lib/dm-core/property.rb +856 -0
  54. data/lib/dm-core/property_set.rb +177 -0
  55. data/lib/dm-core/query/conditions/comparison.rb +886 -0
  56. data/lib/dm-core/query/conditions/operation.rb +710 -0
  57. data/lib/dm-core/query/direction.rb +33 -0
  58. data/lib/dm-core/query/operator.rb +34 -0
  59. data/lib/dm-core/query/path.rb +113 -0
  60. data/lib/dm-core/query/sort.rb +38 -0
  61. data/lib/dm-core/query.rb +1352 -0
  62. data/lib/dm-core/relationship_set.rb +69 -0
  63. data/lib/dm-core/repository.rb +226 -0
  64. data/lib/dm-core/resource/persistence_state/clean.rb +36 -0
  65. data/lib/dm-core/resource/persistence_state/deleted.rb +26 -0
  66. data/lib/dm-core/resource/persistence_state/dirty.rb +91 -0
  67. data/lib/dm-core/resource/persistence_state/immutable.rb +32 -0
  68. data/lib/dm-core/resource/persistence_state/persisted.rb +25 -0
  69. data/lib/dm-core/resource/persistence_state/transient.rb +87 -0
  70. data/lib/dm-core/resource/persistence_state.rb +70 -0
  71. data/lib/dm-core/resource.rb +1220 -0
  72. data/lib/dm-core/spec/lib/adapter_helpers.rb +63 -0
  73. data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
  74. data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
  75. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  76. data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
  77. data/lib/dm-core/spec/setup.rb +164 -0
  78. data/lib/dm-core/spec/shared/adapter_spec.rb +366 -0
  79. data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
  80. data/lib/dm-core/spec/shared/resource_spec.rb +1221 -0
  81. data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
  82. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +184 -0
  83. data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
  84. data/lib/dm-core/support/assertions.rb +8 -0
  85. data/lib/dm-core/support/chainable.rb +18 -0
  86. data/lib/dm-core/support/deprecate.rb +12 -0
  87. data/lib/dm-core/support/descendant_set.rb +89 -0
  88. data/lib/dm-core/support/equalizer.rb +48 -0
  89. data/lib/dm-core/support/ext/array.rb +22 -0
  90. data/lib/dm-core/support/ext/blank.rb +25 -0
  91. data/lib/dm-core/support/ext/hash.rb +67 -0
  92. data/lib/dm-core/support/ext/module.rb +47 -0
  93. data/lib/dm-core/support/ext/object.rb +57 -0
  94. data/lib/dm-core/support/ext/string.rb +24 -0
  95. data/lib/dm-core/support/ext/try_dup.rb +12 -0
  96. data/lib/dm-core/support/hook.rb +388 -0
  97. data/lib/dm-core/support/inflections.rb +60 -0
  98. data/lib/dm-core/support/inflector/inflections.rb +211 -0
  99. data/lib/dm-core/support/inflector/methods.rb +151 -0
  100. data/lib/dm-core/support/lazy_array.rb +451 -0
  101. data/lib/dm-core/support/local_object_space.rb +13 -0
  102. data/lib/dm-core/support/logger.rb +201 -0
  103. data/lib/dm-core/support/mash.rb +176 -0
  104. data/lib/dm-core/support/naming_conventions.rb +109 -0
  105. data/lib/dm-core/support/ordered_set.rb +381 -0
  106. data/lib/dm-core/support/subject.rb +33 -0
  107. data/lib/dm-core/support/subject_set.rb +251 -0
  108. data/lib/dm-core/version.rb +3 -0
  109. data/lib/dm-core.rb +274 -0
  110. data/script/performance.rb +275 -0
  111. data/script/profile.rb +218 -0
  112. data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
  113. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +69 -0
  114. data/spec/public/associations/many_to_many_spec.rb +197 -0
  115. data/spec/public/associations/many_to_one_spec.rb +83 -0
  116. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
  117. data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
  118. data/spec/public/associations/one_to_many_spec.rb +81 -0
  119. data/spec/public/associations/one_to_one_spec.rb +176 -0
  120. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
  121. data/spec/public/collection_spec.rb +69 -0
  122. data/spec/public/finalize_spec.rb +77 -0
  123. data/spec/public/model/hook_spec.rb +245 -0
  124. data/spec/public/model/property_spec.rb +91 -0
  125. data/spec/public/model/relationship_spec.rb +1040 -0
  126. data/spec/public/model_spec.rb +456 -0
  127. data/spec/public/property/binary_spec.rb +43 -0
  128. data/spec/public/property/boolean_spec.rb +21 -0
  129. data/spec/public/property/class_spec.rb +27 -0
  130. data/spec/public/property/date_spec.rb +21 -0
  131. data/spec/public/property/date_time_spec.rb +21 -0
  132. data/spec/public/property/decimal_spec.rb +23 -0
  133. data/spec/public/property/discriminator_spec.rb +134 -0
  134. data/spec/public/property/float_spec.rb +22 -0
  135. data/spec/public/property/integer_spec.rb +22 -0
  136. data/spec/public/property/object_spec.rb +117 -0
  137. data/spec/public/property/serial_spec.rb +22 -0
  138. data/spec/public/property/string_spec.rb +21 -0
  139. data/spec/public/property/text_spec.rb +62 -0
  140. data/spec/public/property/time_spec.rb +21 -0
  141. data/spec/public/property_spec.rb +333 -0
  142. data/spec/public/resource/state_spec.rb +72 -0
  143. data/spec/public/resource_spec.rb +289 -0
  144. data/spec/public/sel_spec.rb +53 -0
  145. data/spec/public/setup_spec.rb +145 -0
  146. data/spec/public/shared/association_collection_shared_spec.rb +309 -0
  147. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  148. data/spec/public/shared/collection_shared_spec.rb +1637 -0
  149. data/spec/public/shared/finder_shared_spec.rb +1647 -0
  150. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  151. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
  152. data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
  153. data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
  154. data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
  155. data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
  156. data/spec/semipublic/associations/relationship_spec.rb +200 -0
  157. data/spec/semipublic/associations_spec.rb +177 -0
  158. data/spec/semipublic/collection_spec.rb +110 -0
  159. data/spec/semipublic/model_spec.rb +96 -0
  160. data/spec/semipublic/property/binary_spec.rb +13 -0
  161. data/spec/semipublic/property/boolean_spec.rb +47 -0
  162. data/spec/semipublic/property/class_spec.rb +33 -0
  163. data/spec/semipublic/property/date_spec.rb +43 -0
  164. data/spec/semipublic/property/date_time_spec.rb +46 -0
  165. data/spec/semipublic/property/decimal_spec.rb +83 -0
  166. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  167. data/spec/semipublic/property/float_spec.rb +82 -0
  168. data/spec/semipublic/property/integer_spec.rb +82 -0
  169. data/spec/semipublic/property/lookup_spec.rb +29 -0
  170. data/spec/semipublic/property/serial_spec.rb +13 -0
  171. data/spec/semipublic/property/string_spec.rb +13 -0
  172. data/spec/semipublic/property/text_spec.rb +31 -0
  173. data/spec/semipublic/property/time_spec.rb +50 -0
  174. data/spec/semipublic/property_spec.rb +114 -0
  175. data/spec/semipublic/query/conditions/comparison_spec.rb +1502 -0
  176. data/spec/semipublic/query/conditions/operation_spec.rb +1296 -0
  177. data/spec/semipublic/query/path_spec.rb +471 -0
  178. data/spec/semipublic/query_spec.rb +3665 -0
  179. data/spec/semipublic/resource/state/clean_spec.rb +89 -0
  180. data/spec/semipublic/resource/state/deleted_spec.rb +79 -0
  181. data/spec/semipublic/resource/state/dirty_spec.rb +163 -0
  182. data/spec/semipublic/resource/state/immutable_spec.rb +107 -0
  183. data/spec/semipublic/resource/state/transient_spec.rb +163 -0
  184. data/spec/semipublic/resource/state_spec.rb +230 -0
  185. data/spec/semipublic/resource_spec.rb +23 -0
  186. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  187. data/spec/semipublic/shared/resource_shared_spec.rb +198 -0
  188. data/spec/semipublic/shared/resource_state_shared_spec.rb +91 -0
  189. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  190. data/spec/spec_helper.rb +34 -0
  191. data/spec/support/core_ext/hash.rb +10 -0
  192. data/spec/support/core_ext/inheritable_attributes.rb +46 -0
  193. data/spec/support/properties/huge_integer.rb +17 -0
  194. data/spec/unit/array_spec.rb +23 -0
  195. data/spec/unit/blank_spec.rb +73 -0
  196. data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
  197. data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
  198. data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
  199. data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
  200. data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
  201. data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
  202. data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
  203. data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
  204. data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
  205. data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
  206. data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
  207. data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
  208. data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
  209. data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
  210. data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
  211. data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
  212. data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
  213. data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
  214. data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
  215. data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
  216. data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
  217. data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
  218. data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
  219. data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
  220. data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
  221. data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
  222. data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
  223. data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
  224. data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
  225. data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
  226. data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
  227. data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
  228. data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
  229. data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
  230. data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
  231. data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
  232. data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
  233. data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
  234. data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
  235. data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
  236. data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
  237. data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
  238. data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
  239. data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
  240. data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
  241. data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
  242. data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
  243. data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
  244. data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
  245. data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
  246. data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
  247. data/spec/unit/hash_spec.rb +27 -0
  248. data/spec/unit/hook_spec.rb +1216 -0
  249. data/spec/unit/inflections_spec.rb +14 -0
  250. data/spec/unit/lazy_array_spec.rb +1949 -0
  251. data/spec/unit/mash_spec.rb +289 -0
  252. data/spec/unit/module_spec.rb +70 -0
  253. data/spec/unit/object_spec.rb +38 -0
  254. data/spec/unit/try_dup_spec.rb +46 -0
  255. data/tasks/ci.rake +1 -0
  256. data/tasks/spec.rake +18 -0
  257. data/tasks/yard.rake +9 -0
  258. data/tasks/yardstick.rake +19 -0
  259. metadata +323 -0
@@ -0,0 +1,89 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe DataMapper::Resource::PersistenceState::Clean do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, HugeInteger, :key => true, :default => 1
9
+ property :name, String
10
+ property :active, Boolean, :default => true
11
+ property :coding, Boolean, :default => true
12
+
13
+ belongs_to :parent, self, :required => false
14
+ has n, :children, self, :inverse => :parent
15
+ end
16
+ DataMapper.finalize
17
+
18
+ @model = Author
19
+ end
20
+
21
+ before do
22
+ @resource = @model.create(:name => 'Dan Kubb')
23
+
24
+ @state = @resource.persistence_state
25
+ expect(@state).to be_kind_of(DataMapper::Resource::PersistenceState::Clean)
26
+ end
27
+
28
+ after do
29
+ @model.destroy!
30
+ end
31
+
32
+ [ :commit, :rollback ].each do |method|
33
+ describe "##{method}" do
34
+ subject { @state.send(method) }
35
+
36
+ supported_by :all do
37
+ it 'is a no-op' do
38
+ is_expected.to equal(@state)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#delete' do
45
+ subject { @state.delete }
46
+
47
+ supported_by :all do
48
+ it 'returns a Deleted state' do
49
+ is_expected.to eql(DataMapper::Resource::PersistenceState::Deleted.new(@resource))
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '#get' do
55
+ it_behaves_like 'Resource::PersistenceState::Persisted#get'
56
+ end
57
+
58
+ describe '#set' do
59
+ subject { @state.set(@key, @value) }
60
+
61
+ supported_by :all do
62
+ describe 'with attributes that make the resource dirty' do
63
+ before do
64
+ @key = @model.properties[:name]
65
+ @value = nil
66
+ end
67
+
68
+ it_behaves_like 'A method that delegates to the superclass #set'
69
+
70
+ it 'returns a Dirty state' do
71
+ is_expected.to eql(DataMapper::Resource::PersistenceState::Dirty.new(@resource))
72
+ end
73
+ end
74
+
75
+ describe 'with attributes that keep the resource clean' do
76
+ before do
77
+ @key = @model.properties[:name]
78
+ @value = 'Dan Kubb'
79
+ end
80
+
81
+ it_behaves_like 'A method that does not delegate to the superclass #set'
82
+
83
+ it 'returns a Clean state' do
84
+ is_expected.to equal(@state)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,79 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe DataMapper::Resource::PersistenceState::Deleted do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, HugeInteger, :key => true, :default => 1
9
+ property :name, String
10
+ property :active, Boolean, :default => true
11
+ property :coding, Boolean, :default => true
12
+
13
+ belongs_to :parent, self, :required => false
14
+ has n, :children, self, :inverse => :parent
15
+ end
16
+
17
+ DataMapper.finalize
18
+ @model = Author
19
+ end
20
+
21
+ before do
22
+ @resource = @model.create(:name => 'Dan Kubb')
23
+
24
+ @state = DataMapper::Resource::PersistenceState::Deleted.new(@resource)
25
+ end
26
+
27
+ after do
28
+ @model.destroy!
29
+ end
30
+
31
+ describe '#commit' do
32
+ subject { @state.commit }
33
+
34
+ supported_by :all do
35
+ it 'returns an Immutable state' do
36
+ is_expected.to eql(DataMapper::Resource::PersistenceState::Immutable.new(@resource))
37
+ end
38
+
39
+ it 'deletes the resource' do
40
+ subject
41
+ expect(@model.get(*@resource.key)).to be_nil
42
+ end
43
+
44
+ it 'removes the resource from the identity map' do
45
+ identity_map = @resource.repository.identity_map(@model)
46
+ expect { method(:subject) }.to change { identity_map.dup }.from(@resource.key => @resource).to({})
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#delete' do
52
+ subject { @state.delete }
53
+
54
+ supported_by :all do
55
+ it 'is a no-op' do
56
+ is_expected.to equal(@state)
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#get' do
62
+ it_behaves_like 'Resource::PersistenceState::Persisted#get'
63
+ end
64
+
65
+ describe '#set' do
66
+ subject { @state.set(@key, @value) }
67
+
68
+ supported_by :all do
69
+ before do
70
+ @key = @model.properties[:name]
71
+ @value = @key.get!(@resource)
72
+ end
73
+
74
+ it 'raises an exception' do
75
+ expect { method(:subject) }.to raise_error(DataMapper::ImmutableDeletedError, 'Deleted resource cannot be modified')
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,163 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe DataMapper::Resource::PersistenceState::Dirty do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, HugeInteger, :key => true, :default => 1
9
+ property :name, String
10
+ property :active, Boolean, :default => true
11
+ property :coding, Boolean, :default => true
12
+
13
+ belongs_to :parent, self, :required => false
14
+ has n, :children, self, :inverse => :parent
15
+ end
16
+
17
+ DataMapper.finalize
18
+
19
+ @model = Author
20
+ end
21
+
22
+ before do
23
+ @parent = @model.create(:name => 'Jane Doe')
24
+
25
+ @resource = @model.create(:id => 2, :name => 'Dan Kubb', :parent => @parent)
26
+ @resource.attributes = { :name => 'John Doe' }
27
+
28
+ @state = @resource.persistence_state
29
+ expect(@state).to be_kind_of(DataMapper::Resource::PersistenceState::Dirty)
30
+ end
31
+
32
+ after do
33
+ @model.destroy!
34
+ end
35
+
36
+ describe '#commit' do
37
+ subject { @state.commit }
38
+
39
+ supported_by :all do
40
+ context 'with valid attributes' do
41
+ let(:state) { @state }
42
+
43
+ before do
44
+ @new_id = @resource.id = @resource.id.succ
45
+ end
46
+
47
+ it 'returns a Clean state' do
48
+ is_expected.to eql(DataMapper::Resource::PersistenceState::Clean.new(@resource))
49
+ end
50
+
51
+ it 'sets the child key if the parent key changes' do
52
+ original_id = @parent.id
53
+ expect { @parent.update(id: 42) }.to be(true)
54
+ expect { method(:subject) }.to change(@resource, :parent_id).from(original_id).to(42)
55
+ end
56
+
57
+ it 'updates the resource' do
58
+ subject
59
+ expect { @model.get!(*@resource.key) }.to eq @resource
60
+ end
61
+
62
+ it 'updates the resource to the identity map if the key changed' do
63
+ identity_map = @resource.repository.identity_map(@model)
64
+ expect(identity_map).to eq({ @resource.key => @resource })
65
+ subject
66
+ expect(identity_map).to eq({[@new_id] => @resource})
67
+ end
68
+ end
69
+
70
+ context 'with invalid attributes' do
71
+ before do
72
+ @resource.coding = 'invalid'
73
+ end
74
+
75
+ it 'raises InvalidValueError' do
76
+ expect { subject }.to(raise_error(DataMapper::Property::InvalidValueError) do |error|
77
+ expect(error.property).to eq Author.coding
78
+ end)
79
+ end
80
+
81
+ it 'does not change the identity map' do
82
+ identity_map = @resource.repository.identity_map(@model).dup
83
+ expect { subject }.to raise_error(DataMapper::Property::InvalidValueError)
84
+ expect(identity_map).to eq @resource.repository.identity_map(@model)
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#delete' do
91
+ subject { @state.delete }
92
+
93
+ supported_by :all do
94
+ before do
95
+ @resource.children = [ @resource.parent = @resource ]
96
+ end
97
+
98
+ it_behaves_like 'It resets resource state'
99
+
100
+ it 'returns a Deleted state' do
101
+ is_expected.to eql(DataMapper::Resource::PersistenceState::Deleted.new(@resource))
102
+ end
103
+ end
104
+ end
105
+
106
+ describe '#get' do
107
+ before do
108
+ @loaded_value = 'John Doe'
109
+ end
110
+
111
+ it_behaves_like 'Resource::PersistenceState::Persisted#get'
112
+ end
113
+
114
+ describe '#rollback' do
115
+ subject { @state.rollback }
116
+
117
+ supported_by :all do
118
+ before do
119
+ @resource.children = [ @resource.parent = @resource ]
120
+ end
121
+
122
+ it_behaves_like 'It resets resource state'
123
+
124
+ it 'returns a Clean state' do
125
+ is_expected.to eql(DataMapper::Resource::PersistenceState::Clean.new(@resource))
126
+ end
127
+ end
128
+ end
129
+
130
+ describe '#set' do
131
+ subject { @state.set(@key, @value) }
132
+
133
+ supported_by :all do
134
+ describe 'with attributes that keep the resource dirty' do
135
+ before do
136
+ @key = @model.properties[:id]
137
+ @value = @key.get!(@resource)
138
+ end
139
+
140
+ it_behaves_like 'A method that delegates to the superclass #set'
141
+
142
+ it 'returns a Dirty state' do
143
+ is_expected.to equal(@state)
144
+ end
145
+
146
+ its(:original_attributes) { is_expected.to eq({@model.properties[:name] => 'Dan Kubb'}) }
147
+ end
148
+
149
+ describe 'with attributes that make the resource clean' do
150
+ before do
151
+ @key = @model.properties[:name]
152
+ @value = 'Dan Kubb'
153
+ end
154
+
155
+ it_behaves_like 'A method that delegates to the superclass #set'
156
+
157
+ it 'returns a Clean state' do
158
+ is_expected.to eql(DataMapper::Resource::PersistenceState::Clean.new(@resource))
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,107 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe DataMapper::Resource::PersistenceState::Immutable do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, Serial
9
+ property :name, String
10
+ property :active, Boolean, :default => true
11
+ property :coding, Boolean, :default => true
12
+
13
+ belongs_to :parent, self, :required => false
14
+ end
15
+
16
+ DataMapper.finalize
17
+
18
+ @model = Author
19
+ end
20
+
21
+ before do
22
+ @parent = @model.create(:name => 'John Doe')
23
+
24
+ @resource = @model.create(:name => 'Dan Kubb', :parent => @parent)
25
+ attributes = Hash[ @model.key.zip(@resource.key) ]
26
+ @resource = @model.first(attributes.merge(:fields => [ :name, :parent_id ]))
27
+
28
+ @state = @resource.persistence_state
29
+
30
+ expect(@state).to be_kind_of(DataMapper::Resource::PersistenceState::Immutable)
31
+ end
32
+
33
+ after do
34
+ @model.destroy!
35
+ end
36
+
37
+ describe '#commit' do
38
+ subject { @state.commit }
39
+
40
+ supported_by :all do
41
+ it 'is a no-op' do
42
+ is_expected.to equal(@state)
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#delete' do
48
+ subject { @state.delete }
49
+
50
+ supported_by :all do
51
+ it 'raises an exception' do
52
+ expect { method(:subject) }.to raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be deleted')
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#get' do
58
+ subject { @state.get(@key) }
59
+
60
+ supported_by :all do
61
+ describe 'with an unloaded property' do
62
+ before do
63
+ @key = @model.properties[:id]
64
+ end
65
+
66
+ it 'raises an exception' do
67
+ expect { method(:subject) }.to raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be lazy loaded')
68
+ end
69
+ end
70
+
71
+ describe 'with an unloaded relationship' do
72
+ before do
73
+ @key = @model.relationships[:parent]
74
+ end
75
+
76
+ it 'returns value' do
77
+ is_expected.to eq @parent
78
+ end
79
+ end
80
+
81
+ describe 'with a loaded subject' do
82
+ before do
83
+ @key = @model.properties[:name]
84
+ end
85
+
86
+ it 'returns value' do
87
+ is_expected.to eq 'Dan Kubb'
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#set' do
94
+ before do
95
+ @key = @model.properties[:name]
96
+ @value = @key.get!(@resource)
97
+ end
98
+
99
+ subject { @state.set(@key, @value) }
100
+
101
+ supported_by :all do
102
+ it 'raises an exception' do
103
+ expect { method(:subject) }.to raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be modified')
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,163 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe DataMapper::Resource::PersistenceState::Transient do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, Serial
9
+ property :name, String
10
+ property :age, Integer
11
+ property :description, Text, :default => lambda { |resource, property| resource.name }
12
+ property :active, Boolean, :default => true
13
+ property :coding, Boolean, :default => true
14
+
15
+ belongs_to :parent, self, :required => false
16
+ has n, :children, self, :inverse => :parent
17
+
18
+ belongs_to :with_default, self, :required => false, :default => proc { first(:name => 'John Doe') }
19
+ end
20
+
21
+ DataMapper.finalize
22
+
23
+ @model = Author
24
+ end
25
+
26
+ before do
27
+ @parent = @model.create(:name => 'John Doe')
28
+ @resource = @model.new(:name => 'Dan Kubb', :coding => false, :parent => @parent)
29
+
30
+ @state = @resource.persistence_state
31
+ expect(@state).to be_kind_of(DataMapper::Resource::PersistenceState::Transient)
32
+ end
33
+
34
+ after do
35
+ @model.destroy!
36
+ end
37
+
38
+ describe '#commit' do
39
+ subject { @state.commit }
40
+
41
+ supported_by :all do
42
+ it 'Returns the expected Clean state' do
43
+ is_expected.to eql(DataMapper::Resource::PersistenceState::Clean.new(@resource))
44
+ end
45
+
46
+ it 'Sets the serial property' do
47
+ expect { method(:subject) }.to change(@resource, :id).from(nil)
48
+ end
49
+
50
+ it 'Sets the child key if the parent key changes' do
51
+ # SqlServer does not allow updating IDENTITY columns.
52
+ if defined?(DataMapper::Adapters::SqlserverAdapter) &&
53
+ @adapter.kind_of?(DataMapper::Adapters::SqlserverAdapter)
54
+ return
55
+ end
56
+
57
+ original_id = @parent.id
58
+ expect { @parent.update(id: 42) }.to be(true)
59
+ expect { method(:subject) }.to change(@resource, :parent_id).from(original_id).to(42)
60
+ end
61
+
62
+ it 'Sets the default values' do
63
+ expect { method(:subject) }.to change { @model.relationships[:with_default].get!(@resource) }.from(nil).to(@parent)
64
+ end
65
+
66
+ it "Doesn't set default values when they are already set" do
67
+ expect { method(:subject) }.not_to change(@resource, :coding)
68
+ end
69
+
70
+ it 'Creates the resource' do
71
+ subject
72
+ expect { @model.get(*@resource.key) }.to eq @resource
73
+ end
74
+
75
+ it 'resets original attributes' do
76
+ original_attributes = {
77
+ @model.properties[:name] => nil,
78
+ @model.properties[:coding] => nil,
79
+ @model.properties[:parent_id] => nil,
80
+ @model.relationships[:parent] => nil,
81
+ }
82
+
83
+ expect do
84
+ @resource.persistence_state = subject
85
+ end.to change { @resource.original_attributes.dup }.from(original_attributes).to({})
86
+ end
87
+
88
+ it 'adds the resource to the identity map' do
89
+ DataMapper.repository do |repository|
90
+ identity_map = repository.identity_map(@model)
91
+ expect(identity_map).to be_empty
92
+ subject
93
+ expect(identity_map).to eq({@parent.key => @parent, @resource.key => @resource})
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ [ :delete, :rollback ].each do |method|
100
+ describe "##{method}" do
101
+ subject { @state.send(method) }
102
+
103
+ supported_by :all do
104
+ it 'is a no-op' do
105
+ is_expected.to equal(@state)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ describe '#get' do
112
+ subject { @state.get(@key) }
113
+
114
+ supported_by :all do
115
+ describe 'with a set value' do
116
+ before do
117
+ @key = @model.properties[:coding]
118
+ expect(@key).to be_loaded(@resource)
119
+ end
120
+
121
+ it 'returns value' do
122
+ is_expected.to be(false)
123
+ end
124
+
125
+ it 'is idempotent' do
126
+ is_expected.to equal(subject)
127
+ end
128
+ end
129
+
130
+ describe 'with an unset value and no default value' do
131
+ before do
132
+ @key = @model.properties[:age]
133
+ expect(@key).not_to be_loaded(@resource)
134
+ expect(@key).not_to be_default
135
+ end
136
+
137
+ it 'returns nil' do
138
+ is_expected.to be_nil
139
+ end
140
+
141
+ it 'is idempotent' do
142
+ is_expected.to equal(subject)
143
+ end
144
+ end
145
+
146
+ describe 'with an unset value and a default value' do
147
+ before do
148
+ @key = @model.properties[:description]
149
+ expect(@key).not_to be_loaded(@resource)
150
+ expect(@key).to be_default
151
+ end
152
+
153
+ it 'Returns the name' do
154
+ is_expected.to eq 'Dan Kubb'
155
+ end
156
+
157
+ it 'Is idempotent' do
158
+ is_expected.to equal(subject)
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end