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
@@ -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