datamapper-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 (192) hide show
  1. data/.autotest +17 -14
  2. data/.gitignore +3 -1
  3. data/FAQ +6 -5
  4. data/History.txt +5 -39
  5. data/Manifest.txt +67 -76
  6. data/QUICKLINKS +1 -1
  7. data/README.txt +21 -15
  8. data/Rakefile +16 -15
  9. data/SPECS +2 -29
  10. data/TODO +1 -1
  11. data/dm-core.gemspec +11 -15
  12. data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
  13. data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
  14. data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
  15. data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
  16. data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
  17. data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
  18. data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
  19. data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
  20. data/lib/dm-core/adapters.rb +135 -16
  21. data/lib/dm-core/associations/many_to_many.rb +372 -90
  22. data/lib/dm-core/associations/many_to_one.rb +220 -73
  23. data/lib/dm-core/associations/one_to_many.rb +319 -255
  24. data/lib/dm-core/associations/one_to_one.rb +66 -53
  25. data/lib/dm-core/associations/relationship.rb +560 -158
  26. data/lib/dm-core/collection.rb +1104 -381
  27. data/lib/dm-core/core_ext/kernel.rb +12 -0
  28. data/lib/dm-core/core_ext/symbol.rb +10 -0
  29. data/lib/dm-core/identity_map.rb +4 -34
  30. data/lib/dm-core/migrations.rb +1283 -0
  31. data/lib/dm-core/model/descendant_set.rb +81 -0
  32. data/lib/dm-core/model/hook.rb +45 -0
  33. data/lib/dm-core/model/is.rb +32 -0
  34. data/lib/dm-core/model/property.rb +248 -0
  35. data/lib/dm-core/model/relationship.rb +335 -0
  36. data/lib/dm-core/model/scope.rb +90 -0
  37. data/lib/dm-core/model.rb +570 -369
  38. data/lib/dm-core/property.rb +753 -280
  39. data/lib/dm-core/property_set.rb +141 -98
  40. data/lib/dm-core/query/conditions/comparison.rb +814 -0
  41. data/lib/dm-core/query/conditions/operation.rb +247 -0
  42. data/lib/dm-core/query/direction.rb +43 -0
  43. data/lib/dm-core/query/operator.rb +42 -0
  44. data/lib/dm-core/query/path.rb +102 -0
  45. data/lib/dm-core/query/sort.rb +45 -0
  46. data/lib/dm-core/query.rb +974 -492
  47. data/lib/dm-core/repository.rb +147 -107
  48. data/lib/dm-core/resource.rb +644 -429
  49. data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
  50. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
  51. data/lib/dm-core/support/chainable.rb +20 -0
  52. data/lib/dm-core/support/deprecate.rb +12 -0
  53. data/lib/dm-core/support/equalizer.rb +23 -0
  54. data/lib/dm-core/support/logger.rb +13 -0
  55. data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
  56. data/lib/dm-core/transaction.rb +333 -92
  57. data/lib/dm-core/type.rb +98 -60
  58. data/lib/dm-core/types/boolean.rb +1 -1
  59. data/lib/dm-core/types/discriminator.rb +34 -20
  60. data/lib/dm-core/types/object.rb +7 -4
  61. data/lib/dm-core/types/paranoid_boolean.rb +11 -9
  62. data/lib/dm-core/types/paranoid_datetime.rb +11 -9
  63. data/lib/dm-core/types/serial.rb +3 -3
  64. data/lib/dm-core/types/text.rb +3 -4
  65. data/lib/dm-core/version.rb +1 -1
  66. data/lib/dm-core.rb +106 -110
  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/model/relationship_spec.rb +924 -0
  80. data/spec/public/model_spec.rb +159 -0
  81. data/spec/public/property_spec.rb +829 -0
  82. data/spec/public/resource_spec.rb +71 -0
  83. data/spec/public/sel_spec.rb +44 -0
  84. data/spec/public/setup_spec.rb +145 -0
  85. data/spec/public/shared/association_collection_shared_spec.rb +317 -0
  86. data/spec/public/shared/collection_shared_spec.rb +1723 -0
  87. data/spec/public/shared/finder_shared_spec.rb +1619 -0
  88. data/spec/public/shared/resource_shared_spec.rb +924 -0
  89. data/spec/public/shared/sel_shared_spec.rb +112 -0
  90. data/spec/public/transaction_spec.rb +129 -0
  91. data/spec/public/types/discriminator_spec.rb +130 -0
  92. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  93. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  94. data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
  95. data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
  96. data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
  97. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
  98. data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
  99. data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
  100. data/spec/semipublic/associations/relationship_spec.rb +194 -0
  101. data/spec/semipublic/associations_spec.rb +177 -0
  102. data/spec/semipublic/collection_spec.rb +142 -0
  103. data/spec/semipublic/property_spec.rb +61 -0
  104. data/spec/semipublic/query/conditions_spec.rb +528 -0
  105. data/spec/semipublic/query/path_spec.rb +443 -0
  106. data/spec/semipublic/query_spec.rb +2626 -0
  107. data/spec/semipublic/resource_spec.rb +47 -0
  108. data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
  109. data/spec/spec.opts +3 -1
  110. data/spec/spec_helper.rb +80 -57
  111. data/tasks/ci.rb +19 -31
  112. data/tasks/dm.rb +43 -48
  113. data/tasks/doc.rb +8 -11
  114. data/tasks/gemspec.rb +5 -5
  115. data/tasks/hoe.rb +15 -16
  116. data/tasks/install.rb +8 -10
  117. metadata +72 -93
  118. data/lib/dm-core/associations/relationship_chain.rb +0 -81
  119. data/lib/dm-core/associations.rb +0 -207
  120. data/lib/dm-core/auto_migrations.rb +0 -105
  121. data/lib/dm-core/dependency_queue.rb +0 -32
  122. data/lib/dm-core/hook.rb +0 -11
  123. data/lib/dm-core/is.rb +0 -16
  124. data/lib/dm-core/logger.rb +0 -232
  125. data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
  126. data/lib/dm-core/migrator.rb +0 -29
  127. data/lib/dm-core/scope.rb +0 -58
  128. data/lib/dm-core/support/array.rb +0 -13
  129. data/lib/dm-core/support/assertions.rb +0 -8
  130. data/lib/dm-core/support/errors.rb +0 -23
  131. data/lib/dm-core/support/kernel.rb +0 -11
  132. data/lib/dm-core/support/symbol.rb +0 -41
  133. data/lib/dm-core/support.rb +0 -7
  134. data/lib/dm-core/type_map.rb +0 -80
  135. data/lib/dm-core/types.rb +0 -19
  136. data/script/all +0 -4
  137. data/spec/integration/association_spec.rb +0 -1382
  138. data/spec/integration/association_through_spec.rb +0 -203
  139. data/spec/integration/associations/many_to_many_spec.rb +0 -449
  140. data/spec/integration/associations/many_to_one_spec.rb +0 -163
  141. data/spec/integration/associations/one_to_many_spec.rb +0 -188
  142. data/spec/integration/auto_migrations_spec.rb +0 -413
  143. data/spec/integration/collection_spec.rb +0 -1073
  144. data/spec/integration/data_objects_adapter_spec.rb +0 -32
  145. data/spec/integration/dependency_queue_spec.rb +0 -46
  146. data/spec/integration/model_spec.rb +0 -197
  147. data/spec/integration/mysql_adapter_spec.rb +0 -85
  148. data/spec/integration/postgres_adapter_spec.rb +0 -731
  149. data/spec/integration/property_spec.rb +0 -253
  150. data/spec/integration/query_spec.rb +0 -514
  151. data/spec/integration/repository_spec.rb +0 -61
  152. data/spec/integration/resource_spec.rb +0 -513
  153. data/spec/integration/sqlite3_adapter_spec.rb +0 -352
  154. data/spec/integration/sti_spec.rb +0 -273
  155. data/spec/integration/strategic_eager_loading_spec.rb +0 -156
  156. data/spec/integration/transaction_spec.rb +0 -75
  157. data/spec/integration/type_spec.rb +0 -275
  158. data/spec/lib/logging_helper.rb +0 -18
  159. data/spec/lib/mock_adapter.rb +0 -27
  160. data/spec/lib/model_loader.rb +0 -100
  161. data/spec/lib/publicize_methods.rb +0 -28
  162. data/spec/models/content.rb +0 -16
  163. data/spec/models/vehicles.rb +0 -34
  164. data/spec/models/zoo.rb +0 -48
  165. data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
  166. data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
  167. data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
  168. data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
  169. data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
  170. data/spec/unit/associations/many_to_many_spec.rb +0 -32
  171. data/spec/unit/associations/many_to_one_spec.rb +0 -159
  172. data/spec/unit/associations/one_to_many_spec.rb +0 -393
  173. data/spec/unit/associations/one_to_one_spec.rb +0 -7
  174. data/spec/unit/associations/relationship_spec.rb +0 -71
  175. data/spec/unit/associations_spec.rb +0 -242
  176. data/spec/unit/auto_migrations_spec.rb +0 -111
  177. data/spec/unit/collection_spec.rb +0 -182
  178. data/spec/unit/data_mapper_spec.rb +0 -35
  179. data/spec/unit/identity_map_spec.rb +0 -126
  180. data/spec/unit/is_spec.rb +0 -80
  181. data/spec/unit/migrator_spec.rb +0 -33
  182. data/spec/unit/model_spec.rb +0 -321
  183. data/spec/unit/naming_conventions_spec.rb +0 -36
  184. data/spec/unit/property_set_spec.rb +0 -90
  185. data/spec/unit/property_spec.rb +0 -753
  186. data/spec/unit/query_spec.rb +0 -571
  187. data/spec/unit/repository_spec.rb +0 -93
  188. data/spec/unit/resource_spec.rb +0 -649
  189. data/spec/unit/scope_spec.rb +0 -142
  190. data/spec/unit/transaction_spec.rb +0 -493
  191. data/spec/unit/type_map_spec.rb +0 -114
  192. data/spec/unit/type_spec.rb +0 -119
data/lib/dm-core.rb CHANGED
@@ -4,27 +4,20 @@
4
4
  # * Requires fastthread, support libs, and base.
5
5
  # * Sets the application root and environment for compatibility with frameworks
6
6
  # such as Rails or Merb.
7
- # * Checks for the database.yml and loads it if it exists.
8
- # * Sets up the database using the config from the Yaml file or from the
9
- # environment.
10
7
  #
11
8
 
9
+ require 'addressable/uri'
10
+ require 'base64'
11
+ require 'bigdecimal'
12
+ require 'bigdecimal/util'
12
13
  require 'date'
14
+ require 'extlib'
13
15
  require 'pathname'
14
- require 'rubygems'
15
16
  require 'set'
16
17
  require 'time'
17
18
  require 'yaml'
18
19
 
19
- gem 'addressable', '~>2.0.1'
20
- require 'addressable/uri'
21
-
22
- gem 'extlib', '~>0.9.11'
23
- require 'extlib'
24
- require 'extlib/inflection'
25
-
26
20
  begin
27
- gem 'fastthread', '~>1.0.1'
28
21
  require 'fastthread'
29
22
  rescue LoadError
30
23
  # fastthread not installed
@@ -32,30 +25,58 @@ end
32
25
 
33
26
  dir = Pathname(__FILE__).dirname.expand_path / 'dm-core'
34
27
 
35
- require dir / 'support'
36
- require dir / 'resource'
28
+ require dir / 'support' / 'chainable'
29
+ require dir / 'support' / 'deprecate'
30
+ require dir / 'support' / 'equalizer'
31
+
37
32
  require dir / 'model'
33
+ require dir / 'model' / 'descendant_set'
34
+ require dir / 'model' / 'hook'
35
+ require dir / 'model' / 'is'
36
+ require dir / 'model' / 'scope'
37
+ require dir / 'model' / 'relationship'
38
+ require dir / 'model' / 'property'
38
39
 
39
- require dir / 'dependency_queue'
40
- require dir / 'type'
41
- require dir / 'type_map'
42
- require dir / 'types'
43
- require dir / 'hook'
44
- require dir / 'associations'
45
- require dir / 'auto_migrations'
40
+ require dir / 'collection'
41
+
42
+ require dir / 'adapters'
43
+ require dir / 'adapters' / 'abstract_adapter'
44
+ require dir / 'associations' / 'relationship'
45
+ require dir / 'associations' / 'one_to_many'
46
+ require dir / 'associations' / 'one_to_one'
47
+ require dir / 'associations' / 'many_to_one'
48
+ require dir / 'associations' / 'many_to_many'
46
49
  require dir / 'identity_map'
47
- require dir / 'logger'
48
- require dir / 'migrator'
49
- require dir / 'naming_conventions'
50
+ require dir / 'migrations' # TODO: move to dm-more
51
+ require dir / 'property'
50
52
  require dir / 'property_set'
51
53
  require dir / 'query'
52
- require dir / 'transaction'
54
+ require dir / 'query' / 'conditions' / 'operation'
55
+ require dir / 'query' / 'conditions' / 'comparison'
56
+ require dir / 'query' / 'operator'
57
+ require dir / 'query' / 'direction'
58
+ require dir / 'query' / 'path'
59
+ require dir / 'query' / 'sort'
53
60
  require dir / 'repository'
54
- require dir / 'scope'
55
- require dir / 'property'
56
- require dir / 'adapters'
57
- require dir / 'collection'
58
- require dir / 'is'
61
+ require dir / 'resource'
62
+ require dir / 'support' / 'logger'
63
+ require dir / 'support' / 'naming_conventions'
64
+ require dir / 'transaction' # TODO: move to dm-more
65
+ require dir / 'type'
66
+ require dir / 'types' / 'boolean'
67
+ require dir / 'types' / 'discriminator'
68
+ require dir / 'types' / 'text'
69
+ require dir / 'types' / 'paranoid_datetime' # TODO: move to dm-more
70
+ require dir / 'types' / 'paranoid_boolean' # TODO: move to dm-more
71
+ require dir / 'types' / 'object'
72
+ require dir / 'types' / 'serial'
73
+ require dir / 'version'
74
+
75
+ require dir / 'core_ext' / 'kernel' # TODO: do not load automatically
76
+ require dir / 'core_ext' / 'symbol' # TODO: do not load automatically
77
+
78
+ # A logger should always be present. Lets be consistent with DO
79
+ DataMapper::Logger.new(StringIO.new, :fatal)
59
80
 
60
81
  # == Setup and Configuration
61
82
  # DataMapper uses URIs or a connection hash to connect to your data-store.
@@ -76,10 +97,10 @@ require dir / 'is'
76
97
  # address the data-store on the server.
77
98
  #
78
99
  # Here's some examples
79
- # DataMapper.setup(:default, "sqlite3://path/to/your/project/db/development.db")
80
- # DataMapper.setup(:default, "mysql://localhost/dm_core_test")
100
+ # DataMapper.setup(:default, 'sqlite3://path/to/your/project/db/development.db')
101
+ # DataMapper.setup(:default, 'mysql://localhost/dm_core_test')
81
102
  # # no auth-info
82
- # DataMapper.setup(:default, "postgres://root:supahsekret@127.0.0.1/dm_core_test")
103
+ # DataMapper.setup(:default, 'postgres://root:supahsekret@127.0.0.1/dm_core_test')
83
104
  # # with auth-info
84
105
  #
85
106
  #
@@ -88,7 +109,7 @@ require dir / 'is'
88
109
  #
89
110
  # DataMapper.setup(:default, {
90
111
  # :adapter => 'adapter_name_here',
91
- # :database => "path/to/repo",
112
+ # :database => 'path/to/repo',
92
113
  # :username => 'username',
93
114
  # :password => 'password',
94
115
  # :host => 'hostname'
@@ -97,67 +118,71 @@ require dir / 'is'
97
118
  # === Logging
98
119
  # To turn on error logging to STDOUT, issue:
99
120
  #
100
- # DataMapper::Logger.new(STDOUT, 0)
121
+ # DataMapper::Logger.new(STDOUT, :debug)
101
122
  #
102
123
  # You can pass a file location ("/path/to/log/file.log") in place of STDOUT.
103
124
  # see DataMapper::Logger for more information.
104
125
  #
105
126
  module DataMapper
106
- extend Assertions
127
+ extend Extlib::Assertions
128
+
129
+ # TODO: move to dm-validations
130
+ class ValidationError < StandardError; end
131
+
132
+ class ObjectNotFoundError < StandardError; end
133
+
134
+ class RepositoryNotSetupError < StandardError; end
135
+
136
+ class IncompleteModelError < StandardError; end
107
137
 
138
+ class PluginNotFoundError < StandardError; end
139
+
140
+ class UpdateConflictError < StandardError; end
141
+
142
+ class UnknownRelationshipError < StandardError; end
143
+
144
+ # Raised on attempt to operate on collection of child objects
145
+ # when parent object is not yet saved.
146
+ # For instance, if your article object is not saved,
147
+ # but you try to fetch or scope down comments (1:n case), or
148
+ # publications (n:m case), operation cannot be completed
149
+ # because parent object's keys are not yet persisted,
150
+ # and thus there is no FK value to use in the query.
151
+ class UnsavedParentError < RuntimeError; end
152
+
153
+ # TODO: document
154
+ # @api private
108
155
  def self.root
109
- @root ||= Pathname(__FILE__).dirname.parent.expand_path
156
+ @root ||= Pathname(__FILE__).dirname.parent.expand_path.freeze
110
157
  end
111
158
 
112
- ##
113
159
  # Setups up a connection to a data-store
114
160
  #
115
- # @param Symbol name a name for the context, defaults to :default
116
- # @param [Hash{Symbol => String}, Addressable::URI, String] uri_or_options
161
+ # @param [Symbol] name
162
+ # a name for the context, defaults to :default
163
+ # @param [Hash(Symbol => String), Addressable::URI, String] uri_or_options
117
164
  # connection information
118
165
  #
119
- # @return Repository the resulting setup repository
166
+ # @return [DataMapper::Adapters::AbstractAdapter]
167
+ # the resulting setup adapter
120
168
  #
121
- # @raise ArgumentError "+name+ must be a Symbol, but was..." indicates that
122
- # an invalid argument was passed for name[Symbol]
123
- # @raise [ArgumentError] "+uri_or_options+ must be a Hash, URI or String,
124
- # but was..." indicates that connection information could not be gleaned
125
- # from the given uri_or_options<Hash, Addressable::URI, String>
169
+ # @raise [ArgumentError] "+name+ must be a Symbol, but was..."
170
+ # indicates that an invalid argument was passed for name[Symbol]
171
+ # @raise [ArgumentError] "+uri_or_options+ must be a Hash, URI or String, but was..."
172
+ # indicates that connection information could not be gleaned from
173
+ # the given uri_or_options[Hash, Addressable::URI, String]
126
174
  #
127
- # -
128
175
  # @api public
129
- def self.setup(name, uri_or_options)
130
- assert_kind_of 'name', name, Symbol
131
- assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, Hash, String
132
-
133
- case uri_or_options
134
- when Hash
135
- adapter_name = uri_or_options[:adapter].to_s
136
- when String, DataObjects::URI, Addressable::URI
137
- uri_or_options = DataObjects::URI.parse(uri_or_options) if uri_or_options.kind_of?(String)
138
- adapter_name = uri_or_options.scheme
139
- end
140
-
141
- class_name = Extlib::Inflection.classify(adapter_name) + 'Adapter'
142
-
143
- unless Adapters::const_defined?(class_name)
144
- lib_name = "#{Extlib::Inflection.underscore(adapter_name)}_adapter"
145
- begin
146
- require root / 'lib' / 'dm-core' / 'adapters' / lib_name
147
- rescue LoadError => e
148
- begin
149
- require lib_name
150
- rescue Exception
151
- # library not found, raise the original error
152
- raise e
153
- end
154
- end
176
+ def self.setup(*args)
177
+ adapter = if args.first.kind_of?(Adapters::AbstractAdapter)
178
+ args.first
179
+ else
180
+ DataMapper::Adapters.new(*args)
155
181
  end
156
182
 
157
- Repository.adapters[name] = Adapters::const_get(class_name).new(name, uri_or_options)
183
+ Repository.adapters[adapter.name] = adapter
158
184
  end
159
185
 
160
- ##
161
186
  # Block Syntax
162
187
  # Pushes the named repository onto the context-stack,
163
188
  # yields a new session, and pops the context-stack.
@@ -167,12 +192,14 @@ module DataMapper
167
192
  # a new Session.
168
193
  #
169
194
  # @param [Symbol] args the name of a repository to act within or return, :default is default
195
+ #
170
196
  # @yield [Proc] (optional) block to execute within the context of the named repository
171
- # @demo spec/integration/repository_spec.rb
172
- def self.repository(name = nil) # :yields: current_context
197
+ #
198
+ # @api public
199
+ def self.repository(name = nil)
173
200
  current_repository = if name
174
- raise ArgumentError, "First optional argument must be a Symbol, but was #{name.inspect}" unless name.is_a?(Symbol)
175
- Repository.context.detect { |r| r.name == name } || Repository.new(name)
201
+ assert_kind_of 'name', name, Symbol
202
+ Repository.context.detect { |repository| repository.name == name } || Repository.new(name)
176
203
  else
177
204
  Repository.context.last || Repository.new(Repository.default_name)
178
205
  end
@@ -183,35 +210,4 @@ module DataMapper
183
210
  current_repository
184
211
  end
185
212
  end
186
-
187
- # A logger should always be present. Lets be consistent with DO
188
- Logger.new(nil, :off)
189
-
190
- ##
191
- # destructively migrates the repository upwards to match model definitions
192
- #
193
- # @param [Symbol] name repository to act on, :default is the default
194
- def self.migrate!(name = Repository.default_name)
195
- repository(name).migrate!
196
- end
197
-
198
- ##
199
- # drops and recreates the repository upwards to match model definitions
200
- #
201
- # @param [Symbol] name repository to act on, :default is the default
202
- def self.auto_migrate!(repository_name = nil)
203
- AutoMigrator.auto_migrate(repository_name)
204
- end
205
-
206
- def self.auto_upgrade!(repository_name = nil)
207
- AutoMigrator.auto_upgrade(repository_name)
208
- end
209
-
210
- def self.prepare(*args, &blk)
211
- yield repository(*args)
212
- end
213
-
214
- def self.dependency_queue
215
- @dependency_queue ||= DependencyQueue.new
216
- end
217
213
  end
@@ -1,19 +1,19 @@
1
- #!/usr/bin/env ruby
2
-
3
- require File.join(File.dirname(__FILE__), '..', 'lib', 'dm-core')
4
- require File.join(File.dirname(__FILE__), '..', 'lib', 'dm-core', 'version')
1
+ #!/usr/bin/env ruby -KU
5
2
 
6
3
  require 'ftools'
7
4
  require 'rubygems'
8
5
 
9
- gem 'rbench', '~>0.2.3'
10
- require 'rbench'
6
+ gem 'activerecord', '~>2.3.2'
7
+ gem 'addressable', '~>2.0'
8
+ gem 'faker', '~>0.3.1'
9
+ gem 'rbench', '~>0.2.3'
11
10
 
12
- gem 'faker', '~>0.3.1'
11
+ require 'active_record'
12
+ require 'addressable/uri'
13
13
  require 'faker'
14
+ require 'rbench'
14
15
 
15
- gem 'activerecord', '~>2.2.2'
16
- require 'active_record'
16
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'dm-core'))
17
17
 
18
18
  socket_file = Pathname.glob(%w[
19
19
  /opt/local/var/run/mysql5/mysqld.sock
@@ -29,7 +29,7 @@ configuration_options = {
29
29
  :adapter => 'mysql',
30
30
  :username => 'root',
31
31
  :password => '',
32
- :database => 'data_mapper_1',
32
+ :database => 'dm_core_test',
33
33
  }
34
34
 
35
35
  configuration_options[:socket] = socket_file unless socket_file.nil?
@@ -38,12 +38,12 @@ log_dir = DataMapper.root / 'log'
38
38
  log_dir.mkdir unless log_dir.directory?
39
39
 
40
40
  DataMapper::Logger.new(log_dir / 'dm.log', :off)
41
- adapter = DataMapper.setup(:default, "mysql://root@localhost/data_mapper_1?socket=#{socket_file}")
41
+ adapter = DataMapper.setup(:default, "mysql://root@localhost/dm_core_test?socket=#{socket_file}")
42
42
 
43
43
  if configuration_options[:adapter]
44
- sqlfile = File.join(File.dirname(__FILE__),'..','tmp','performance.sql')
45
- mysql_bin = %w[mysql mysql5].select{|bin| `which #{bin}`.length > 0 }
46
- mysqldump_bin = %w[mysqldump mysqldump5].select{|bin| `which #{bin}`.length > 0 }
44
+ sqlfile = File.join(File.dirname(__FILE__), '..', 'tmp', 'performance.sql')
45
+ mysql_bin = %w[ mysql mysql5 ].select { |bin| `which #{bin}`.length > 0 }
46
+ mysqldump_bin = %w[ mysqldump mysqldump5 ].select { |bin| `which #{bin}`.length > 0 }
47
47
  end
48
48
 
49
49
  ActiveRecord::Base.logger = Logger.new(log_dir / 'ar.log')
@@ -61,46 +61,45 @@ class ARUser < ActiveRecord::Base #:nodoc:
61
61
  set_table_name 'users'
62
62
 
63
63
  has_many :exhibits, :foreign_key => 'user_id'
64
-
65
64
  end
66
65
 
67
66
  ARExhibit.find_by_sql('SELECT 1')
68
67
 
69
- class Exhibit
68
+ class User
70
69
  include DataMapper::Resource
71
70
 
72
71
  property :id, Serial
73
72
  property :name, String
74
- property :zoo_id, Integer
75
- property :user_id, Integer
76
- property :notes, Text, :lazy => true
73
+ property :email, String
74
+ property :about, Text, :lazy => false
77
75
  property :created_on, Date
78
-
79
- belongs_to :user
80
- # property :updated_at, DateTime
81
76
  end
82
77
 
83
- class User
78
+ class Exhibit
84
79
  include DataMapper::Resource
85
80
 
86
- property :id, Serial
87
- property :name, String
88
- property :email, String
89
- property :about, Text, :lazy => true
81
+ property :id, Serial
82
+ property :name, String
83
+ property :zoo_id, Integer
84
+ property :user_id, Integer
85
+ property :notes, Text, :lazy => false
90
86
  property :created_on, Date
91
87
 
88
+ belongs_to :user
92
89
  end
93
90
 
94
- touch_attributes = lambda do |exhibits|
95
- [*exhibits].each do |exhibit|
91
+ DataMapper.auto_migrate!
92
+
93
+ def touch_attributes(*exhibits)
94
+ exhibits.flatten.each do |exhibit|
96
95
  exhibit.id
97
96
  exhibit.name
98
97
  exhibit.created_on
99
98
  end
100
99
  end
101
100
 
102
- touch_relationships = lambda do |exhibits|
103
- [*exhibits].each do |exhibit|
101
+ def touch_relationships(*exhibits)
102
+ exhibits.flatten.each do |exhibit|
104
103
  exhibit.id
105
104
  exhibit.name
106
105
  exhibit.created_on
@@ -108,7 +107,6 @@ touch_relationships = lambda do |exhibits|
108
107
  end
109
108
  end
110
109
 
111
-
112
110
  c = configuration_options
113
111
 
114
112
  if sqlfile && File.exists?(sqlfile)
@@ -116,14 +114,7 @@ if sqlfile && File.exists?(sqlfile)
116
114
  #adapter.execute("LOAD DATA LOCAL INFILE '#{sqlfile}' INTO TABLE exhibits")
117
115
  `#{mysql_bin} -u #{c[:username]} #{"-p#{c[:password]}" unless c[:password].blank?} #{c[:database]} < #{sqlfile}`
118
116
  else
119
-
120
- puts "Generating data for benchmarking..."
121
-
122
- User.auto_migrate!
123
- Exhibit.auto_migrate!
124
-
125
- users = []
126
- exhibits = []
117
+ puts 'Generating data for benchmarking...'
127
118
 
128
119
  # pre-compute the insert statements and fake data compilation,
129
120
  # so the benchmarks below show the actual runtime for the execute
@@ -131,35 +122,30 @@ else
131
122
 
132
123
  # Using the same paragraph for all exhibits because it is very slow
133
124
  # to generate unique paragraphs for all exhibits.
134
- paragraph = Faker::Lorem.paragraphs.join($/)
135
-
136
- 10_000.times do |i|
137
- users << [
138
- 'INSERT INTO `users` (`name`,`email`,`created_on`) VALUES (?, ?, ?)',
139
- Faker::Name.name,
140
- Faker::Internet.email,
141
- Date.today
142
- ]
143
-
144
- exhibits << [
145
- 'INSERT INTO `exhibits` (`name`, `zoo_id`, `user_id`, `notes`, `created_on`) VALUES (?, ?, ?, ?, ?)',
146
- Faker::Company.name,
147
- rand(10).ceil,
148
- i,
149
- paragraph,#Faker::Lorem.paragraphs.join($/),
150
- Date.today
151
- ]
125
+ notes = Faker::Lorem.paragraphs.join($/)
126
+ today = Date.today
127
+
128
+ puts 'Inserting 10,000 users and exhibits...'
129
+ 10_000.times do
130
+ user = User.create(
131
+ :created_on => today,
132
+ :name => Faker::Name.name,
133
+ :email => Faker::Internet.email
134
+ )
135
+
136
+ Exhibit.create(
137
+ :created_on => today,
138
+ :name => Faker::Company.name,
139
+ :user => user,
140
+ :notes => notes,
141
+ :zoo_id => rand(10).ceil
142
+ )
152
143
  end
153
144
 
154
- puts "Inserting 10,000 users..."
155
- 10_000.times { |i| adapter.execute(*users.at(i)) }
156
- puts "Inserting 10,000 exhibits..."
157
- 10_000.times { |i| adapter.execute(*exhibits.at(i)) }
158
-
159
145
  if sqlfile
160
146
  answer = nil
161
147
  until answer && answer[/^$|y|yes|n|no/]
162
- print("Would you like to dump data into tmp/performance.sql (for faster setup)? [Yn]");
148
+ print('Would you like to dump data into tmp/performance.sql (for faster setup)? [Yn]');
163
149
  STDOUT.flush
164
150
  answer = gets
165
151
  end
@@ -171,13 +157,12 @@ else
171
157
  puts "File saved\n"
172
158
  end
173
159
  end
174
-
175
160
  end
176
161
 
177
- TIMES = ENV['x'] ? ENV['x'].to_i : 10_000
162
+ TIMES = ENV.key?('x') ? ENV['x'].to_i : 10_000
178
163
 
179
- puts "You can specify how many times you want to run the benchmarks with rake:perf x=(number)"
180
- puts "Some tasks will be run 10 and 1000 times less than (number)"
164
+ puts 'You can specify how many times you want to run the benchmarks with rake:perf x=(number)'
165
+ puts 'Some tasks will be run 10 and 1000 times less than (number)'
181
166
  puts "Benchmarks will now run #{TIMES} times"
182
167
  # Inform about slow benchmark
183
168
  # answer = nil
@@ -193,90 +178,98 @@ puts "Benchmarks will now run #{TIMES} times"
193
178
  RBench.run(TIMES) do
194
179
 
195
180
  column :times
196
- column :ar, :title => "AR 2.1"
181
+ column :ar, :title => 'AR 2.3.2'
197
182
  column :dm, :title => "DM #{DataMapper::VERSION}"
198
- column :diff, :compare => [:ar,:dm]
183
+ column :diff, :compare => [:ar, :dm]
184
+
185
+ report 'Model#id', (TIMES * 100).ceil do
186
+ ar_obj = ARExhibit.find(1)
187
+ dm_obj = Exhibit.get(1)
188
+
189
+ ar { ar_obj.id }
190
+ dm { dm_obj.id }
191
+ end
199
192
 
200
- report "Model.new (instantiation)" do
193
+ report 'Model.new (instantiation)' do
201
194
  ar { ARExhibit.new }
202
195
  dm { Exhibit.new }
203
196
  end
204
197
 
205
- report "Model.new (setting attributes)" do
206
- attrs = {:name => 'sam', :zoo_id => 1}
198
+ report 'Model.new (setting attributes)' do
199
+ attrs = { :name => 'sam', :zoo_id => 1 }
207
200
  ar { ARExhibit.new(attrs) }
208
201
  dm { Exhibit.new(attrs) }
209
202
  end
210
203
 
211
- report "Model.get specific (not cached)" do
212
- ActiveRecord::Base.uncached { ar { touch_attributes[ARExhibit.find(1)] } }
213
- dm { touch_attributes[Exhibit.get(1)] }
204
+ report 'Model.get specific (not cached)' do
205
+ ActiveRecord::Base.uncached { ar { touch_attributes(ARExhibit.find(1)) } }
206
+ dm { touch_attributes(Exhibit.get(1)) }
214
207
  end
215
208
 
216
- report "Model.get specific (cached)" do
217
- ActiveRecord::Base.cache { ar { touch_attributes[ARExhibit.find(1)] } }
218
- Exhibit.repository(:default) { dm { touch_attributes[Exhibit.get(1)] } }
209
+ report 'Model.get specific (cached)' do
210
+ ActiveRecord::Base.cache { ar { touch_attributes(ARExhibit.find(1)) } }
211
+ Exhibit.repository(:default) { dm { touch_attributes(Exhibit.get(1)) } }
219
212
  end
220
213
 
221
- report "Model.first" do
222
- ar { touch_attributes[ARExhibit.first] }
223
- dm { touch_attributes[Exhibit.first] }
214
+ report 'Model.first' do
215
+ ar { touch_attributes(ARExhibit.first) }
216
+ dm { touch_attributes(Exhibit.first) }
224
217
  end
225
218
 
226
- report "Model.all limit(100)", (TIMES / 10.0).ceil do
227
- ar { touch_attributes[ARExhibit.find(:all, :limit => 100)] }
228
- dm { touch_attributes[Exhibit.all(:limit => 100)] }
219
+ report 'Model.all limit(100)', (TIMES / 10).ceil do
220
+ ar { touch_attributes(ARExhibit.find(:all, :limit => 100)) }
221
+ dm { touch_attributes(Exhibit.all(:limit => 100)) }
229
222
  end
230
223
 
231
- report "Model.all limit(100) with relationship", (TIMES / 10.0).ceil do
232
- ar { touch_relationships[ARExhibit.all(:limit => 100, :include => [:user])] }
233
- dm { touch_relationships[Exhibit.all(:limit => 100)] }
224
+ report 'Model.all limit(100) with relationship', (TIMES / 10).ceil do
225
+ ar { touch_relationships(ARExhibit.all(:limit => 100, :include => [ :user ])) }
226
+ dm { touch_relationships(Exhibit.all(:limit => 100)) }
234
227
  end
235
228
 
236
- report "Model.all limit(10,000)", (TIMES / 1000.0).ceil do
237
- ar { touch_attributes[ARExhibit.find(:all, :limit => 10_000)] }
238
- dm { touch_attributes[Exhibit.all(:limit => 10_000)] }
229
+ report 'Model.all limit(10,000)', (TIMES / 1000).ceil do
230
+ ar { touch_attributes(ARExhibit.find(:all, :limit => 10_000)) }
231
+ dm { touch_attributes(Exhibit.all(:limit => 10_000)) }
239
232
  end
240
233
 
241
- create_exhibit = {
234
+ exhibit = {
242
235
  :name => Faker::Company.name,
243
236
  :zoo_id => rand(10).ceil,
244
237
  :notes => Faker::Lorem.paragraphs.join($/),
245
238
  :created_on => Date.today
246
239
  }
247
240
 
248
- report "Model.create" do
249
- ar { ARExhibit.create(create_exhibit) }
250
- dm { Exhibit.create(create_exhibit) }
241
+ report 'Model.create' do
242
+ ar { ARExhibit.create(exhibit) }
243
+ dm { Exhibit.create(exhibit) }
251
244
  end
252
245
 
253
- report "Resource#attributes" do
254
- attrs_first = {:name => 'sam', :zoo_id => 1}
255
- attrs_second = {:name => 'tom', :zoo_id => 1}
256
- ar { e = ARExhibit.new(attrs_first); e.attributes = attrs_second }
257
- dm { e = Exhibit.new(attrs_first); e.attributes = attrs_second }
246
+ report 'Resource#attributes=' do
247
+ attrs_first = { :name => 'sam', :zoo_id => 1 }
248
+ attrs_second = { :name => 'tom', :zoo_id => 1 }
249
+ ar { exhibit = ARExhibit.new(attrs_first); exhibit.attributes = attrs_second }
250
+ dm { exhibit = Exhibit.new(attrs_first); exhibit.attributes = attrs_second }
258
251
  end
259
252
 
260
- report "Resource#update" do
261
- ar { e = ARExhibit.find(1); e.name = 'bob'; e.save }
262
- dm { e = Exhibit.get(1); e.name = 'bob'; e.save }
253
+ report 'Resource#update' do
254
+ ar { ARExhibit.find(1).update_attributes(:name => 'bob') }
255
+ dm { Exhibit.get(1).update(:name => 'bob') }
263
256
  end
264
257
 
265
- report "Resource#destroy" do
258
+ report 'Resource#destroy' do
266
259
  ar { ARExhibit.first.destroy }
267
260
  dm { Exhibit.first.destroy }
268
261
  end
269
262
 
270
- report "Model.transaction" do
263
+ report 'Model.transaction' do
271
264
  ar { ARExhibit.transaction { ARExhibit.new } }
272
265
  dm { Exhibit.transaction { Exhibit.new } }
273
266
  end
274
267
 
275
- summary "Total"
268
+ summary 'Total'
276
269
  end
277
270
 
278
- connection = adapter.send(:create_connection)
279
- command = connection.create_command("DROP TABLE exhibits")
280
- command = connection.create_command("DROP TABLE users")
271
+ connection = adapter.send(:open_connection)
272
+ command = connection.create_command('DROP TABLE exhibits')
273
+ command = connection.create_command('DROP TABLE users')
281
274
  command.execute_non_query rescue nil
282
275
  connection.close