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,79 @@
1
+ module DataMapper
2
+ module Resource
3
+
4
+ # the state of the resource (abstract)
5
+ class State
6
+ attr_reader :resource
7
+
8
+ def initialize(resource)
9
+ @resource = resource
10
+ end
11
+
12
+ def get(subject, *args)
13
+ subject.get(resource, *args)
14
+ end
15
+
16
+ def set(subject, value)
17
+ subject.set(resource, value)
18
+ self
19
+ end
20
+
21
+ def delete
22
+ raise NotImplementedError, "#{self.class}#delete should be implemented"
23
+ end
24
+
25
+ def commit
26
+ raise NotImplementedError, "#{self.class}#commit should be implemented"
27
+ end
28
+
29
+ def rollback
30
+ raise NotImplementedError, "#{self.class}#rollback should be implemented"
31
+ end
32
+
33
+ def eql?(other)
34
+ instance_of?(other.class) &&
35
+ hash == other.hash
36
+ end
37
+
38
+ def ==(other)
39
+ self.class <=> other.class &&
40
+ hash == other.hash
41
+ end
42
+
43
+ def hash
44
+ resource.object_id.hash
45
+ end
46
+
47
+ private
48
+
49
+ def model
50
+ @model ||= resource.model
51
+ end
52
+
53
+ def properties
54
+ @properties ||= model.properties(repository.name)
55
+ end
56
+
57
+ def relationships
58
+ @relationships ||= model.relationships(repository.name).values
59
+ end
60
+
61
+ def identity_map
62
+ @identity_map ||= repository.identity_map(model)
63
+ end
64
+
65
+ def remove_from_identity_map
66
+ identity_map.delete(resource.key)
67
+ end
68
+
69
+ def add_to_identity_map
70
+ identity_map[resource.key] = resource
71
+ end
72
+
73
+ def reset_original_attributes
74
+ original_attributes.clear
75
+ end
76
+
77
+ end # class State
78
+ end # module Resource
79
+ end # module DataMapper
@@ -0,0 +1,40 @@
1
+ module DataMapper
2
+ module Resource
3
+ class State
4
+
5
+ # a persisted/unmodified resource
6
+ class Clean < Persisted
7
+ def set(subject, value)
8
+ if not_modified?(subject, value)
9
+ self
10
+ else
11
+ # assign to persisted_state so that if Dirty#set calls
12
+ # a Relationship#set, which modifies a Property, the same
13
+ # Dirty state instance will be reused.
14
+ state = resource.persisted_state = Dirty.new(resource)
15
+ state.set(subject, value)
16
+ end
17
+ end
18
+
19
+ def delete
20
+ Deleted.new(resource)
21
+ end
22
+
23
+ def commit
24
+ self
25
+ end
26
+
27
+ def rollback
28
+ self
29
+ end
30
+
31
+ private
32
+
33
+ def not_modified?(subject, value)
34
+ subject.loaded?(resource) && subject.get!(resource).eql?(value)
35
+ end
36
+
37
+ end # class Clean
38
+ end # class State
39
+ end # module Resource
40
+ end # module DataMapper
@@ -0,0 +1,30 @@
1
+ module DataMapper
2
+ module Resource
3
+ class State
4
+
5
+ # a persisted/deleted resource
6
+ class Deleted < Persisted
7
+ def set(subject, value)
8
+ raise ImmutableDeletedError, 'Deleted resource cannot be modified'
9
+ end
10
+
11
+ def delete
12
+ self
13
+ end
14
+
15
+ def commit
16
+ delete_resource
17
+ remove_from_identity_map
18
+ Immutable.new(resource)
19
+ end
20
+
21
+ private
22
+
23
+ def delete_resource
24
+ repository.delete(collection_for_self)
25
+ end
26
+
27
+ end # class Deleted
28
+ end # class State
29
+ end # module Resource
30
+ end # module DataMapper
@@ -0,0 +1,86 @@
1
+ module DataMapper
2
+ module Resource
3
+ class State
4
+
5
+ # a persisted/dirty resource
6
+ class Dirty < Persisted
7
+ def set(subject, value)
8
+ track(subject, value)
9
+ super
10
+ original_attributes.empty? ? Clean.new(resource) : self
11
+ end
12
+
13
+ def delete
14
+ reset_resource
15
+ Deleted.new(resource)
16
+ end
17
+
18
+ def commit
19
+ remove_from_identity_map
20
+ update_resource
21
+ reset_original_attributes
22
+ reset_resource_key
23
+ add_to_identity_map
24
+ Clean.new(resource)
25
+ end
26
+
27
+ def rollback
28
+ reset_resource
29
+ Clean.new(resource)
30
+ end
31
+
32
+ def original_attributes
33
+ @original_attributes ||= {}
34
+ end
35
+
36
+ private
37
+
38
+ def track(subject, value)
39
+ if original_attributes.key?(subject)
40
+ # stop tracking if the new value is the same as the original
41
+ if original_attributes[subject].eql?(value)
42
+ original_attributes.delete(subject)
43
+ end
44
+ else
45
+ # track the original value
46
+ original_attributes[subject] = get(subject)
47
+ end
48
+ end
49
+
50
+ def update_resource
51
+ repository.update(resource.dirty_attributes, collection_for_self)
52
+ end
53
+
54
+ def reset_resource
55
+ reset_resource_properties
56
+ reset_resource_relationships
57
+ end
58
+
59
+ def reset_resource_key
60
+ resource.instance_eval { remove_instance_variable(:@_key) }
61
+ end
62
+
63
+ def reset_resource_properties
64
+ # delete every original attribute after resetting the resource
65
+ original_attributes.delete_if do |property, value|
66
+ property.set!(resource, value)
67
+ true
68
+ end
69
+ end
70
+
71
+ def reset_resource_relationships
72
+ relationships.each do |relationship|
73
+ next unless relationship.loaded?(resource)
74
+ # TODO: consider a method in Relationship that can reset the relationship
75
+ resource.instance_eval { remove_instance_variable(relationship.instance_variable_name) }
76
+ end
77
+ end
78
+
79
+ def reset_original_attributes
80
+ original_attributes.clear
81
+ end
82
+
83
+ end # class Dirty
84
+ end # class State
85
+ end # module Resource
86
+ end # module DataMapper
@@ -0,0 +1,34 @@
1
+ module DataMapper
2
+ module Resource
3
+ class State
4
+
5
+ # a not-persisted/unmodifiable resource
6
+ class Immutable < State
7
+ def get(subject, *args)
8
+ unless subject.loaded?(resource) || subject.kind_of?(Associations::Relationship)
9
+ raise ImmutableError, 'Immutable resource cannot be lazy loaded'
10
+ end
11
+
12
+ super
13
+ end
14
+
15
+ def set(subject, value)
16
+ raise ImmutableError, 'Immutable resource cannot be modified'
17
+ end
18
+
19
+ def delete
20
+ raise ImmutableError, 'Immutable resource cannot be deleted'
21
+ end
22
+
23
+ def commit
24
+ self
25
+ end
26
+
27
+ def rollback
28
+ self
29
+ end
30
+
31
+ end # class Immutable
32
+ end # class State
33
+ end # module Resource
34
+ end # module DataMapper
@@ -0,0 +1,29 @@
1
+ module DataMapper
2
+ module Resource
3
+ class State
4
+
5
+ # a persisted resource (abstract)
6
+ class Persisted < State
7
+ def get(subject, *args)
8
+ lazy_load(subject)
9
+ super
10
+ end
11
+
12
+ private
13
+
14
+ def repository
15
+ @repository ||= resource.instance_variable_get(:@_repository)
16
+ end
17
+
18
+ def collection_for_self
19
+ @collection_for_self ||= resource.collection_for_self
20
+ end
21
+
22
+ def lazy_load(subject)
23
+ subject.lazy_load(resource)
24
+ end
25
+
26
+ end # class Persisted
27
+ end # class State
28
+ end # module Resource
29
+ end # module DataMapper
@@ -0,0 +1,70 @@
1
+ module DataMapper
2
+ module Resource
3
+ class State
4
+
5
+ # a not-persisted/modifiable resource
6
+ class Transient < State
7
+ def get(subject, *args)
8
+ set_default_value(subject)
9
+ super
10
+ end
11
+
12
+ def set(subject, value)
13
+ track(subject)
14
+ super
15
+ end
16
+
17
+ def delete
18
+ self
19
+ end
20
+
21
+ def commit
22
+ set_default_values
23
+ create_resource
24
+ set_repository
25
+ reset_original_attributes
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
39
+
40
+ def repository
41
+ @repository ||= model.repository
42
+ end
43
+
44
+ def set_default_values
45
+ (properties | relationships).each do |subject|
46
+ set_default_value(subject)
47
+ end
48
+ end
49
+
50
+ def set_default_value(subject)
51
+ return if subject.loaded?(resource) || !subject.default?
52
+ set(subject, subject.default_for(resource))
53
+ end
54
+
55
+ def track(subject)
56
+ original_attributes[subject] = nil
57
+ end
58
+
59
+ def create_resource
60
+ repository.create([ resource ])
61
+ end
62
+
63
+ def set_repository
64
+ resource.instance_variable_set(:@_repository, repository)
65
+ end
66
+
67
+ end # class Transient
68
+ end # class State
69
+ end # module Resource
70
+ end # module DataMapper
@@ -0,0 +1,52 @@
1
+ module DataMapper
2
+ module Spec
3
+ module Adapters
4
+
5
+ module Helpers
6
+
7
+ def supported_by(*adapters, &block)
8
+ adapters = adapters.map { |adapter| adapter.to_sym }
9
+ adapter = DataMapper::Spec.adapter_name.to_sym
10
+ if adapters.include?(:all) || adapters.include?(adapter)
11
+ describe_adapter(:default, &block)
12
+ end
13
+ end
14
+
15
+ def with_alternate_adapter(&block)
16
+ describe_adapter(:alternate, &block)
17
+ end
18
+
19
+ def describe_adapter(kind, &block)
20
+ describe("with #{kind} adapter") do
21
+
22
+ before :all do
23
+ # store these in instance vars for the shared adapter specs
24
+ @adapter = DataMapper::Spec.adapter(kind)
25
+ @repository = DataMapper.repository(@adapter.name)
26
+
27
+ # create all tables and constraints before each spec
28
+ if @repository.respond_to?(:auto_migrate!)
29
+ @repository.auto_migrate!
30
+ end
31
+ end
32
+
33
+ after :all do
34
+ # remove all tables and constraints after each spec
35
+ if @repository.respond_to?(:auto_migrate_down!, true)
36
+ @repository.send(:auto_migrate_down!, @repository.name)
37
+ end
38
+ # TODO consider proper automigrate functionality
39
+ if @adapter.respond_to?(:reset)
40
+ @adapter.reset
41
+ end
42
+ end
43
+
44
+ instance_eval(&block)
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ module DataMapper
2
+ module Spec
3
+ module CollectionHelpers
4
+ module GroupMethods
5
+ def self.extended(base)
6
+ base.class_inheritable_accessor :loaded
7
+ base.loaded = false
8
+ end
9
+
10
+ def should_not_be_a_kicker(ivar = :@articles)
11
+ unless loaded
12
+ it 'should not be a kicker' do
13
+ instance_variable_get(ivar).should_not be_loaded
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end