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,3 +1,3 @@
1
1
  module DataMapper
2
- VERSION = '0.9.11'.freeze
2
+ VERSION = '0.10.0'.freeze
3
3
  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.3.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
@@ -1,17 +1,21 @@
1
- #!/usr/bin/env ruby
2
-
3
- require File.join(File.dirname(__FILE__), '..', 'lib', 'dm-core')
1
+ #!/usr/bin/env ruby -KU
4
2
 
3
+ require 'ftools'
5
4
  require 'rubygems'
6
5
 
7
- gem 'ruby-prof', '~>0.7.3'
8
- require 'ruby-prof'
6
+ gem 'addressable', '~>2.0'
7
+ gem 'faker', '~>0.3.1'
8
+ gem 'ruby-prof', '~>0.7.3'
9
9
 
10
- gem 'faker', '~>0.3.1'
10
+ require 'addressable/uri'
11
11
  require 'faker'
12
+ require 'ruby-prof'
12
13
 
13
- OUTPUT = DataMapper.root / 'profile_results.txt'
14
- #OUTPUT = DataMapper.root / 'profile_results.html'
14
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'dm-core'))
15
+
16
+ TEXT_OUTPUT = DataMapper.root / 'profile_results.txt'
17
+ HTML_OUTPUT = DataMapper.root / 'profile_results.html'
18
+ CALL_OUTPUT = DataMapper.root / 'profile_results.prof'
15
19
 
16
20
  SOCKET_FILE = Pathname.glob(%w[
17
21
  /opt/local/var/run/mysql5/mysqld.sock
@@ -21,8 +25,33 @@ SOCKET_FILE = Pathname.glob(%w[
21
25
  /var/run/mysqld/mysqld.sock
22
26
  ]).find { |path| path.socket? }
23
27
 
28
+ configuration_options = {
29
+ :adapter => 'mysql',
30
+ :database => 'dm_core_test',
31
+ :host => 'localhost',
32
+ :username => 'root',
33
+ :password => '',
34
+ :socket => SOCKET_FILE,
35
+ }
36
+
24
37
  DataMapper::Logger.new(DataMapper.root / 'log' / 'dm.log', :debug)
25
- DataMapper.setup(:default, "mysql://root@localhost/data_mapper_1?socket=#{SOCKET_FILE}")
38
+ adapter = DataMapper.setup(:default, configuration_options)
39
+
40
+ if configuration_options[:adapter]
41
+ sqlfile = File.join(File.dirname(__FILE__), '..', 'tmp', 'performance.sql')
42
+ mysql_bin = %w[ mysql mysql5 ].select { |bin| `which #{bin}`.length > 0 }
43
+ mysqldump_bin = %w[ mysqldump mysqldump5 ].select { |bin| `which #{bin}`.length > 0 }
44
+ end
45
+
46
+ class User
47
+ include DataMapper::Resource
48
+
49
+ property :id, Serial
50
+ property :name, String
51
+ property :email, String
52
+ property :about, Text, :lazy => false
53
+ property :created_on, Date
54
+ end
26
55
 
27
56
  class Exhibit
28
57
  include DataMapper::Resource
@@ -30,58 +59,160 @@ class Exhibit
30
59
  property :id, Serial
31
60
  property :name, String
32
61
  property :zoo_id, Integer
33
- property :notes, Text, :lazy => true
62
+ property :user_id, Integer
63
+ property :notes, Text, :lazy => false
34
64
  property :created_on, Date
35
- # property :updated_at, DateTime
36
65
 
37
- auto_migrate!
38
- create # create one row for testing
66
+ belongs_to :user
67
+ end
68
+
69
+ DataMapper.auto_migrate!
70
+
71
+ def touch_attributes(*exhibits)
72
+ exhibits.flatten.each do |exhibit|
73
+ exhibit.id
74
+ exhibit.name
75
+ exhibit.created_on
76
+ end
39
77
  end
40
78
 
41
- touch_attributes = lambda do |exhibits|
42
- [*exhibits].each do |exhibit|
79
+ def touch_relationships(*exhibits)
80
+ exhibits.flatten.each do |exhibit|
43
81
  exhibit.id
44
82
  exhibit.name
45
83
  exhibit.created_on
46
- exhibit.updated_at
84
+ exhibit.user
47
85
  end
48
86
  end
49
87
 
50
88
  # RubyProf, making profiling Ruby pretty since 1899!
51
89
  def profile(&b)
52
- result = RubyProf.profile &b
53
- printer = RubyProf::FlatPrinter.new(result)
54
- #printer = RubyProf::GraphHtmlPrinter.new(result)
55
- printer.print(OUTPUT.open('w+'))
90
+ results = RubyProf.profile(&b)
91
+
92
+ TEXT_OUTPUT.open('w+') do |file|
93
+ RubyProf::FlatPrinter.new(results).print(file)
94
+ end
95
+
96
+ HTML_OUTPUT.open('w+') do |file|
97
+ RubyProf::GraphHtmlPrinter.new(results).print(file)
98
+ end
99
+
100
+ CALL_OUTPUT.open('w+') do |file|
101
+ RubyProf::CallTreePrinter.new(results).print(file)
102
+ end
103
+ end
104
+
105
+ c = configuration_options
106
+
107
+ if sqlfile && File.exists?(sqlfile)
108
+ puts "Found data-file. Importing from #{sqlfile}"
109
+ #adapter.execute("LOAD DATA LOCAL INFILE '#{sqlfile}' INTO TABLE exhibits")
110
+ `#{mysql_bin} -u #{c[:username]} #{"-p#{c[:password]}" unless c[:password].blank?} #{c[:database]} < #{sqlfile}`
111
+ else
112
+ puts 'Generating data for benchmarking...'
113
+
114
+ # pre-compute the insert statements and fake data compilation,
115
+ # so the benchmarks below show the actual runtime for the execute
116
+ # method, minus the setup steps
117
+
118
+ # Using the same paragraph for all exhibits because it is very slow
119
+ # to generate unique paragraphs for all exhibits.
120
+ notes = Faker::Lorem.paragraphs.join($/)
121
+ today = Date.today
122
+
123
+ puts 'Inserting 10,000 users and exhibits...'
124
+ 10_000.times do
125
+ user = User.create(
126
+ :created_on => today,
127
+ :name => Faker::Name.name,
128
+ :email => Faker::Internet.email
129
+ )
130
+
131
+ Exhibit.create(
132
+ :created_on => today,
133
+ :name => Faker::Company.name,
134
+ :user => user,
135
+ :notes => notes,
136
+ :zoo_id => rand(10).ceil
137
+ )
138
+ end
139
+
140
+ if sqlfile
141
+ answer = nil
142
+ until answer && answer[/^$|y|yes|n|no/]
143
+ print('Would you like to dump data into tmp/performance.sql (for faster setup)? [Yn]');
144
+ STDOUT.flush
145
+ answer = gets
146
+ end
147
+
148
+ if answer[/^$|y|yes/]
149
+ File.makedirs(File.dirname(sqlfile))
150
+ #adapter.execute("SELECT * INTO OUTFILE '#{sqlfile}' FROM exhibits;")
151
+ `#{mysqldump_bin} -u #{c[:username]} #{"-p#{c[:password]}" unless c[:password].blank?} #{c[:database]} exhibits users > #{sqlfile}`
152
+ puts "File saved\n"
153
+ end
154
+ end
56
155
  end
57
156
 
157
+ TIMES = 10_000
158
+
159
+ exhibits = Exhibit.all.to_a
160
+
58
161
  profile do
59
- # 10_000.times { touch_attributes[Exhibit.get(1)] }
60
- #
61
- # repository(:default) do
62
- # 10_000.times { touch_attributes[Exhibit.get(1)] }
63
- # end
162
+ # dm_obj = Exhibit.get(1)
163
+ # puts 'Model#id'
164
+ # (TIMES * 100).times { dm_obj.id }
64
165
  #
65
- # 1000.times { touch_attributes[Exhibit.all(:limit => 100)] }
166
+ # puts 'Model.new (instantiation)'
167
+ # TIMES.times { Exhibit.new }
66
168
  #
67
- # repository(:default) do
68
- # 1000.times { touch_attributes[Exhibit.all(:limit => 100)] }
69
- # end
169
+ # puts 'Model.new (setting attributes)'
170
+ # TIMES.times { Exhibit.new(:name => 'sam', :zoo_id => 1) }
70
171
  #
71
- # 10.times { touch_attributes[Exhibit.all(:limit => 10_000)] }
172
+ # puts 'Model.get specific (not cached)'
173
+ # TIMES.times { touch_attributes(Exhibit.get(1)) }
72
174
  #
175
+ # puts 'Model.get specific (cached)'
73
176
  # repository(:default) do
74
- # 10.times { touch_attributes[Exhibit.all(:limit => 10_000)] }
177
+ # TIMES.times { touch_attributes(Exhibit.get(1)) }
75
178
  # end
76
179
 
77
- create_exhibit = {
78
- :name => Faker::Company.name,
79
- :zoo_id => rand(10).ceil,
80
- :notes => Faker::Lorem.paragraphs.join($/),
81
- :created_on => Date.today
82
- }
180
+ puts 'Model.first'
181
+ TIMES.times { touch_attributes(Exhibit.first) }
83
182
 
84
- 1000.times { Exhibit.create(create_exhibit) }
183
+ # puts 'Model.all limit(100)'
184
+ # (TIMES / 10).ceil.times { touch_attributes(Exhibit.all(:limit => 100)) }
185
+ #
186
+ # puts 'Model.all limit(100) with relationship'
187
+ # (TIMES / 10).ceil.times { touch_relationships(Exhibit.all(:limit => 100)) }
188
+ #
189
+ # puts 'Model.all limit(10,000)'
190
+ # (TIMES / 1000).ceil { touch_attributes(Exhibit.all(:limit => 10_000)) }
191
+ #
192
+ # exhibit = {
193
+ # :name => Faker::Company.name,
194
+ # :zoo_id => rand(10).ceil,
195
+ # :notes => Faker::Lorem.paragraphs.join($/),
196
+ # :created_on => Date.today
197
+ # }
198
+ #
199
+ # puts 'Model.create'
200
+ # TIMES.times { Exhibit.create(exhibit) }
201
+ #
202
+ # attrs_first = { :name => 'sam', :zoo_id => 1 }
203
+ # attrs_second = { :name => 'tom', :zoo_id => 1 }
204
+ #
205
+ # puts 'Resource#attributes='
206
+ # TIMES.times { exhibit = Exhibit.new(attrs_first); exhibit.attributes = attrs_second }
207
+ #
208
+ # puts 'Resource#update'
209
+ # TIMES.times { |index| exhibit = exhibits[index]; exhibit.name = 'bob'; exhibit.save }
210
+ #
211
+ # puts 'Resource#destroy'
212
+ # TIMES.times { |index| exhibits[index].destroy }
213
+ #
214
+ # puts 'Model.transaction'
215
+ # TIMES.times { Exhibit.transaction { Exhibit.new } }
85
216
  end
86
217
 
87
218
  puts "Done!"