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,69 @@
1
+ module DataMapper
2
+ # A {SubjectSet} that keeps track of relationships defined in a {Model}
3
+ #
4
+ class RelationshipSet < SubjectSet
5
+ # A list of all relationships in this set
6
+ #
7
+ # @deprecated use DataMapper::RelationshipSet#each or DataMapper::RelationshipSet#to_a instead
8
+ #
9
+ # @return [Array]
10
+ # a list of all relationships in the set
11
+ #
12
+ # @api semipublic
13
+ def values
14
+ warn "#{self.class}#values is deprecated. Use #{self.class}#each or #{self.class}#to_a instead: #{caller.first}"
15
+ to_a
16
+ end
17
+
18
+ # A list of all relationships in this set
19
+ #
20
+ # @deprecated use DataMapper::RelationshipSet#each instead
21
+ #
22
+ # @yield [DataMapper::Associations::Relationship]
23
+ # all relationships in the set
24
+ #
25
+ # @yieldparam [DataMapper::Associations::Relationship] relationship
26
+ # a relationship in the set
27
+ #
28
+ # @return [RelationshipSet] self
29
+ #
30
+ # @api semipublic
31
+ def each_value(&block)
32
+ warn "#{self.class}#each_value is deprecated. Use #{self.class}#each instead: #{caller.first}"
33
+ each(&block)
34
+ self
35
+ end
36
+
37
+ # Check whether this RelationshipSet includes an entry with the given name
38
+ #
39
+ # @deprecated use DataMapper::RelationshipSet#named? instead
40
+ #
41
+ # @param [#to_s] name
42
+ # the name of the entry to look for
43
+ #
44
+ # @return [Boolean]
45
+ # true if the set contains a relationship with the given name
46
+ #
47
+ # @api semipublic
48
+ def key?(name)
49
+ warn "#{self.class}#key? is deprecated. Use #{self.class}#named? instead: #{caller.first}"
50
+ named?(name)
51
+ end
52
+
53
+ # Check whether this RelationshipSet includes an entry with the given name
54
+ #
55
+ # @deprecated use DataMapper::RelationshipSet#named? instead
56
+ #
57
+ # @param [#to_s] name
58
+ # the name of the entry to look for
59
+ #
60
+ # @return [Boolean]
61
+ # true if the set contains a relationship with the given name
62
+ #
63
+ # @api semipublic
64
+ def has_key?(name)
65
+ warn "#{self.class}#has_key? is deprecated. Use #{self.class}#named? instead: #{caller.first}"
66
+ named?(name)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,226 @@
1
+ module DataMapper
2
+ class Repository
3
+ include DataMapper::Assertions
4
+ extend Equalizer
5
+
6
+ equalize :name
7
+
8
+ # Get the list of adapters registered for all Repositories,
9
+ # keyed by repository name.
10
+ #
11
+ # TODO: create example
12
+ #
13
+ # @return [Hash(Symbol => Adapters::AbstractAdapter)]
14
+ # the adapters registered for all Repositories
15
+ #
16
+ # @api private
17
+ def self.adapters
18
+ @adapters ||= {}
19
+ end
20
+
21
+ # Get the stack of current repository contexts
22
+ #
23
+ # TODO: create example
24
+ #
25
+ # @return [Array]
26
+ # List of Repository contexts for the current Thread
27
+ #
28
+ # @api private
29
+ def self.context
30
+ Thread.current[:dm_repository_contexts] ||= []
31
+ end
32
+
33
+ # Get the default name of this Repository
34
+ #
35
+ # TODO: create example
36
+ #
37
+ # @return [Symbol]
38
+ # the default name of this repository
39
+ #
40
+ # @api private
41
+ def self.default_name
42
+ :default
43
+ end
44
+
45
+ # @api semipublic
46
+ attr_reader :name
47
+
48
+ # @api semipublic
49
+ alias_method :to_sym, :name
50
+
51
+ # Get the adapter for this repository
52
+ #
53
+ # Lazy loads adapter setup from registered adapters
54
+ #
55
+ # TODO: create example
56
+ #
57
+ # @return [Adapters::AbstractAdapter]
58
+ # the adapter for this repository
59
+ #
60
+ # @raise [RepositoryNotSetupError]
61
+ # if there is no adapter registered for a repository named @name
62
+ #
63
+ # @api semipublic
64
+ def adapter
65
+ # Make adapter instantiation lazy so we can defer repository setup until it's actually
66
+ # needed. Do not remove this code.
67
+ @adapter ||=
68
+ begin
69
+ adapters = self.class.adapters
70
+
71
+ raise RepositoryNotSetupError, "Adapter not set: #{@name}. Did you forget to setup?" unless adapters.key?(@name)
72
+
73
+ adapters[@name]
74
+ end
75
+ end
76
+
77
+ # Get the identity for a particular model within this repository.
78
+ #
79
+ # If one doesn't yet exist, create a new default in-memory IdentityMap
80
+ # for the requested model.
81
+ #
82
+ # TODO: create example
83
+ #
84
+ # @param [Model] model
85
+ # Model whose identity map should be returned
86
+ #
87
+ # @return [IdentityMap]
88
+ # The IdentityMap for model in this Repository
89
+ #
90
+ # @api private
91
+ def identity_map(model)
92
+ @identity_maps[model.base_model] ||= IdentityMap.new
93
+ end
94
+
95
+ # Executes a block in the scope of this Repository
96
+ #
97
+ # TODO: create example
98
+ #
99
+ # @yieldparam [Repository] repository
100
+ # yields self within the block
101
+ #
102
+ # @yield
103
+ # execute block in the scope of this Repository
104
+ #
105
+ # @api private
106
+ def scope
107
+ context = Repository.context
108
+
109
+ context << self
110
+
111
+ begin
112
+ yield self
113
+ ensure
114
+ context.pop
115
+ end
116
+ end
117
+
118
+ # Create a Query or subclass instance for this repository.
119
+ #
120
+ # @param [Model] model
121
+ # the Model to retrieve results from
122
+ # @param [Hash] options
123
+ # the conditions and scope
124
+ #
125
+ # @return [Query]
126
+ #
127
+ # @api semipublic
128
+ def new_query(model, options = {})
129
+ adapter.new_query(self, model, options)
130
+ end
131
+
132
+ # Create one or more resource instances in this repository.
133
+ #
134
+ # TODO: create example
135
+ #
136
+ # @param [Enumerable(Resource)] resources
137
+ # The list of resources (model instances) to create
138
+ #
139
+ # @return [Integer]
140
+ # The number of records that were actually saved into the data-store
141
+ #
142
+ # @api semipublic
143
+ def create(resources)
144
+ adapter.create(resources)
145
+ end
146
+
147
+ # Retrieve a collection of results of a query
148
+ #
149
+ # TODO: create example
150
+ #
151
+ # @param [Query] query
152
+ # composition of the query to perform
153
+ #
154
+ # @return [Mixed]
155
+ # [DataMapper::Resource] result set of the query
156
+ # [Array]
157
+ #
158
+ # @api semipublic
159
+ def read(query)
160
+ return [] unless query.valid?
161
+
162
+ query.model.load(adapter.read(query), query)
163
+ end
164
+
165
+ # Update the attributes of one or more resource instances
166
+ #
167
+ # TODO: create example
168
+ #
169
+ # @param [Hash(Property => Object)] attributes
170
+ # hash of attribute values to set, keyed by Property
171
+ # @param [Collection] collection
172
+ # collection of records to be updated
173
+ #
174
+ # @return [Integer]
175
+ # the number of records updated
176
+ #
177
+ # @api semipublic
178
+ def update(attributes, collection)
179
+ return 0 unless collection.query.valid? && attributes.any?
180
+
181
+ adapter.update(attributes, collection)
182
+ end
183
+
184
+ # Delete one or more resource instances
185
+ #
186
+ # TODO: create example
187
+ #
188
+ # @param [Collection] collection
189
+ # collection of records to be deleted
190
+ #
191
+ # @return [Integer]
192
+ # the number of records deleted
193
+ #
194
+ # @api semipublic
195
+ def delete(collection)
196
+ return 0 unless collection.query.valid?
197
+
198
+ adapter.delete(collection)
199
+ end
200
+
201
+ # Return a human readable representation of the repository
202
+ #
203
+ # TODO: create example
204
+ #
205
+ # @return [String]
206
+ # human readable representation of the repository
207
+ #
208
+ # @api private
209
+ def inspect
210
+ "#<#{self.class.name} @name=#{@name}>"
211
+ end
212
+
213
+ # Initializes a new Repository
214
+ #
215
+ # TODO: create example
216
+ #
217
+ # @param [Symbol] name
218
+ # The name of the Repository
219
+ #
220
+ # @api semipublic
221
+ private def initialize(name)
222
+ @name = name.to_sym
223
+ @identity_maps = {}
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,36 @@
1
+ module DataMapper
2
+ module Resource
3
+ class PersistenceState
4
+ # a persisted/unmodified resource
5
+ class Clean < Persisted
6
+ def set(subject, value)
7
+ if not_modified?(subject, value)
8
+ self
9
+ else
10
+ # assign to persistence_state so that if Dirty#set calls
11
+ # a Relationship#set, which modifies a Property, the same
12
+ # Dirty state instance will be reused.
13
+ state = resource.persistence_state = Dirty.new(resource)
14
+ state.set(subject, value)
15
+ end
16
+ end
17
+
18
+ def delete
19
+ Deleted.new(resource)
20
+ end
21
+
22
+ def commit
23
+ self
24
+ end
25
+
26
+ def rollback
27
+ self
28
+ end
29
+
30
+ private def not_modified?(subject, value)
31
+ subject.loaded?(resource) && subject.get!(resource).eql?(value)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,26 @@
1
+ module DataMapper
2
+ module Resource
3
+ class PersistenceState
4
+ # a persisted/deleted resource
5
+ class Deleted < Persisted
6
+ def set(_subject, _value)
7
+ raise ImmutableDeletedError, 'Deleted resource cannot be modified'
8
+ end
9
+
10
+ def delete
11
+ self
12
+ end
13
+
14
+ def commit
15
+ delete_resource
16
+ remove_from_identity_map
17
+ Immutable.new(resource)
18
+ end
19
+
20
+ private def delete_resource
21
+ repository.delete(collection_for_self)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,91 @@
1
+ module DataMapper
2
+ module Resource
3
+ class PersistenceState
4
+ # a persisted/dirty resource
5
+ class Dirty < Persisted
6
+ def set(subject, value)
7
+ track(subject, value)
8
+ super
9
+ original_attributes.empty? ? Clean.new(resource) : self
10
+ end
11
+
12
+ def delete
13
+ reset_resource
14
+ Deleted.new(resource)
15
+ end
16
+
17
+ def commit
18
+ remove_from_identity_map
19
+ set_child_keys
20
+ assert_valid_attributes
21
+ update_resource
22
+ reset_original_attributes
23
+ reset_resource_key
24
+ Clean.new(resource)
25
+ ensure
26
+ add_to_identity_map
27
+ end
28
+
29
+ def rollback
30
+ reset_resource
31
+ Clean.new(resource)
32
+ end
33
+
34
+ def original_attributes
35
+ @original_attributes ||= {}
36
+ end
37
+
38
+ private def track(subject, value)
39
+ if original_attributes.key?(subject)
40
+ # stop tracking if the new value is the same as the original
41
+ original_attributes.delete(subject) if original_attributes[subject].eql?(value)
42
+ elsif !value.eql?((original = get(subject)))
43
+ # track the original value
44
+ original_attributes[subject] = original
45
+ end
46
+ end
47
+
48
+ private def update_resource
49
+ repository.update(resource.dirty_attributes, collection_for_self)
50
+ end
51
+
52
+ private def reset_resource
53
+ reset_resource_properties
54
+ reset_resource_relationships
55
+ end
56
+
57
+ private def reset_resource_key
58
+ resource.instance_eval { remove_instance_variable(:@_key) }
59
+ end
60
+
61
+ private def reset_resource_properties
62
+ # delete every original attribute after resetting the resource
63
+ original_attributes.delete_if do |property, value|
64
+ property.set!(resource, value)
65
+ true
66
+ end
67
+ end
68
+
69
+ private def reset_resource_relationships
70
+ relationships.each do |relationship|
71
+ next unless relationship.loaded?(resource)
72
+
73
+ # TODO: consider a method in Relationship that can reset the relationship
74
+ resource.instance_eval { remove_instance_variable(relationship.instance_variable_name) }
75
+ end
76
+ end
77
+
78
+ private def reset_original_attributes
79
+ original_attributes.clear
80
+ end
81
+
82
+ private def assert_valid_attributes
83
+ properties.each do |property|
84
+ value = property.get! resource
85
+ property.assert_valid_value(value)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,32 @@
1
+ module DataMapper
2
+ module Resource
3
+ class PersistenceState
4
+ # a not-persisted/unmodifiable resource
5
+ class Immutable < PersistenceState
6
+ def get(subject, *args)
7
+ unless subject.loaded?(resource) || subject.is_a?(Associations::Relationship)
8
+ raise ImmutableError, 'Immutable resource cannot be lazy loaded'
9
+ end
10
+
11
+ super
12
+ end
13
+
14
+ def set(_subject, _value)
15
+ raise ImmutableError, 'Immutable resource cannot be modified'
16
+ end
17
+
18
+ def delete
19
+ raise ImmutableError, 'Immutable resource cannot be deleted'
20
+ end
21
+
22
+ def commit
23
+ self
24
+ end
25
+
26
+ def rollback
27
+ self
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ module DataMapper
2
+ module Resource
3
+ class PersistenceState
4
+ # a persisted resource (abstract)
5
+ class Persisted < PersistenceState
6
+ def get(subject, *args)
7
+ lazy_load(subject)
8
+ super
9
+ end
10
+
11
+ private def repository
12
+ @repository ||= resource.instance_variable_get(:@_repository)
13
+ end
14
+
15
+ private def collection_for_self
16
+ @collection_for_self ||= resource.collection_for_self
17
+ end
18
+
19
+ private def lazy_load(subject)
20
+ subject.lazy_load(resource)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,87 @@
1
+ module DataMapper
2
+ module Resource
3
+ class PersistenceState
4
+ # a not-persisted/modifiable resource
5
+ class Transient < PersistenceState
6
+ def get(subject, *args)
7
+ set_default_value(subject)
8
+ super
9
+ end
10
+
11
+ def set(subject, value)
12
+ track(subject)
13
+ super
14
+ end
15
+
16
+ def delete
17
+ self
18
+ end
19
+
20
+ def commit
21
+ set_child_keys
22
+ set_default_values
23
+ assert_valid_attributes
24
+ create_resource
25
+ set_repository
26
+ add_to_identity_map
27
+ Clean.new(resource)
28
+ end
29
+
30
+ def rollback
31
+ self
32
+ end
33
+
34
+ def original_attributes
35
+ @original_attributes ||= {}
36
+ end
37
+
38
+ private def repository
39
+ @repository ||= model.repository
40
+ end
41
+
42
+ private def set_default_values
43
+ (properties | relationships).each do |subject|
44
+ set_default_value(subject)
45
+ end
46
+ end
47
+
48
+ private def set_default_value(subject)
49
+ return if subject.loaded?(resource) || !subject.default?
50
+
51
+ default = typecast_default(subject, subject.default_for(resource))
52
+ set(subject, default)
53
+ end
54
+
55
+ private def typecast_default(subject, default)
56
+ return default unless subject.respond_to?(:typecast)
57
+
58
+ typecasted_default = subject.send(:typecast, default)
59
+ unless typecasted_default.eql?(default)
60
+ warn "Automatic typecasting of default property values is deprecated (#{default.inspect} was casted to #{typecasted_default.inspect}). " \
61
+ "Specify the correct type for #{resource.class}."
62
+ end
63
+ typecasted_default
64
+ end
65
+
66
+ private def track(subject)
67
+ original_attributes[subject] = nil
68
+ end
69
+
70
+ private def create_resource
71
+ repository.create([resource])
72
+ end
73
+
74
+ private def set_repository
75
+ resource.instance_variable_set(:@_repository, repository)
76
+ end
77
+
78
+ private def assert_valid_attributes
79
+ properties.each do |property|
80
+ value = get(property)
81
+ property.assert_valid_value(value) unless property.serial? && value.nil?
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,70 @@
1
+ module DataMapper
2
+ module Resource
3
+ # the state of the resource (abstract)
4
+ class PersistenceState
5
+ extend Equalizer
6
+
7
+ equalize :resource
8
+
9
+ attr_reader :resource, :model
10
+
11
+ def initialize(resource)
12
+ @resource = resource
13
+ @model = resource.model
14
+ end
15
+
16
+ def get(subject, *args)
17
+ subject.get(resource, *args)
18
+ end
19
+
20
+ def set(subject, value)
21
+ subject.set(resource, value)
22
+ self
23
+ end
24
+
25
+ def delete
26
+ raise NotImplementedError, "#{self.class}#delete should be implemented"
27
+ end
28
+
29
+ def commit
30
+ raise NotImplementedError, "#{self.class}#commit should be implemented"
31
+ end
32
+
33
+ def rollback
34
+ raise NotImplementedError, "#{self.class}#rollback should be implemented"
35
+ end
36
+
37
+ private def properties
38
+ @properties ||= model.properties(repository&.name)
39
+ end
40
+
41
+ private def relationships
42
+ @relationships ||= model.relationships(repository&.name)
43
+ end
44
+
45
+ private def identity_map
46
+ @identity_map ||= repository&.identity_map(model)
47
+ end
48
+
49
+ private def remove_from_identity_map
50
+ identity_map.delete(resource.key)
51
+ end
52
+
53
+ private def add_to_identity_map
54
+ identity_map[resource.key] = resource
55
+ end
56
+
57
+ private def set_child_keys
58
+ relationships.each do |relationship|
59
+ set_child_key(relationship)
60
+ end
61
+ end
62
+
63
+ private def set_child_key(relationship)
64
+ return unless relationship.loaded?(resource) && relationship.respond_to?(:resource_for)
65
+
66
+ set(relationship, get(relationship))
67
+ end
68
+ end
69
+ end
70
+ end