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.
- data/.autotest +17 -14
- data/.gitignore +3 -1
- data/FAQ +6 -5
- data/History.txt +5 -39
- data/Manifest.txt +67 -76
- data/QUICKLINKS +1 -1
- data/README.txt +21 -15
- data/Rakefile +16 -15
- data/SPECS +2 -29
- data/TODO +1 -1
- data/dm-core.gemspec +11 -15
- data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
- data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
- data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
- data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
- data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
- data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
- data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
- data/lib/dm-core/adapters.rb +135 -16
- data/lib/dm-core/associations/many_to_many.rb +372 -90
- data/lib/dm-core/associations/many_to_one.rb +220 -73
- data/lib/dm-core/associations/one_to_many.rb +319 -255
- data/lib/dm-core/associations/one_to_one.rb +66 -53
- data/lib/dm-core/associations/relationship.rb +560 -158
- data/lib/dm-core/collection.rb +1104 -381
- data/lib/dm-core/core_ext/kernel.rb +12 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +4 -34
- data/lib/dm-core/migrations.rb +1283 -0
- data/lib/dm-core/model/descendant_set.rb +81 -0
- data/lib/dm-core/model/hook.rb +45 -0
- data/lib/dm-core/model/is.rb +32 -0
- data/lib/dm-core/model/property.rb +248 -0
- data/lib/dm-core/model/relationship.rb +335 -0
- data/lib/dm-core/model/scope.rb +90 -0
- data/lib/dm-core/model.rb +570 -369
- data/lib/dm-core/property.rb +753 -280
- data/lib/dm-core/property_set.rb +141 -98
- data/lib/dm-core/query/conditions/comparison.rb +814 -0
- data/lib/dm-core/query/conditions/operation.rb +247 -0
- data/lib/dm-core/query/direction.rb +43 -0
- data/lib/dm-core/query/operator.rb +42 -0
- data/lib/dm-core/query/path.rb +102 -0
- data/lib/dm-core/query/sort.rb +45 -0
- data/lib/dm-core/query.rb +974 -492
- data/lib/dm-core/repository.rb +147 -107
- data/lib/dm-core/resource.rb +644 -429
- data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
- data/lib/dm-core/support/chainable.rb +20 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/equalizer.rb +23 -0
- data/lib/dm-core/support/logger.rb +13 -0
- data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
- data/lib/dm-core/transaction.rb +333 -92
- data/lib/dm-core/type.rb +98 -60
- data/lib/dm-core/types/boolean.rb +1 -1
- data/lib/dm-core/types/discriminator.rb +34 -20
- data/lib/dm-core/types/object.rb +7 -4
- data/lib/dm-core/types/paranoid_boolean.rb +11 -9
- data/lib/dm-core/types/paranoid_datetime.rb +11 -9
- data/lib/dm-core/types/serial.rb +3 -3
- data/lib/dm-core/types/text.rb +3 -4
- data/lib/dm-core/version.rb +1 -1
- data/lib/dm-core.rb +106 -110
- data/script/performance.rb +102 -109
- data/script/profile.rb +169 -38
- data/spec/lib/adapter_helpers.rb +105 -0
- data/spec/lib/collection_helpers.rb +18 -0
- data/spec/lib/counter_adapter.rb +34 -0
- data/spec/lib/pending_helpers.rb +27 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
- data/spec/public/associations/many_to_many_spec.rb +193 -0
- data/spec/public/associations/many_to_one_spec.rb +73 -0
- data/spec/public/associations/one_to_many_spec.rb +77 -0
- data/spec/public/associations/one_to_one_spec.rb +156 -0
- data/spec/public/collection_spec.rb +65 -0
- data/spec/public/model/relationship_spec.rb +924 -0
- data/spec/public/model_spec.rb +159 -0
- data/spec/public/property_spec.rb +829 -0
- data/spec/public/resource_spec.rb +71 -0
- data/spec/public/sel_spec.rb +44 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +317 -0
- data/spec/public/shared/collection_shared_spec.rb +1723 -0
- data/spec/public/shared/finder_shared_spec.rb +1619 -0
- data/spec/public/shared/resource_shared_spec.rb +924 -0
- data/spec/public/shared/sel_shared_spec.rb +112 -0
- data/spec/public/transaction_spec.rb +129 -0
- data/spec/public/types/discriminator_spec.rb +130 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +194 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +142 -0
- data/spec/semipublic/property_spec.rb +61 -0
- data/spec/semipublic/query/conditions_spec.rb +528 -0
- data/spec/semipublic/query/path_spec.rb +443 -0
- data/spec/semipublic/query_spec.rb +2626 -0
- data/spec/semipublic/resource_spec.rb +47 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
- data/spec/spec.opts +3 -1
- data/spec/spec_helper.rb +80 -57
- data/tasks/ci.rb +19 -31
- data/tasks/dm.rb +43 -48
- data/tasks/doc.rb +8 -11
- data/tasks/gemspec.rb +5 -5
- data/tasks/hoe.rb +15 -16
- data/tasks/install.rb +8 -10
- metadata +72 -93
- data/lib/dm-core/associations/relationship_chain.rb +0 -81
- data/lib/dm-core/associations.rb +0 -207
- data/lib/dm-core/auto_migrations.rb +0 -105
- data/lib/dm-core/dependency_queue.rb +0 -32
- data/lib/dm-core/hook.rb +0 -11
- data/lib/dm-core/is.rb +0 -16
- data/lib/dm-core/logger.rb +0 -232
- data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
- data/lib/dm-core/migrator.rb +0 -29
- data/lib/dm-core/scope.rb +0 -58
- data/lib/dm-core/support/array.rb +0 -13
- data/lib/dm-core/support/assertions.rb +0 -8
- data/lib/dm-core/support/errors.rb +0 -23
- data/lib/dm-core/support/kernel.rb +0 -11
- data/lib/dm-core/support/symbol.rb +0 -41
- data/lib/dm-core/support.rb +0 -7
- data/lib/dm-core/type_map.rb +0 -80
- data/lib/dm-core/types.rb +0 -19
- data/script/all +0 -4
- data/spec/integration/association_spec.rb +0 -1382
- data/spec/integration/association_through_spec.rb +0 -203
- data/spec/integration/associations/many_to_many_spec.rb +0 -449
- data/spec/integration/associations/many_to_one_spec.rb +0 -163
- data/spec/integration/associations/one_to_many_spec.rb +0 -188
- data/spec/integration/auto_migrations_spec.rb +0 -413
- data/spec/integration/collection_spec.rb +0 -1073
- data/spec/integration/data_objects_adapter_spec.rb +0 -32
- data/spec/integration/dependency_queue_spec.rb +0 -46
- data/spec/integration/model_spec.rb +0 -197
- data/spec/integration/mysql_adapter_spec.rb +0 -85
- data/spec/integration/postgres_adapter_spec.rb +0 -731
- data/spec/integration/property_spec.rb +0 -253
- data/spec/integration/query_spec.rb +0 -514
- data/spec/integration/repository_spec.rb +0 -61
- data/spec/integration/resource_spec.rb +0 -513
- data/spec/integration/sqlite3_adapter_spec.rb +0 -352
- data/spec/integration/sti_spec.rb +0 -273
- data/spec/integration/strategic_eager_loading_spec.rb +0 -156
- data/spec/integration/transaction_spec.rb +0 -75
- data/spec/integration/type_spec.rb +0 -275
- data/spec/lib/logging_helper.rb +0 -18
- data/spec/lib/mock_adapter.rb +0 -27
- data/spec/lib/model_loader.rb +0 -100
- data/spec/lib/publicize_methods.rb +0 -28
- data/spec/models/content.rb +0 -16
- data/spec/models/vehicles.rb +0 -34
- data/spec/models/zoo.rb +0 -48
- data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
- data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
- data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
- data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
- data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
- data/spec/unit/associations/many_to_many_spec.rb +0 -32
- data/spec/unit/associations/many_to_one_spec.rb +0 -159
- data/spec/unit/associations/one_to_many_spec.rb +0 -393
- data/spec/unit/associations/one_to_one_spec.rb +0 -7
- data/spec/unit/associations/relationship_spec.rb +0 -71
- data/spec/unit/associations_spec.rb +0 -242
- data/spec/unit/auto_migrations_spec.rb +0 -111
- data/spec/unit/collection_spec.rb +0 -182
- data/spec/unit/data_mapper_spec.rb +0 -35
- data/spec/unit/identity_map_spec.rb +0 -126
- data/spec/unit/is_spec.rb +0 -80
- data/spec/unit/migrator_spec.rb +0 -33
- data/spec/unit/model_spec.rb +0 -321
- data/spec/unit/naming_conventions_spec.rb +0 -36
- data/spec/unit/property_set_spec.rb +0 -90
- data/spec/unit/property_spec.rb +0 -753
- data/spec/unit/query_spec.rb +0 -571
- data/spec/unit/repository_spec.rb +0 -93
- data/spec/unit/resource_spec.rb +0 -649
- data/spec/unit/scope_spec.rb +0 -142
- data/spec/unit/transaction_spec.rb +0 -493
- data/spec/unit/type_map_spec.rb +0 -114
- 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
|