datamapper-dm-core 0.9.11 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,731 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
- if HAS_POSTGRES
4
- describe DataMapper::Adapters::PostgresAdapter do
5
- before :all do
6
- @adapter = repository(:postgres).adapter
7
- end
8
-
9
- describe "auto migrating" do
10
- before :all do
11
- class ::Sputnik
12
- include DataMapper::Resource
13
-
14
- property :id, Serial
15
- property :name, DM::Text
16
- end
17
- end
18
-
19
- it "#upgrade_model should work" do
20
- @adapter.destroy_model_storage(repository(:postgres), Sputnik)
21
- @adapter.storage_exists?("sputniks").should be_false
22
- Sputnik.auto_migrate!(:postgres)
23
- @adapter.storage_exists?("sputniks").should be_true
24
- @adapter.field_exists?("sputniks", "new_prop").should be_false
25
- Sputnik.property :new_prop, DM::Serial
26
- @adapter.send(:drop_sequence, repository(:postgres), Sputnik.new_prop)
27
- Sputnik.auto_upgrade!(:postgres)
28
- @adapter.field_exists?("sputniks", "new_prop").should == true
29
- end
30
- end
31
-
32
- describe '#312' do
33
- it "should behave sanely for time fields" do
34
-
35
- class ::Thing
36
- include DataMapper::Resource
37
- property :id, Integer, :serial => true
38
- property :created_at, Time
39
- end
40
-
41
- Thing.auto_migrate!(:postgres)
42
-
43
- repository(:postgres) do
44
- time_now = Time.now
45
-
46
- t = Thing.new
47
- t.created_at = time_now
48
-
49
- t.save
50
-
51
- t1 = Thing.first
52
- t1.created_at.should == time_now
53
- end
54
-
55
- end
56
- end
57
-
58
- describe "querying metadata" do
59
- before :all do
60
- class ::Sputnik
61
- include DataMapper::Resource
62
-
63
- property :id, Serial
64
- property :name, DM::Text
65
- end
66
-
67
- Sputnik.auto_migrate!(:postgres)
68
- end
69
-
70
- it "#storage_exists? should return true for tables that exist" do
71
- @adapter.storage_exists?("sputniks").should == true
72
- end
73
-
74
- it "#storage_exists? should return false for tables that don't exist" do
75
- @adapter.storage_exists?("space turds").should == false
76
- end
77
-
78
- it "#field_exists? should return true for columns that exist" do
79
- @adapter.field_exists?("sputniks", "name").should == true
80
- end
81
-
82
- it "#field_exists? should return false for columns that don't exist" do
83
- @adapter.field_exists?("sputniks", "plur").should == false
84
- end
85
- end
86
-
87
- describe "handling transactions" do
88
- before :all do
89
- class ::Sputnik
90
- include DataMapper::Resource
91
-
92
- property :id, Serial
93
- property :name, DM::Text
94
- end
95
-
96
- Sputnik.auto_migrate!(:postgres)
97
- end
98
-
99
- before do
100
- @transaction = DataMapper::Transaction.new(@adapter)
101
- end
102
-
103
- it "should rollback changes when #rollback_transaction is called" do
104
- @transaction.commit do |trans|
105
- @adapter.execute("INSERT INTO sputniks (name) VALUES ('my pretty sputnik')")
106
- trans.rollback
107
- end
108
- @adapter.query("SELECT * FROM sputniks WHERE name = 'my pretty sputnik'").empty?.should == true
109
- end
110
-
111
- it "should commit changes when #commit_transaction is called" do
112
- @transaction.commit do
113
- @adapter.execute("INSERT INTO sputniks (name) VALUES ('my pretty sputnik')")
114
- end
115
- @adapter.query("SELECT * FROM sputniks WHERE name = 'my pretty sputnik'").size.should == 1
116
- end
117
- end
118
-
119
- describe "reading & writing a database" do
120
- before :all do
121
- class ::User
122
- include DataMapper::Resource
123
-
124
- property :id, Serial
125
- property :name, DM::Text
126
- end
127
-
128
- class ::Voyager
129
- include DataMapper::Resource
130
- storage_names[:postgres] = 'voyagers'
131
-
132
- property :id, Serial
133
- property :age, Integer
134
- end
135
-
136
- # Voyager.auto_migrate!(:postgres)
137
- end
138
-
139
- before do
140
- User.auto_migrate!(:postgres)
141
-
142
- @adapter.execute("INSERT INTO users (name) VALUES ('Paul')")
143
- end
144
-
145
- it "should be able to specify a schema name as part of the storage name" do
146
- pending "This works, but no create-schema support in PostgresAdapter to easily test with"
147
- lambda do
148
- repository(:postgres) do
149
- Voyager.create(:age => 1_000)
150
- end
151
- end.should_not raise_error
152
- end
153
-
154
- it 'should be able to #execute an arbitrary query' do
155
- result = @adapter.execute("INSERT INTO users (name) VALUES ('Sam')")
156
-
157
- result.affected_rows.should == 1
158
- end
159
-
160
- it 'should be able to #query' do
161
- result = @adapter.query("SELECT * FROM users")
162
-
163
- result.should be_kind_of(Array)
164
- row = result.first
165
- row.should be_kind_of(Struct)
166
- row.members.map { |m| m.to_s }.should == %w{id name}
167
-
168
- row.id.should == 1
169
- row.name.should == 'Paul'
170
- end
171
-
172
- it 'should return an empty array if #query found no rows' do
173
- @adapter.execute("DELETE FROM users")
174
-
175
- result = nil
176
- lambda { result = @adapter.query("SELECT * FROM users") }.should_not raise_error
177
-
178
- result.should be_kind_of(Array)
179
- result.size.should == 0
180
- end
181
- end
182
-
183
- describe "CRUD for serial Key" do
184
- before :all do
185
- class ::VideoGame
186
- include DataMapper::Resource
187
-
188
- property :id, Serial
189
- property :name, String
190
- property :object, Object
191
- end
192
- end
193
-
194
- before do
195
- VideoGame.auto_migrate!(:postgres)
196
- end
197
-
198
- it 'should be able to create a record' do
199
- time = Time.now
200
- game = VideoGame.new(:name => 'System Shock', :object => time)
201
- repository(:postgres) do
202
- game.save
203
- game.should_not be_a_new_record
204
- game.should_not be_dirty
205
-
206
- saved = VideoGame.first(:name => game.name)
207
- saved.id.should == game.id
208
- saved.object.should == time
209
- end
210
- end
211
-
212
- it 'should be able to read a record' do
213
- name = 'Wing Commander: Privateer'
214
- id = @adapter.execute('INSERT INTO "video_games" ("name") VALUES (?) RETURNING id', name).insert_id
215
-
216
- game = repository(:postgres) do
217
- VideoGame.get(id)
218
- end
219
-
220
- game.name.should == name
221
- game.should_not be_dirty
222
- game.should_not be_a_new_record
223
- end
224
-
225
- it 'should be able to update a record' do
226
- name = 'Resistance: Fall of Mon'
227
- id = @adapter.execute('INSERT INTO "video_games" ("name") VALUES (?) RETURNING id', name).insert_id
228
-
229
- game = repository(:postgres) do
230
- VideoGame.get(id)
231
- end
232
-
233
- game.should_not be_a_new_record
234
-
235
- game.should_not be_dirty
236
- game.name = game.name.sub(/Mon/, 'Man')
237
- game.should be_dirty
238
-
239
- repository(:postgres) do
240
- game.save
241
- end
242
-
243
- game.should_not be_dirty
244
-
245
- clone = repository(:postgres) do
246
- VideoGame.get(id)
247
- end
248
-
249
- clone.name.should == game.name
250
- end
251
-
252
- it 'should be able to delete a record' do
253
- name = 'Zelda'
254
- id = @adapter.execute('INSERT INTO "video_games" ("name") VALUES (?) RETURNING id', name).insert_id
255
-
256
- game = repository(:postgres) do
257
- VideoGame.get(id)
258
- end
259
-
260
- game.name.should == name
261
-
262
- repository(:postgres) do
263
- game.destroy.should be_true
264
- end
265
-
266
- game.should be_a_new_record
267
- game.should be_dirty
268
- end
269
-
270
- it 'should respond to Resource#get' do
271
- name = 'Contra'
272
- id = @adapter.execute('INSERT INTO "video_games" ("name") VALUES (?) RETURNING id', name).insert_id
273
-
274
- contra = repository(:postgres) { VideoGame.get(id) }
275
-
276
- contra.should_not be_nil
277
- contra.should_not be_dirty
278
- contra.should_not be_a_new_record
279
- contra.id.should == id
280
- end
281
- end
282
-
283
- describe "CRUD for Composite Key" do
284
- before :all do
285
- class ::BankCustomer
286
- include DataMapper::Resource
287
-
288
- property :bank, String, :key => true
289
- property :account_number, String, :key => true
290
- property :name, String
291
- end
292
- end
293
-
294
- before do
295
- BankCustomer.auto_migrate!(:postgres)
296
- end
297
-
298
- it 'should be able to create a record' do
299
- customer = BankCustomer.new(:bank => 'Community Bank', :account_number => '123456', :name => 'David Hasselhoff')
300
- repository(:postgres) do
301
- customer.save
302
- end
303
-
304
- customer.should_not be_a_new_record
305
- customer.should_not be_dirty
306
-
307
- row = @adapter.query('SELECT "bank", "account_number" FROM "bank_customers" WHERE "name" = ?', customer.name).first
308
- row.bank.should == customer.bank
309
- row.account_number.should == customer.account_number
310
- end
311
-
312
- it 'should be able to read a record' do
313
- bank, account_number, name = 'Chase', '4321', 'Super Wonderful'
314
- @adapter.execute('INSERT INTO "bank_customers" ("bank", "account_number", "name") VALUES (?, ?, ?)', bank, account_number, name)
315
-
316
- repository(:postgres) do
317
- BankCustomer.get(bank, account_number).name.should == name
318
- end
319
- end
320
-
321
- it 'should be able to update a record' do
322
- bank, account_number, name = 'Wells Fargo', '00101001', 'Spider Pig'
323
- @adapter.execute('INSERT INTO "bank_customers" ("bank", "account_number", "name") VALUES (?, ?, ?)', bank, account_number, name)
324
-
325
- customer = repository(:postgres) do
326
- BankCustomer.get(bank, account_number)
327
- end
328
-
329
- customer.name = 'Bat-Pig'
330
-
331
- customer.should_not be_a_new_record
332
- customer.should be_dirty
333
-
334
- customer.save
335
-
336
- customer.should_not be_dirty
337
-
338
- clone = repository(:postgres) do
339
- BankCustomer.get(bank, account_number)
340
- end
341
-
342
- clone.name.should == customer.name
343
- end
344
-
345
- it 'should be able to delete a record' do
346
- bank, account_number, name = 'Megacorp', 'ABC', 'Flash Gordon'
347
- @adapter.execute('INSERT INTO "bank_customers" ("bank", "account_number", "name") VALUES (?, ?, ?)', bank, account_number, name)
348
-
349
- customer = repository(:postgres) do
350
- BankCustomer.get(bank, account_number)
351
- end
352
-
353
- customer.name.should == name
354
-
355
- repository(:postgres) do
356
- customer.destroy.should be_true
357
- end
358
-
359
- customer.should be_a_new_record
360
- customer.should be_dirty
361
- end
362
-
363
- it 'should respond to Resource#get' do
364
- bank, account_number, name = 'Conchords', '1100101', 'Robo Boogie'
365
- @adapter.execute('INSERT INTO "bank_customers" ("bank", "account_number", "name") VALUES (?, ?, ?)', bank, account_number, name)
366
-
367
- robots = repository(:postgres) { BankCustomer.get(bank, account_number) }
368
-
369
- robots.should_not be_nil
370
- robots.should_not be_dirty
371
- robots.should_not be_a_new_record
372
- robots.bank.should == bank
373
- robots.account_number.should == account_number
374
- end
375
- end
376
-
377
- describe "Ordering a Query" do
378
- before :all do
379
- class ::SailBoat
380
- include DataMapper::Resource
381
- property :id, Serial
382
- property :name, String
383
- property :port, String
384
- end
385
- end
386
-
387
- before do
388
- SailBoat.auto_migrate!(:postgres)
389
-
390
- repository(:postgres) do
391
- SailBoat.create(:id => 1, :name => "A", :port => "C")
392
- SailBoat.create(:id => 2, :name => "B", :port => "B")
393
- SailBoat.create(:id => 3, :name => "C", :port => "A")
394
- end
395
- end
396
-
397
- it "should order results" do
398
- repository(:postgres) do
399
- result = SailBoat.all(:order => [
400
- DataMapper::Query::Direction.new(SailBoat.properties[:name], :asc)
401
- ])
402
- result[0].id.should == 1
403
-
404
- result = SailBoat.all(:order => [
405
- DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
406
- ])
407
- result[0].id.should == 3
408
-
409
- result = SailBoat.all(:order => [
410
- DataMapper::Query::Direction.new(SailBoat.properties[:name], :asc),
411
- DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
412
- ])
413
- result[0].id.should == 1
414
-
415
- result = SailBoat.all(:order => [
416
- SailBoat.properties[:name],
417
- DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
418
- ])
419
- result[0].id.should == 1
420
- end
421
- end
422
- end
423
-
424
- describe "Lazy Loaded Properties" do
425
- before :all do
426
- class ::SailBoat
427
- include DataMapper::Resource
428
- property :id, Serial
429
- property :notes, String, :lazy => [:notes]
430
- property :trip_report, String, :lazy => [:notes,:trip]
431
- property :miles, Integer, :lazy => [:trip]
432
- end
433
- end
434
-
435
- before do
436
- SailBoat.auto_migrate!(:postgres)
437
-
438
- repository(:postgres) do
439
- SailBoat.create(:id => 1, :notes=>'Note',:trip_report=>'Report',:miles=>23)
440
- SailBoat.create(:id => 2, :notes=>'Note',:trip_report=>'Report',:miles=>23)
441
- SailBoat.create(:id => 3, :notes=>'Note',:trip_report=>'Report',:miles=>23)
442
- end
443
- end
444
-
445
- it "should lazy load" do
446
- result = repository(:postgres) { SailBoat.all.to_a }
447
-
448
- result[0].attribute_loaded?(:notes).should be_false
449
- result[0].attribute_loaded?(:trip_report).should be_false
450
- result[1].attribute_loaded?(:notes).should be_false
451
-
452
- result[1].notes.should_not be_nil
453
-
454
- result[1].attribute_loaded?(:notes).should be_true
455
- result[1].attribute_loaded?(:trip_report).should be_true
456
- result[1].attribute_loaded?(:miles).should be_false
457
-
458
- result = repository(:postgres) { SailBoat.all.to_a }
459
-
460
- result[0].attribute_loaded?(:trip_report).should be_false
461
- result[0].attribute_loaded?(:miles).should be_false
462
-
463
- result[1].trip_report.should_not be_nil
464
- result[2].attribute_loaded?(:miles).should be_true
465
- end
466
- end
467
-
468
- describe "finders" do
469
- before :all do
470
- class ::SerialFinderSpec
471
- include DataMapper::Resource
472
-
473
- property :id, Serial
474
- property :sample, String
475
- end
476
- end
477
-
478
- before do
479
- SerialFinderSpec.auto_migrate!(:postgres)
480
-
481
- repository(:postgres) do
482
- 100.times do
483
- SerialFinderSpec.create(:sample => rand.to_s)
484
- end
485
- end
486
- end
487
-
488
- it "should return all available rows" do
489
- repository(:postgres) do
490
- SerialFinderSpec.all.should have(100).entries
491
- end
492
- end
493
-
494
- it "should allow limit and offset" do
495
- repository(:postgres) do
496
- SerialFinderSpec.all(:limit => 50).should have(50).entries
497
-
498
- SerialFinderSpec.all(:limit => 20, :offset => 40).map { |entry| entry.id }.should == SerialFinderSpec.all[40...60].map { |entry| entry.id }
499
- end
500
- end
501
-
502
- it "should lazy-load missing attributes" do
503
- sfs = repository(:postgres) do
504
- SerialFinderSpec.first(:fields => [ :id ])
505
- end
506
-
507
- sfs.should be_a_kind_of(SerialFinderSpec)
508
- sfs.should_not be_a_new_record
509
-
510
- sfs.attribute_loaded?(:sample).should be_false
511
- sfs.sample
512
- sfs.attribute_loaded?(:sample).should be_true
513
- end
514
-
515
- it "should translate an Array to an IN clause" do
516
- ids = repository(:postgres) do
517
- SerialFinderSpec.all(:limit => 10).map { |entry| entry.id }
518
- end
519
-
520
- results = repository(:postgres) do
521
- SerialFinderSpec.all(:id => ids)
522
- end
523
-
524
- results.size.should == 10
525
- results.map { |entry| entry.id }.should == ids
526
- end
527
- end
528
-
529
- describe "belongs_to associations" do
530
- before :all do
531
- class ::Engine
532
- include DataMapper::Resource
533
- def self.default_repository_name; :postgres end
534
-
535
- property :id, Serial
536
- property :name, String
537
- end
538
-
539
- class ::Yard
540
- include DataMapper::Resource
541
- def self.default_repository_name; :postgres end
542
-
543
- property :id, Serial
544
- property :name, String
545
- property :engine_id, Integer
546
-
547
- belongs_to :engine
548
- end
549
- end
550
-
551
- before do
552
- Engine.auto_migrate!(:postgres)
553
-
554
- @adapter.execute('INSERT INTO "engines" ("id", "name") values (?, ?)', 1, 'engine1')
555
- @adapter.execute('INSERT INTO "engines" ("id", "name") values (?, ?)', 2, 'engine2')
556
-
557
- Yard.auto_migrate!(:postgres)
558
-
559
- @adapter.execute('INSERT INTO "yards" ("id", "name", "engine_id") values (?, ?, ?)', 1, 'yard1', 1)
560
- end
561
-
562
- it "should load without the parent"
563
-
564
- it 'should allow substituting the parent' do
565
- repository(:postgres) do
566
- y = Yard.first(:id => 1)
567
- e = Engine.first(:id => 2)
568
- y.engine = e
569
- y.save
570
- end
571
-
572
- repository(:postgres) do
573
- Yard.first(:id => 1).engine_id.should == 2
574
- end
575
- end
576
-
577
- it "#belongs_to" do
578
- yard = Yard.new
579
- yard.should respond_to(:engine)
580
- yard.should respond_to(:engine=)
581
- end
582
-
583
- it "should load the associated instance" do
584
- y = repository(:postgres) do
585
- Yard.first(:id => 1)
586
- end
587
- y.engine.should_not be_nil
588
- y.engine.id.should == 1
589
- y.engine.name.should == "engine1"
590
- end
591
-
592
- it 'should save the association key in the child' do
593
- repository(:postgres) do
594
- e = Engine.first(:id => 2)
595
- Yard.create(:id => 2, :name => 'yard2', :engine => e)
596
- end
597
-
598
- repository(:postgres) do
599
- Yard.first(:id => 2).engine_id.should == 2
600
- end
601
- end
602
-
603
- it 'should save the parent upon saving of child' do
604
- repository(:postgres) do
605
- e = Engine.new(:id => 10, :name => "engine10")
606
- y = Yard.new(:id => 10, :name => "Yard10", :engine => e)
607
- y.save
608
-
609
- y.engine_id.should == 10
610
- end
611
-
612
- repository(:postgres) do
613
- Engine.first(:id => 10).should_not be_nil
614
- end
615
- end
616
- end
617
-
618
- describe "has n associations" do
619
- before :all do
620
- class ::Host
621
- include DataMapper::Resource
622
- def self.default_repository_name; :postgres end
623
-
624
- property :id, Serial
625
- property :name, String
626
-
627
- has n, :slices
628
- end
629
-
630
- class ::Slice
631
- include DataMapper::Resource
632
- def self.default_repository_name; :postgres end
633
-
634
- property :id, Serial
635
- property :name, String
636
- property :host_id, Integer
637
-
638
- belongs_to :host
639
- end
640
- end
641
-
642
- before do
643
- Host.auto_migrate!(:postgres)
644
- Slice.auto_migrate!(:postgres)
645
-
646
- @adapter.execute('INSERT INTO "hosts" ("id", "name") values (?, ?)', 1, 'host1')
647
- @adapter.execute('INSERT INTO "hosts" ("id", "name") values (?, ?)', 2, 'host2')
648
-
649
- @adapter.execute('INSERT INTO "slices" ("id", "name", "host_id") values (?, ?, ?)', 1, 'slice1', 1)
650
- @adapter.execute('INSERT INTO "slices" ("id", "name", "host_id") values (?, ?, ?)', 2, 'slice2', 1)
651
- end
652
-
653
- it "#has n" do
654
- h = Host.new
655
- h.should respond_to(:slices)
656
- end
657
-
658
- it "should allow removal of a child through a loaded association" do
659
- h = repository(:postgres) do
660
- Host.first(:id => 1)
661
- end
662
-
663
- s = h.slices.first
664
-
665
- h.slices.delete(s)
666
- h.slices.size.should == 1
667
- h.save
668
-
669
- s = repository(:postgres) do
670
- Slice.first(:id => s.id)
671
- end
672
-
673
- s.host.should be_nil
674
- s.host_id.should be_nil
675
- end
676
-
677
- it "should load the associated instances" do
678
- h = repository(:postgres) do
679
- Host.first(:id => 1)
680
- end
681
-
682
- h.slices.should_not be_nil
683
- h.slices.size.should == 2
684
- h.slices.first.id.should == 1
685
- h.slices.last.id.should == 2
686
- end
687
-
688
- it "should add and save the associated instance" do
689
- repository(:postgres) do
690
- h = Host.first(:id => 1)
691
-
692
- h.slices << Slice.new(:id => 3, :name => 'slice3')
693
- h.save
694
-
695
- s = repository(:postgres) do
696
- Slice.first(:id => 3)
697
- end
698
-
699
- s.host.id.should == 1
700
- end
701
- end
702
-
703
- it "should not save the associated instance if the parent is not saved" do
704
- repository(:postgres) do
705
- h = Host.new(:id => 10, :name => "host10")
706
- h.slices << Slice.new(:id => 10, :name => 'slice10')
707
- end
708
-
709
- repository(:postgres) do
710
- Slice.first(:id => 10).should be_nil
711
- end
712
- end
713
-
714
- it "should save the associated instance upon saving of parent" do
715
- repository(:postgres) do
716
- h = Host.new(:id => 10, :name => "host10")
717
- h.slices << Slice.new(:id => 10, :name => 'slice10')
718
- h.save
719
- end
720
-
721
- s = repository(:postgres) do
722
- Slice.first(:id => 10)
723
- end
724
-
725
- s.should_not be_nil
726
- s.host.should_not be_nil
727
- s.host.id.should == 10
728
- end
729
- end
730
- end
731
- end