dm-core 0.9.11 → 0.10.0

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 (194) hide show
  1. data/.autotest +17 -14
  2. data/.gitignore +3 -1
  3. data/FAQ +6 -5
  4. data/History.txt +5 -50
  5. data/Manifest.txt +66 -76
  6. data/QUICKLINKS +1 -1
  7. data/README.txt +21 -15
  8. data/Rakefile +6 -7
  9. data/SPECS +2 -29
  10. data/TODO +1 -1
  11. data/deps.rip +2 -0
  12. data/dm-core.gemspec +11 -15
  13. data/lib/dm-core.rb +105 -110
  14. data/lib/dm-core/adapters.rb +135 -16
  15. data/lib/dm-core/adapters/abstract_adapter.rb +251 -181
  16. data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
  17. data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
  18. data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
  19. data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
  20. data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
  21. data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
  22. data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
  23. data/lib/dm-core/associations/many_to_many.rb +372 -90
  24. data/lib/dm-core/associations/many_to_one.rb +220 -73
  25. data/lib/dm-core/associations/one_to_many.rb +319 -255
  26. data/lib/dm-core/associations/one_to_one.rb +66 -53
  27. data/lib/dm-core/associations/relationship.rb +561 -156
  28. data/lib/dm-core/collection.rb +1101 -379
  29. data/lib/dm-core/core_ext/kernel.rb +12 -0
  30. data/lib/dm-core/core_ext/symbol.rb +10 -0
  31. data/lib/dm-core/identity_map.rb +4 -34
  32. data/lib/dm-core/migrations.rb +1283 -0
  33. data/lib/dm-core/model.rb +570 -369
  34. data/lib/dm-core/model/descendant_set.rb +81 -0
  35. data/lib/dm-core/model/hook.rb +45 -0
  36. data/lib/dm-core/model/is.rb +32 -0
  37. data/lib/dm-core/model/property.rb +247 -0
  38. data/lib/dm-core/model/relationship.rb +335 -0
  39. data/lib/dm-core/model/scope.rb +90 -0
  40. data/lib/dm-core/property.rb +808 -273
  41. data/lib/dm-core/property_set.rb +141 -98
  42. data/lib/dm-core/query.rb +1037 -483
  43. data/lib/dm-core/query/conditions/comparison.rb +872 -0
  44. data/lib/dm-core/query/conditions/operation.rb +221 -0
  45. data/lib/dm-core/query/direction.rb +43 -0
  46. data/lib/dm-core/query/operator.rb +84 -0
  47. data/lib/dm-core/query/path.rb +138 -0
  48. data/lib/dm-core/query/sort.rb +45 -0
  49. data/lib/dm-core/repository.rb +210 -94
  50. data/lib/dm-core/resource.rb +641 -421
  51. data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
  52. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
  53. data/lib/dm-core/support/chainable.rb +22 -0
  54. data/lib/dm-core/support/deprecate.rb +12 -0
  55. data/lib/dm-core/support/logger.rb +13 -0
  56. data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
  57. data/lib/dm-core/transaction.rb +333 -92
  58. data/lib/dm-core/type.rb +98 -60
  59. data/lib/dm-core/types/boolean.rb +1 -1
  60. data/lib/dm-core/types/discriminator.rb +34 -20
  61. data/lib/dm-core/types/object.rb +7 -4
  62. data/lib/dm-core/types/paranoid_boolean.rb +11 -9
  63. data/lib/dm-core/types/paranoid_datetime.rb +11 -9
  64. data/lib/dm-core/types/serial.rb +3 -3
  65. data/lib/dm-core/types/text.rb +3 -4
  66. data/lib/dm-core/version.rb +1 -1
  67. data/script/performance.rb +102 -109
  68. data/script/profile.rb +169 -38
  69. data/spec/lib/adapter_helpers.rb +105 -0
  70. data/spec/lib/collection_helpers.rb +18 -0
  71. data/spec/lib/counter_adapter.rb +34 -0
  72. data/spec/lib/pending_helpers.rb +27 -0
  73. data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
  74. data/spec/public/associations/many_to_many_spec.rb +193 -0
  75. data/spec/public/associations/many_to_one_spec.rb +73 -0
  76. data/spec/public/associations/one_to_many_spec.rb +77 -0
  77. data/spec/public/associations/one_to_one_spec.rb +156 -0
  78. data/spec/public/collection_spec.rb +65 -0
  79. data/spec/public/migrations_spec.rb +359 -0
  80. data/spec/public/model/relationship_spec.rb +924 -0
  81. data/spec/public/model_spec.rb +159 -0
  82. data/spec/public/property_spec.rb +829 -0
  83. data/spec/public/resource_spec.rb +71 -0
  84. data/spec/public/sel_spec.rb +44 -0
  85. data/spec/public/setup_spec.rb +145 -0
  86. data/spec/public/shared/association_collection_shared_spec.rb +317 -0
  87. data/spec/public/shared/collection_shared_spec.rb +1670 -0
  88. data/spec/public/shared/finder_shared_spec.rb +1619 -0
  89. data/spec/public/shared/resource_shared_spec.rb +924 -0
  90. data/spec/public/shared/sel_shared_spec.rb +112 -0
  91. data/spec/public/transaction_spec.rb +129 -0
  92. data/spec/public/types/discriminator_spec.rb +130 -0
  93. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  94. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  95. data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
  96. data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
  97. data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
  98. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
  99. data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
  100. data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
  101. data/spec/semipublic/associations/relationship_spec.rb +194 -0
  102. data/spec/semipublic/associations_spec.rb +177 -0
  103. data/spec/semipublic/collection_spec.rb +142 -0
  104. data/spec/semipublic/property_spec.rb +61 -0
  105. data/spec/semipublic/query/conditions_spec.rb +528 -0
  106. data/spec/semipublic/query/path_spec.rb +443 -0
  107. data/spec/semipublic/query_spec.rb +2626 -0
  108. data/spec/semipublic/resource_spec.rb +47 -0
  109. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  110. data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
  111. data/spec/spec.opts +3 -1
  112. data/spec/spec_helper.rb +80 -57
  113. data/tasks/ci.rb +19 -31
  114. data/tasks/dm.rb +43 -48
  115. data/tasks/doc.rb +8 -11
  116. data/tasks/gemspec.rb +5 -5
  117. data/tasks/hoe.rb +15 -16
  118. data/tasks/install.rb +8 -10
  119. metadata +74 -111
  120. data/lib/dm-core/associations.rb +0 -207
  121. data/lib/dm-core/associations/relationship_chain.rb +0 -81
  122. data/lib/dm-core/auto_migrations.rb +0 -105
  123. data/lib/dm-core/dependency_queue.rb +0 -32
  124. data/lib/dm-core/hook.rb +0 -11
  125. data/lib/dm-core/is.rb +0 -16
  126. data/lib/dm-core/logger.rb +0 -232
  127. data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
  128. data/lib/dm-core/migrator.rb +0 -29
  129. data/lib/dm-core/scope.rb +0 -58
  130. data/lib/dm-core/support.rb +0 -7
  131. data/lib/dm-core/support/array.rb +0 -13
  132. data/lib/dm-core/support/assertions.rb +0 -8
  133. data/lib/dm-core/support/errors.rb +0 -23
  134. data/lib/dm-core/support/kernel.rb +0 -11
  135. data/lib/dm-core/support/symbol.rb +0 -41
  136. data/lib/dm-core/type_map.rb +0 -80
  137. data/lib/dm-core/types.rb +0 -19
  138. data/script/all +0 -4
  139. data/spec/integration/association_spec.rb +0 -1382
  140. data/spec/integration/association_through_spec.rb +0 -203
  141. data/spec/integration/associations/many_to_many_spec.rb +0 -449
  142. data/spec/integration/associations/many_to_one_spec.rb +0 -163
  143. data/spec/integration/associations/one_to_many_spec.rb +0 -188
  144. data/spec/integration/auto_migrations_spec.rb +0 -413
  145. data/spec/integration/collection_spec.rb +0 -1073
  146. data/spec/integration/data_objects_adapter_spec.rb +0 -32
  147. data/spec/integration/dependency_queue_spec.rb +0 -46
  148. data/spec/integration/model_spec.rb +0 -197
  149. data/spec/integration/mysql_adapter_spec.rb +0 -85
  150. data/spec/integration/postgres_adapter_spec.rb +0 -731
  151. data/spec/integration/property_spec.rb +0 -253
  152. data/spec/integration/query_spec.rb +0 -514
  153. data/spec/integration/repository_spec.rb +0 -61
  154. data/spec/integration/resource_spec.rb +0 -513
  155. data/spec/integration/sqlite3_adapter_spec.rb +0 -352
  156. data/spec/integration/sti_spec.rb +0 -273
  157. data/spec/integration/strategic_eager_loading_spec.rb +0 -156
  158. data/spec/integration/transaction_spec.rb +0 -75
  159. data/spec/integration/type_spec.rb +0 -275
  160. data/spec/lib/logging_helper.rb +0 -18
  161. data/spec/lib/mock_adapter.rb +0 -27
  162. data/spec/lib/model_loader.rb +0 -100
  163. data/spec/lib/publicize_methods.rb +0 -28
  164. data/spec/models/content.rb +0 -16
  165. data/spec/models/vehicles.rb +0 -34
  166. data/spec/models/zoo.rb +0 -48
  167. data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
  168. data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
  169. data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
  170. data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
  171. data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
  172. data/spec/unit/associations/many_to_many_spec.rb +0 -32
  173. data/spec/unit/associations/many_to_one_spec.rb +0 -159
  174. data/spec/unit/associations/one_to_many_spec.rb +0 -393
  175. data/spec/unit/associations/one_to_one_spec.rb +0 -7
  176. data/spec/unit/associations/relationship_spec.rb +0 -71
  177. data/spec/unit/associations_spec.rb +0 -242
  178. data/spec/unit/auto_migrations_spec.rb +0 -111
  179. data/spec/unit/collection_spec.rb +0 -182
  180. data/spec/unit/data_mapper_spec.rb +0 -35
  181. data/spec/unit/identity_map_spec.rb +0 -126
  182. data/spec/unit/is_spec.rb +0 -80
  183. data/spec/unit/migrator_spec.rb +0 -33
  184. data/spec/unit/model_spec.rb +0 -321
  185. data/spec/unit/naming_conventions_spec.rb +0 -36
  186. data/spec/unit/property_set_spec.rb +0 -90
  187. data/spec/unit/property_spec.rb +0 -753
  188. data/spec/unit/query_spec.rb +0 -571
  189. data/spec/unit/repository_spec.rb +0 -93
  190. data/spec/unit/resource_spec.rb +0 -649
  191. data/spec/unit/scope_spec.rb +0 -142
  192. data/spec/unit/transaction_spec.rb +0 -493
  193. data/spec/unit/type_map_spec.rb +0 -114
  194. data/spec/unit/type_spec.rb +0 -119
@@ -1,209 +1,279 @@
1
1
  module DataMapper
2
2
  module Adapters
3
+ # Specific adapters extend this class and implement
4
+ # methods for creating, reading, updating and deleting records.
5
+ #
6
+ # Adapters may only implement method for reading or (less common case)
7
+ # writing. Read only adapter may be useful when one needs to work
8
+ # with legacy data that should not be changed or web services that
9
+ # only provide read access to data (from Wordnet and Medline to
10
+ # Atom and RSS syndication feeds)
11
+ #
12
+ # Note that in case of adapters to relational databases it makes
13
+ # sense to inherit from DataObjectsAdapter class.
3
14
  class AbstractAdapter
4
- include Assertions
5
-
6
- attr_reader :name, :uri
7
- attr_accessor :resource_naming_convention, :field_naming_convention
8
-
15
+ include Extlib::Assertions
16
+ extend Extlib::Assertions
17
+
18
+ # Adapter name
19
+ #
20
+ # @example
21
+ # adapter.name # => :default
22
+ #
23
+ # Note that when you use
24
+ #
25
+ # DataMapper.setup(:default, 'postgres://postgres@localhost/dm_core_test')
26
+ #
27
+ # then adapter name is currently be set to is :default
28
+ #
29
+ # @return [Symbol]
30
+ # the adapter name
31
+ #
32
+ # @api semipublic
33
+ attr_reader :name
34
+
35
+ # Options with which adapter was set up
36
+ #
37
+ # @example
38
+ # adapter.options # => { :adapter => 'yaml', :path => '/tmp' }
39
+ #
40
+ # @return [Hash]
41
+ # adapter configuration options
42
+ #
43
+ # @api semipublic
44
+ attr_reader :options
45
+
46
+ # A callable object returning a naming convention for model storage
47
+ #
48
+ # @example
49
+ # adapter.resource_naming_convention # => Proc for model storage name
50
+ #
51
+ # @return [#call]
52
+ # object to return the naming convention for each model
53
+ #
54
+ # @api semipublic
55
+ attr_accessor :resource_naming_convention
56
+
57
+ # A callable object returning a naming convention for property fields
58
+ #
59
+ # @example
60
+ # adapter.field_naming_convention # => Proc for field name
61
+ #
62
+ # @return [#call]
63
+ # object to return the naming convention for each field
64
+ #
65
+ # @api semipublic
66
+ attr_accessor :field_naming_convention
67
+
68
+ # Persists one or many new resources
69
+ #
70
+ # @example
71
+ # adapter.create(collection) # => 1
72
+ #
73
+ # Adapters provide specific implementation of this method
74
+ #
75
+ # @param [Enumerable<Resource>] resources
76
+ # The list of resources (model instances) to create
77
+ #
78
+ # @return [Integer]
79
+ # The number of records that were actually saved into the data-store
80
+ #
81
+ # @api semipublic
9
82
  def create(resources)
10
- raise NotImplementedError
11
- end
12
-
13
- def read_many(query)
14
- raise NotImplementedError
15
- end
16
-
17
- def read_one(query)
18
- raise NotImplementedError
83
+ raise NotImplementedError, "#{self.class}#create not implemented"
19
84
  end
20
85
 
21
- def update(attributes, query)
22
- raise NotImplementedError
86
+ # Reads one or many resources from a datastore
87
+ #
88
+ # @example
89
+ # adapter.read(query) # => [ { 'name' => 'Dan Kubb' } ]
90
+ #
91
+ # Adapters provide specific implementation of this method
92
+ #
93
+ # @param [Query] query
94
+ # the query to match resources in the datastore
95
+ #
96
+ # @return [Enumerable<Hash>]
97
+ # an array of hashes to become resources
98
+ #
99
+ # @api semipublic
100
+ def read(query)
101
+ raise NotImplementedError, "#{self.class}#read not implemented"
23
102
  end
24
103
 
25
- def delete(query)
26
- raise NotImplementedError
104
+ # Updates one or many existing resources
105
+ #
106
+ # @example
107
+ # adapter.update(attributes, collection) # => 1
108
+ #
109
+ # Adapters provide specific implementation of this method
110
+ #
111
+ # @param [Hash(Property => Object)] attributes
112
+ # hash of attribute values to set, keyed by Property
113
+ # @param [Collection] collection
114
+ # collection of records to be updated
115
+ #
116
+ # @return [Integer]
117
+ # the number of records updated
118
+ #
119
+ # @api semipublic
120
+ def update(attributes, collection)
121
+ raise NotImplementedError, "#{self.class}#update not implemented"
27
122
  end
28
123
 
29
- protected
30
-
31
- def normalize_uri(uri_or_options)
32
- uri_or_options
33
- end
34
-
35
- private
36
-
37
- # Instantiate an Adapter by passing it a DataMapper::Repository
38
- # connection string for configuration.
39
- def initialize(name, uri_or_options)
40
- assert_kind_of 'name', name, Symbol
41
- assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, DataObjects::URI, Hash, String
42
-
43
- @name = name
44
- @uri = normalize_uri(uri_or_options)
45
-
46
- @resource_naming_convention = NamingConventions::Resource::UnderscoredAndPluralized
47
- @field_naming_convention = NamingConventions::Field::Underscored
48
-
49
- @transactions = {}
124
+ # Deletes one or many existing resources
125
+ #
126
+ # @example
127
+ # adapter.delete(collection) # => 1
128
+ #
129
+ # Adapters provide specific implementation of this method
130
+ #
131
+ # @param [Collection] collection
132
+ # collection of records to be deleted
133
+ #
134
+ # @return [Integer]
135
+ # the number of records deleted
136
+ #
137
+ # @api semipublic
138
+ def delete(collection)
139
+ raise NotImplementedError, "#{self.class}#delete not implemented"
50
140
  end
51
141
 
52
- # TODO: move to dm-more/dm-migrations
53
- module Migration
54
- #
55
- # Returns whether the storage_name exists.
56
- #
57
- # @param storage_name<String> a String defining the name of a storage,
58
- # for example a table name.
59
- #
60
- # @return <Boolean> true if the storage exists
61
- #
62
- # TODO: move to dm-more/dm-migrations (if possible)
63
- def storage_exists?(storage_name)
64
- raise NotImplementedError
65
- end
66
-
67
- #
68
- # Returns whether the field exists.
69
- #
70
- # @param storage_name<String> a String defining the name of a storage, for example a table name.
71
- # @param field_name<String> a String defining the name of a field, for example a column name.
72
- #
73
- # @return <Boolean> true if the field exists.
74
- #
75
- # TODO: move to dm-more/dm-migrations (if possible)
76
- def field_exists?(storage_name, field_name)
77
- raise NotImplementedError
78
- end
79
-
80
- # TODO: move to dm-more/dm-migrations
81
- def upgrade_model_storage(repository, model)
82
- raise NotImplementedError
83
- end
84
-
85
- # TODO: move to dm-more/dm-migrations
86
- def create_model_storage(repository, model)
87
- raise NotImplementedError
88
- end
89
-
90
- # TODO: move to dm-more/dm-migrations
91
- def destroy_model_storage(repository, model)
92
- raise NotImplementedError
93
- end
94
-
95
- # TODO: move to dm-more/dm-migrations
96
- def alter_model_storage(repository, *args)
97
- raise NotImplementedError
98
- end
99
-
100
- # TODO: move to dm-more/dm-migrations
101
- def create_property_storage(repository, property)
102
- raise NotImplementedError
103
- end
104
-
105
- # TODO: move to dm-more/dm-migrations
106
- def destroy_property_storage(repository, property)
107
- raise NotImplementedError
142
+ # Compares another AbstractAdapter for equality
143
+ #
144
+ # @example with an equal adapter
145
+ # adapter.eql?(equal_adapter) # => true
146
+ #
147
+ # @example with a different adapter
148
+ # adapter.eql?(different_adapter) # => false
149
+ #
150
+ # AbstractAdapter is equal to +other+ if they are the same object (identity)
151
+ # or if they are of the same class and have the same name
152
+ #
153
+ # @param [AbstractAdapter] other
154
+ # the other AbstractAdapter to compare with
155
+ #
156
+ # @return [Boolean]
157
+ # true if they are equal, false if not
158
+ #
159
+ # @api public
160
+ def eql?(other)
161
+ if equal?(other)
162
+ return true
108
163
  end
109
164
 
110
- # TODO: move to dm-more/dm-migrations
111
- def alter_property_storage(repository, *args)
112
- raise NotImplementedError
165
+ unless instance_of?(other.class)
166
+ return false
113
167
  end
114
168
 
115
- module ClassMethods
116
- # Default TypeMap for all adapters.
117
- #
118
- # @return <DataMapper::TypeMap> default TypeMap
119
- #
120
- # TODO: move to dm-more/dm-migrations
121
- def type_map
122
- @type_map ||= TypeMap.new
123
- end
124
- end
169
+ cmp?(other, :eql?)
125
170
  end
126
171
 
127
- include Migration
128
- extend Migration::ClassMethods
129
-
130
- # TODO: move to dm-more/dm-transaction
131
- module Transaction
132
- #
133
- # Pushes the given Transaction onto the per thread Transaction stack so
134
- # that everything done by this Adapter is done within the context of said
135
- # Transaction.
136
- #
137
- # @param transaction<DataMapper::Transaction> a Transaction to be the
138
- # 'current' transaction until popped.
139
- #
140
- # TODO: move to dm-more/dm-transaction
141
- def push_transaction(transaction)
142
- transactions(Thread.current) << transaction
143
- end
144
-
145
- #
146
- # Pop the 'current' Transaction from the per thread Transaction stack so
147
- # that everything done by this Adapter is no longer necessarily within the
148
- # context of said Transaction.
149
- #
150
- # @return <DataMapper::Transaction> the former 'current' transaction.
151
- #
152
- # TODO: move to dm-more/dm-transaction
153
- def pop_transaction
154
- transactions(Thread.current).pop
155
- end
172
+ # Compares another AbstractAdapter for equivalency
173
+ #
174
+ # @example with an equivalent adapter
175
+ # adapter == equivalent_adapter # => true
176
+ #
177
+ # @example with a different adapter
178
+ # adapter == different_adapter # => false
179
+ #
180
+ # AbstractAdapter is equal to +other+ if they are the same object (identity)
181
+ # or if they both have the same name
182
+ #
183
+ # @param [AbstractAdapter] other
184
+ # the other AbstractAdapter to compare with
185
+ #
186
+ # @return [Boolean]
187
+ # true if they are equal, false if not
188
+ #
189
+ # @api public
190
+ def ==(other)
191
+ return true if equal?(other)
192
+
193
+ other.respond_to?(:name) &&
194
+ other.respond_to?(:options) &&
195
+ other.respond_to?(:resource_naming_convention) &&
196
+ other.respond_to?(:field_naming_convention) &&
197
+ cmp?(other, :==)
198
+ end
156
199
 
157
- #
158
- # Retrieve the current transaction for this Adapter.
159
- #
160
- # Everything done by this Adapter is done within the context of this
161
- # Transaction.
162
- #
163
- # @return <DataMapper::Transaction> the 'current' transaction for this Adapter.
164
- #
165
- # TODO: move to dm-more/dm-transaction
166
- def current_transaction
167
- transactions(Thread.current).last
168
- end
200
+ protected
169
201
 
170
- #
171
- # Returns whether we are within a Transaction.
172
- #
173
- # @return <Boolean> whether we are within a Transaction.
174
- #
175
- # TODO: move to dm-more/dm-transaction
176
- def within_transaction?
177
- !current_transaction.nil?
178
- end
202
+ # Set the serial value of the Resource
203
+ #
204
+ # @param [Resource] resource
205
+ # the resource to set the serial property in
206
+ # @param [Integer] id
207
+ # the identifier to set in the resource
208
+ #
209
+ # @return [undefined]
210
+ #
211
+ # @api semipublic
212
+ def initialize_serial(resource, next_id)
213
+ return unless serial = resource.model.serial(name)
214
+ return unless serial.get!(resource).nil?
215
+ serial.set!(resource, next_id)
216
+
217
+ # TODO: replace above with this, once
218
+ # specs can handle random, non-sequential ids
219
+ #serial.set!(resource, rand(2**32))
220
+ end
179
221
 
180
- #
181
- # Produces a fresh transaction primitive for this Adapter
182
- #
183
- # Used by DataMapper::Transaction to perform its various tasks.
184
- #
185
- # @return <Object> a new Object that responds to :close, :begin, :commit,
186
- # :rollback, :rollback_prepared and :prepare
187
- #
188
- # TODO: move to dm-more/dm-transaction (if possible)
189
- def transaction_primitive
190
- raise NotImplementedError
191
- end
222
+ # Translate the attributes into a Hash with the field as the key
223
+ #
224
+ # @example
225
+ # attributes = { User.properties[:name] => 'Dan Kubb' }
226
+ # adapter.attributes_as_fields(attributes) # => { 'name' => 'Dan Kubb' }
227
+ #
228
+ # @param [Hash] attributes
229
+ # the attributes with the Property as the key
230
+ #
231
+ # @return [Hash]
232
+ # the attributes with the Property#field as the key
233
+ #
234
+ # @api semipublic
235
+ def attributes_as_fields(attributes)
236
+ attributes.map { |property, value| [ property.field, value ] }.to_hash
237
+ end
192
238
 
193
- private
194
- def transactions(thread)
195
- unless @transactions[thread]
196
- @transactions.delete_if do |key, value|
197
- !key.respond_to?(:alive?) || !key.alive?
198
- end
199
- @transactions[thread] = []
200
- end
201
- @transactions[thread]
202
- end
239
+ private
203
240
 
241
+ # Initialize an AbstractAdapter instance
242
+ #
243
+ # @param [Symbol] name
244
+ # the adapter repository name
245
+ # @param [Hash] options
246
+ # the adapter configuration options
247
+ #
248
+ # @return [undefined]
249
+ #
250
+ # @api semipublic
251
+ def initialize(name, options)
252
+ @name = name
253
+ @options = options.dup.freeze
254
+ @resource_naming_convention = NamingConventions::Resource::UnderscoredAndPluralized
255
+ @field_naming_convention = NamingConventions::Field::Underscored
204
256
  end
205
257
 
206
- include Transaction
258
+ # Compare other object for equality of equivalency
259
+ #
260
+ # @param [AbstractAdapter] other
261
+ # the other adapter
262
+ # @param [Symbol] operator
263
+ # the comparison operator
264
+ #
265
+ # @return [Boolean]
266
+ # true if the other object is equal or equivalent
267
+ #
268
+ # @api private
269
+ def cmp?(other, operator)
270
+ name.send(operator, other.name) &&
271
+ options.send(operator, other.options) &&
272
+ resource_naming_convention.send(operator, other.resource_naming_convention) &&
273
+ field_naming_convention.send(operator, other.field_naming_convention)
274
+ end
207
275
  end # class AbstractAdapter
276
+
277
+ const_added(:AbstractAdapter)
208
278
  end # module Adapters
209
279
  end # module DataMapper