dm-core 0.9.2
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/CHANGELOG +144 -0
- data/FAQ +74 -0
- data/MIT-LICENSE +22 -0
- data/QUICKLINKS +12 -0
- data/README +143 -0
- data/lib/dm-core.rb +213 -0
- data/lib/dm-core/adapters.rb +4 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
- data/lib/dm-core/adapters/data_objects_adapter.rb +701 -0
- data/lib/dm-core/adapters/mysql_adapter.rb +132 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +179 -0
- data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
- data/lib/dm-core/associations.rb +172 -0
- data/lib/dm-core/associations/many_to_many.rb +138 -0
- data/lib/dm-core/associations/many_to_one.rb +101 -0
- data/lib/dm-core/associations/one_to_many.rb +275 -0
- data/lib/dm-core/associations/one_to_one.rb +61 -0
- data/lib/dm-core/associations/relationship.rb +116 -0
- data/lib/dm-core/associations/relationship_chain.rb +74 -0
- data/lib/dm-core/auto_migrations.rb +64 -0
- data/lib/dm-core/collection.rb +604 -0
- data/lib/dm-core/hook.rb +11 -0
- data/lib/dm-core/identity_map.rb +45 -0
- data/lib/dm-core/is.rb +16 -0
- data/lib/dm-core/logger.rb +233 -0
- data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
- data/lib/dm-core/migrator.rb +29 -0
- data/lib/dm-core/model.rb +399 -0
- data/lib/dm-core/naming_conventions.rb +52 -0
- data/lib/dm-core/property.rb +611 -0
- data/lib/dm-core/property_set.rb +158 -0
- data/lib/dm-core/query.rb +590 -0
- data/lib/dm-core/repository.rb +159 -0
- data/lib/dm-core/resource.rb +618 -0
- data/lib/dm-core/scope.rb +35 -0
- data/lib/dm-core/support.rb +7 -0
- data/lib/dm-core/support/array.rb +13 -0
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/errors.rb +23 -0
- data/lib/dm-core/support/kernel.rb +7 -0
- data/lib/dm-core/support/symbol.rb +41 -0
- data/lib/dm-core/transaction.rb +267 -0
- data/lib/dm-core/type.rb +160 -0
- data/lib/dm-core/type_map.rb +80 -0
- data/lib/dm-core/types.rb +19 -0
- data/lib/dm-core/types/boolean.rb +7 -0
- data/lib/dm-core/types/discriminator.rb +32 -0
- data/lib/dm-core/types/object.rb +20 -0
- data/lib/dm-core/types/paranoid_boolean.rb +23 -0
- data/lib/dm-core/types/paranoid_datetime.rb +22 -0
- data/lib/dm-core/types/serial.rb +9 -0
- data/lib/dm-core/types/text.rb +10 -0
- data/spec/integration/association_spec.rb +1215 -0
- data/spec/integration/association_through_spec.rb +150 -0
- data/spec/integration/associations/many_to_many_spec.rb +171 -0
- data/spec/integration/associations/many_to_one_spec.rb +123 -0
- data/spec/integration/associations/one_to_many_spec.rb +66 -0
- data/spec/integration/auto_migrations_spec.rb +398 -0
- data/spec/integration/collection_spec.rb +1015 -0
- data/spec/integration/data_objects_adapter_spec.rb +32 -0
- data/spec/integration/model_spec.rb +68 -0
- data/spec/integration/mysql_adapter_spec.rb +85 -0
- data/spec/integration/postgres_adapter_spec.rb +732 -0
- data/spec/integration/property_spec.rb +224 -0
- data/spec/integration/query_spec.rb +376 -0
- data/spec/integration/repository_spec.rb +57 -0
- data/spec/integration/resource_spec.rb +324 -0
- data/spec/integration/sqlite3_adapter_spec.rb +352 -0
- data/spec/integration/sti_spec.rb +185 -0
- data/spec/integration/transaction_spec.rb +75 -0
- data/spec/integration/type_spec.rb +149 -0
- data/spec/lib/mock_adapter.rb +27 -0
- data/spec/spec_helper.rb +112 -0
- data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
- data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
- data/spec/unit/adapters/data_objects_adapter_spec.rb +627 -0
- data/spec/unit/adapters/postgres_adapter_spec.rb +125 -0
- data/spec/unit/associations/many_to_many_spec.rb +14 -0
- data/spec/unit/associations/many_to_one_spec.rb +138 -0
- data/spec/unit/associations/one_to_many_spec.rb +385 -0
- data/spec/unit/associations/one_to_one_spec.rb +7 -0
- data/spec/unit/associations/relationship_spec.rb +67 -0
- data/spec/unit/associations_spec.rb +205 -0
- data/spec/unit/auto_migrations_spec.rb +110 -0
- data/spec/unit/collection_spec.rb +174 -0
- data/spec/unit/data_mapper_spec.rb +21 -0
- data/spec/unit/identity_map_spec.rb +126 -0
- data/spec/unit/is_spec.rb +80 -0
- data/spec/unit/migrator_spec.rb +33 -0
- data/spec/unit/model_spec.rb +339 -0
- data/spec/unit/naming_conventions_spec.rb +28 -0
- data/spec/unit/property_set_spec.rb +96 -0
- data/spec/unit/property_spec.rb +447 -0
- data/spec/unit/query_spec.rb +485 -0
- data/spec/unit/repository_spec.rb +93 -0
- data/spec/unit/resource_spec.rb +557 -0
- data/spec/unit/scope_spec.rb +131 -0
- data/spec/unit/transaction_spec.rb +493 -0
- data/spec/unit/type_map_spec.rb +114 -0
- data/spec/unit/type_spec.rb +119 -0
- metadata +187 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
gem 'fastercsv', '>=1.2.3'
|
|
4
|
+
require 'fastercsv'
|
|
5
|
+
|
|
6
|
+
if ADAPTER
|
|
7
|
+
describe DataMapper::Property, "with #{ADAPTER}" do
|
|
8
|
+
describe " tracking strategies" do
|
|
9
|
+
before :all do
|
|
10
|
+
class Actor
|
|
11
|
+
include DataMapper::Resource
|
|
12
|
+
|
|
13
|
+
property :id, Serial
|
|
14
|
+
property :name, String, :track => :set # :track default is :get for mutable types
|
|
15
|
+
property :notes, DataMapper::Types::Text
|
|
16
|
+
property :age, Integer # :track default is :set for mutable types
|
|
17
|
+
property :rating, Integer
|
|
18
|
+
property :location, String
|
|
19
|
+
property :lead, TrueClass, :track => :load
|
|
20
|
+
property :cv, Object # :track should be :hash
|
|
21
|
+
property :agent, String, :track => :hash # :track only Object#hash value on :load.
|
|
22
|
+
# Potentially faster, but less safe, so use judiciously, when the odds of a hash-collision are low.
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
before do
|
|
27
|
+
Actor.auto_migrate!(ADAPTER)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should set up tracking information" do
|
|
31
|
+
Actor.properties[:name].track.should == :set
|
|
32
|
+
Actor.properties[:location].track.should == :get
|
|
33
|
+
Actor.properties[:rating].track.should == :set
|
|
34
|
+
Actor.properties[:lead].track.should == :load
|
|
35
|
+
Actor.properties[:cv].track.should == :hash
|
|
36
|
+
Actor.properties[:agent].track.should == :hash
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should track on :set" do
|
|
40
|
+
repository(ADAPTER) do
|
|
41
|
+
bob = Actor.new(:name => 'bob')
|
|
42
|
+
bob.save
|
|
43
|
+
|
|
44
|
+
bob.original_values.should_not have_key(:name)
|
|
45
|
+
bob.dirty?.should == false
|
|
46
|
+
|
|
47
|
+
bob.name = "Bob"
|
|
48
|
+
bob.original_values.should have_key(:name)
|
|
49
|
+
bob.original_values[:name].should == 'bob'
|
|
50
|
+
bob.dirty?.should == true
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should track on :get" do
|
|
55
|
+
repository(ADAPTER) do
|
|
56
|
+
jon = Actor.new(:name => 'jon', :location => 'dallas')
|
|
57
|
+
jon.save
|
|
58
|
+
|
|
59
|
+
jon.location
|
|
60
|
+
jon.original_values.should have_key(:location)
|
|
61
|
+
jon.original_values[:location].should == 'dallas'
|
|
62
|
+
|
|
63
|
+
jon.dirty?.should be_false
|
|
64
|
+
jon.save.should be_false
|
|
65
|
+
|
|
66
|
+
jon.location.upcase!
|
|
67
|
+
jon.location.should == 'DALLAS'
|
|
68
|
+
jon.original_values[:location].should == 'dallas'
|
|
69
|
+
|
|
70
|
+
jon.dirty?.should be_true
|
|
71
|
+
jon.save.should be_true
|
|
72
|
+
|
|
73
|
+
jon.location << '!'
|
|
74
|
+
jon.original_values[:location].should == 'DALLAS'
|
|
75
|
+
jon.dirty?.should be_true
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "should track on :load" do
|
|
80
|
+
repository(ADAPTER) do
|
|
81
|
+
jan = Actor.create!(:name => 'jan', :lead => true)
|
|
82
|
+
jan.lead = false
|
|
83
|
+
jan.original_values[:lead].should be_true
|
|
84
|
+
jan.dirty?.should == true
|
|
85
|
+
end
|
|
86
|
+
repository(ADAPTER) do
|
|
87
|
+
jan = Actor.first
|
|
88
|
+
jan.original_values.should have_key(:lead)
|
|
89
|
+
jan.original_values[:lead].should be_true
|
|
90
|
+
jan.dirty?.should == false
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "should track on :hash" do
|
|
95
|
+
cv = { 2005 => "Othello" }
|
|
96
|
+
repository(ADAPTER) do
|
|
97
|
+
tom = Actor.create!(:name => 'tom', :cv => cv)
|
|
98
|
+
end
|
|
99
|
+
repository(ADAPTER) do
|
|
100
|
+
tom = Actor.first(:name => 'tom')
|
|
101
|
+
tom.cv.merge!({2006 => "Macbeth"})
|
|
102
|
+
|
|
103
|
+
tom.original_values.should have_key(:cv)
|
|
104
|
+
# tom.original_values[:cv].should == cv.hash
|
|
105
|
+
tom.cv.should == { 2005 => "Othello", 2006 => "Macbeth" }
|
|
106
|
+
tom.dirty?.should == true
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "should track with lazy text fields (#342)" do
|
|
111
|
+
repository(ADAPTER) do
|
|
112
|
+
tim = Actor.create!(:name => 'tim')
|
|
113
|
+
end
|
|
114
|
+
repository(ADAPTER) do
|
|
115
|
+
tim = Actor.first(:name => 'tim')
|
|
116
|
+
tim.notes # make sure they're loaded...
|
|
117
|
+
tim.dirty?.should be_false
|
|
118
|
+
tim.save.should be_false
|
|
119
|
+
tim.notes = "Testing"
|
|
120
|
+
tim.dirty?.should be_true
|
|
121
|
+
tim.save
|
|
122
|
+
end
|
|
123
|
+
repository(ADAPTER) do
|
|
124
|
+
tim = Actor.first(:name => 'tim')
|
|
125
|
+
tim.notes.should == "Testing"
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
describe "lazy loading" do
|
|
131
|
+
before :all do
|
|
132
|
+
class RowBoat
|
|
133
|
+
include DataMapper::Resource
|
|
134
|
+
property :id, Serial
|
|
135
|
+
property :notes, String, :lazy => [:notes]
|
|
136
|
+
property :trip_report, String, :lazy => [:notes,:trip]
|
|
137
|
+
property :miles, Integer, :lazy => [:trip]
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
before do
|
|
142
|
+
RowBoat.auto_migrate!(ADAPTER)
|
|
143
|
+
|
|
144
|
+
repository(ADAPTER) do
|
|
145
|
+
RowBoat.create!(:id => 1, :notes=>'Note',:trip_report=>'Report',:miles=>23)
|
|
146
|
+
RowBoat.create!(:id => 2, :notes=>'Note',:trip_report=>'Report',:miles=>23)
|
|
147
|
+
RowBoat.create!(:id => 3, :notes=>'Note',:trip_report=>'Report',:miles=>23)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "should lazy load in context" do
|
|
152
|
+
result = repository(ADAPTER) { RowBoat.all.to_a }
|
|
153
|
+
|
|
154
|
+
result[0].attribute_loaded?(:notes).should be_false
|
|
155
|
+
result[0].attribute_loaded?(:trip_report).should be_false
|
|
156
|
+
result[1].attribute_loaded?(:notes).should be_false
|
|
157
|
+
|
|
158
|
+
result[0].notes.should_not be_nil
|
|
159
|
+
|
|
160
|
+
result[1].attribute_loaded?(:notes).should be_true
|
|
161
|
+
result[1].attribute_loaded?(:trip_report).should be_true
|
|
162
|
+
result[1].attribute_loaded?(:miles).should be_false
|
|
163
|
+
|
|
164
|
+
result = repository(ADAPTER) { RowBoat.all.to_a }
|
|
165
|
+
|
|
166
|
+
result[0].attribute_loaded?(:trip_report).should be_false
|
|
167
|
+
result[0].attribute_loaded?(:miles).should be_false
|
|
168
|
+
|
|
169
|
+
result[1].trip_report.should_not be_nil
|
|
170
|
+
result[2].attribute_loaded?(:miles).should be_true
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
describe 'defaults' do
|
|
175
|
+
before :all do
|
|
176
|
+
class Catamaran
|
|
177
|
+
include DataMapper::Resource
|
|
178
|
+
property :id, Serial
|
|
179
|
+
property :name, String
|
|
180
|
+
|
|
181
|
+
# Boolean
|
|
182
|
+
property :could_be_bool0, TrueClass, :default => true
|
|
183
|
+
property :could_be_bool1, TrueClass, :default => false
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
repository(ADAPTER){ Catamaran.auto_migrate!(ADAPTER) }
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
before :each do
|
|
190
|
+
@cat = Catamaran.new
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it "should have defaults" do
|
|
194
|
+
@cat.could_be_bool0.should == true
|
|
195
|
+
@cat.could_be_bool1.should_not be_nil
|
|
196
|
+
@cat.could_be_bool1.should == false
|
|
197
|
+
|
|
198
|
+
@cat.name = 'Mary Mayweather'
|
|
199
|
+
|
|
200
|
+
repository(ADAPTER) do
|
|
201
|
+
@cat.save
|
|
202
|
+
|
|
203
|
+
cat = Catamaran.first
|
|
204
|
+
cat.could_be_bool0.should == true
|
|
205
|
+
cat.could_be_bool1.should_not be_nil
|
|
206
|
+
cat.could_be_bool1.should == false
|
|
207
|
+
cat.destroy
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "should have defaults even with creates" do
|
|
213
|
+
repository(ADAPTER) do
|
|
214
|
+
Catamaran.create!(:name => 'Jingle All The Way')
|
|
215
|
+
cat = Catamaran.first
|
|
216
|
+
cat.name.should == 'Jingle All The Way'
|
|
217
|
+
cat.could_be_bool0.should == true
|
|
218
|
+
cat.could_be_bool1.should_not be_nil
|
|
219
|
+
cat.could_be_bool1.should == false
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
if ADAPTER
|
|
4
|
+
describe DataMapper::Query, "with #{ADAPTER}" do
|
|
5
|
+
describe 'when ordering' do
|
|
6
|
+
before :all do
|
|
7
|
+
class SailBoat
|
|
8
|
+
include DataMapper::Resource
|
|
9
|
+
property :id, Serial
|
|
10
|
+
property :name, String
|
|
11
|
+
property :port, String
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
before do
|
|
16
|
+
SailBoat.auto_migrate!(ADAPTER)
|
|
17
|
+
|
|
18
|
+
repository(ADAPTER) do
|
|
19
|
+
SailBoat.create!(:name => 'A', :port => 'C')
|
|
20
|
+
SailBoat.create!(:name => 'B', :port => 'B')
|
|
21
|
+
SailBoat.create!(:name => 'C', :port => 'A')
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should find by conditions" do
|
|
26
|
+
lambda do
|
|
27
|
+
repository(ADAPTER) do
|
|
28
|
+
SailBoat.first(:conditions => ['name = ?', 'B'])
|
|
29
|
+
end
|
|
30
|
+
end.should_not raise_error
|
|
31
|
+
|
|
32
|
+
lambda do
|
|
33
|
+
repository(ADAPTER) do
|
|
34
|
+
SailBoat.first(:conditions => ['name = ?', 'A'])
|
|
35
|
+
end
|
|
36
|
+
end.should_not raise_error
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should find by conditions passed in as hash" do
|
|
40
|
+
repository(ADAPTER) do
|
|
41
|
+
SailBoat.create!(:name => "couldbe@email.com", :port => 'wee')
|
|
42
|
+
|
|
43
|
+
find = SailBoat.first(:name => 'couldbe@email.com')
|
|
44
|
+
find.name.should == 'couldbe@email.com'
|
|
45
|
+
|
|
46
|
+
find = SailBoat.first(:name => 'couldbe@email.com', :port.not => nil)
|
|
47
|
+
find.should_not be_nil
|
|
48
|
+
find.port.should_not be_nil
|
|
49
|
+
find.name.should == 'couldbe@email.com'
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should find by conditions passed in a range" do
|
|
54
|
+
repository(ADAPTER) do
|
|
55
|
+
find = SailBoat.all(:id => 0..2)
|
|
56
|
+
find.should_not be_nil
|
|
57
|
+
find.should have(2).entries
|
|
58
|
+
|
|
59
|
+
find = SailBoat.all(:id.not => 0..2)
|
|
60
|
+
find.should have(1).entries
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should order results" do
|
|
65
|
+
repository(ADAPTER) do
|
|
66
|
+
result = SailBoat.all(:order => [
|
|
67
|
+
DataMapper::Query::Direction.new(SailBoat.properties[:name], :asc)
|
|
68
|
+
])
|
|
69
|
+
result[0].id.should == 1
|
|
70
|
+
|
|
71
|
+
result = SailBoat.all(:order => [
|
|
72
|
+
DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
|
|
73
|
+
])
|
|
74
|
+
result[0].id.should == 3
|
|
75
|
+
|
|
76
|
+
result = SailBoat.all(:order => [
|
|
77
|
+
DataMapper::Query::Direction.new(SailBoat.properties[:name], :asc),
|
|
78
|
+
DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
|
|
79
|
+
])
|
|
80
|
+
result[0].id.should == 1
|
|
81
|
+
|
|
82
|
+
result = SailBoat.all(:order => [
|
|
83
|
+
SailBoat.properties[:name],
|
|
84
|
+
DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
|
|
85
|
+
])
|
|
86
|
+
result[0].id.should == 1
|
|
87
|
+
|
|
88
|
+
result = SailBoat.all(:order => [:name])
|
|
89
|
+
result[0].id.should == 1
|
|
90
|
+
|
|
91
|
+
result = SailBoat.all(:order => [:name.desc])
|
|
92
|
+
result[0].id.should == 3
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe 'when sub-selecting' do
|
|
98
|
+
before :all do
|
|
99
|
+
class Permission
|
|
100
|
+
include DataMapper::Resource
|
|
101
|
+
property :id, Serial
|
|
102
|
+
property :user_id, Integer
|
|
103
|
+
property :resource_id, Integer
|
|
104
|
+
property :resource_type, String
|
|
105
|
+
property :token, String
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class SailBoat
|
|
109
|
+
include DataMapper::Resource
|
|
110
|
+
property :id, Serial
|
|
111
|
+
property :name, String
|
|
112
|
+
property :port, String
|
|
113
|
+
property :captain, String
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
before do
|
|
118
|
+
Permission.auto_migrate!(ADAPTER)
|
|
119
|
+
SailBoat.auto_migrate!(ADAPTER)
|
|
120
|
+
|
|
121
|
+
repository(ADAPTER) do
|
|
122
|
+
SailBoat.create!(:id => 1, :name => "Fantasy I", :port => "Cape Town", :captain => 'Joe')
|
|
123
|
+
SailBoat.create!(:id => 2, :name => "Royal Flush II", :port => "Cape Town", :captain => 'James')
|
|
124
|
+
SailBoat.create!(:id => 3, :name => "Infringer III", :port => "Cape Town", :captain => 'Jason')
|
|
125
|
+
|
|
126
|
+
#User 1 permission -- read boat 1 & 2
|
|
127
|
+
Permission.create!(:id => 1, :user_id => 1, :resource_id => 1, :resource_type => 'SailBoat', :token => 'READ')
|
|
128
|
+
Permission.create!(:id => 2, :user_id => 1, :resource_id => 2, :resource_type => 'SailBoat', :token => 'READ')
|
|
129
|
+
|
|
130
|
+
#User 2 permission -- read boat 2 & 3
|
|
131
|
+
Permission.create!(:id => 3, :user_id => 2, :resource_id => 2, :resource_type => 'SailBoat', :token => 'READ')
|
|
132
|
+
Permission.create!(:id => 4, :user_id => 2, :resource_id => 3, :resource_type => 'SailBoat', :token => 'READ')
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'should accept a DM::Query as a value of a condition' do
|
|
137
|
+
# User 1
|
|
138
|
+
acl = DataMapper::Query.new(repository(ADAPTER), Permission, :user_id => 1, :resource_type => 'SailBoat', :token => 'READ', :fields => [ :resource_id ])
|
|
139
|
+
query = { :port => 'Cape Town', :id => acl, :captain.like => 'J%', :order => [ :id ] }
|
|
140
|
+
boats = repository(ADAPTER) { SailBoat.all(query) }
|
|
141
|
+
boats.should have(2).entries
|
|
142
|
+
boats.entries[0].id.should == 1
|
|
143
|
+
boats.entries[1].id.should == 2
|
|
144
|
+
|
|
145
|
+
# User 2
|
|
146
|
+
acl = DataMapper::Query.new(repository(ADAPTER), Permission, :user_id => 2, :resource_type => 'SailBoat', :token => 'READ', :fields => [ :resource_id ])
|
|
147
|
+
query = { :port => 'Cape Town', :id => acl, :captain.like => 'J%', :order => [ :id ] }
|
|
148
|
+
boats = repository(ADAPTER) { SailBoat.all(query) }
|
|
149
|
+
|
|
150
|
+
boats.should have(2).entries
|
|
151
|
+
boats.entries[0].id.should == 2
|
|
152
|
+
boats.entries[1].id.should == 3
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it 'when value is NOT IN another query' do
|
|
156
|
+
# Boats that User 1 Cannot see
|
|
157
|
+
acl = DataMapper::Query.new(repository(ADAPTER), Permission, :user_id => 1, :resource_type => 'SailBoat', :token => 'READ', :fields => [:resource_id])
|
|
158
|
+
query = { :port => 'Cape Town', :id.not => acl, :captain.like => 'J%' }
|
|
159
|
+
boats = repository(ADAPTER) { SailBoat.all(query) }
|
|
160
|
+
boats.should have(1).entries
|
|
161
|
+
boats.entries[0].id.should == 3
|
|
162
|
+
end
|
|
163
|
+
end # describe sub-selecting
|
|
164
|
+
|
|
165
|
+
describe 'when linking associated objects' do
|
|
166
|
+
before :all do
|
|
167
|
+
class Region
|
|
168
|
+
include DataMapper::Resource
|
|
169
|
+
property :id, Serial
|
|
170
|
+
property :name, String
|
|
171
|
+
|
|
172
|
+
def self.default_repository_name
|
|
173
|
+
ADAPTER
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
class Factory
|
|
178
|
+
include DataMapper::Resource
|
|
179
|
+
property :id, Serial
|
|
180
|
+
property :region_id, Integer
|
|
181
|
+
property :name, String
|
|
182
|
+
|
|
183
|
+
repository(:mock) do
|
|
184
|
+
property :land, String
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
belongs_to :region
|
|
188
|
+
|
|
189
|
+
def self.default_repository_name
|
|
190
|
+
ADAPTER
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
class Vehicle
|
|
195
|
+
include DataMapper::Resource
|
|
196
|
+
property :id, Serial
|
|
197
|
+
property :factory_id, Integer
|
|
198
|
+
property :name, String
|
|
199
|
+
|
|
200
|
+
belongs_to :factory
|
|
201
|
+
|
|
202
|
+
def self.default_repository_name
|
|
203
|
+
ADAPTER
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
module Namespace
|
|
208
|
+
class Region
|
|
209
|
+
include DataMapper::Resource
|
|
210
|
+
property :id, Serial
|
|
211
|
+
property :name, String
|
|
212
|
+
|
|
213
|
+
def self.default_repository_name
|
|
214
|
+
ADAPTER
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
class Factory
|
|
219
|
+
include DataMapper::Resource
|
|
220
|
+
property :id, Serial
|
|
221
|
+
property :region_id, Integer
|
|
222
|
+
property :name, String
|
|
223
|
+
|
|
224
|
+
repository(:mock) do
|
|
225
|
+
property :land, String
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
belongs_to :region
|
|
229
|
+
|
|
230
|
+
def self.default_repository_name
|
|
231
|
+
ADAPTER
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
class Vehicle
|
|
236
|
+
include DataMapper::Resource
|
|
237
|
+
property :id, Serial
|
|
238
|
+
property :factory_id, Integer
|
|
239
|
+
property :name, String
|
|
240
|
+
|
|
241
|
+
belongs_to :factory
|
|
242
|
+
|
|
243
|
+
def self.default_repository_name
|
|
244
|
+
ADAPTER
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
before do
|
|
251
|
+
Region.auto_migrate!
|
|
252
|
+
Factory.auto_migrate!
|
|
253
|
+
Vehicle.auto_migrate!
|
|
254
|
+
|
|
255
|
+
Region.new(:id=>1, :name=>'North West').save
|
|
256
|
+
Factory.new(:id=>2000, :region_id=>1, :name=>'North West Plant').save
|
|
257
|
+
Vehicle.new(:id=>1, :factory_id=>2000, :name=>'10 ton delivery truck').save
|
|
258
|
+
|
|
259
|
+
Namespace::Region.auto_migrate!
|
|
260
|
+
Namespace::Factory.auto_migrate!
|
|
261
|
+
Namespace::Vehicle.auto_migrate!
|
|
262
|
+
|
|
263
|
+
Namespace::Region.new(:id=>1, :name=>'North West').save
|
|
264
|
+
Namespace::Factory.new(:id=>2000, :region_id=>1, :name=>'North West Plant').save
|
|
265
|
+
Namespace::Vehicle.new(:id=>1, :factory_id=>2000, :name=>'10 ton delivery truck').save
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
it 'should require that all properties in :fields and all :links come from the same repository' #do
|
|
269
|
+
# land = Factory.properties(:mock)[:land]
|
|
270
|
+
# fields = []
|
|
271
|
+
# Vehicle.properties(ADAPTER).map do |property|
|
|
272
|
+
# fields << property
|
|
273
|
+
# end
|
|
274
|
+
# fields << land
|
|
275
|
+
#
|
|
276
|
+
# lambda{
|
|
277
|
+
# begin
|
|
278
|
+
# results = repository(ADAPTER) { Vehicle.all(:links => [:factory], :fields => fields) }
|
|
279
|
+
# rescue RuntimeError
|
|
280
|
+
# $!.message.should == "Property Factory.land not available in repository #{ADAPTER}"
|
|
281
|
+
# raise $!
|
|
282
|
+
# end
|
|
283
|
+
# }.should raise_error(RuntimeError)
|
|
284
|
+
#end
|
|
285
|
+
|
|
286
|
+
it 'should accept a DM::Assoc::Relationship as a link' do
|
|
287
|
+
factory = DataMapper::Associations::Relationship.new(
|
|
288
|
+
:factory,
|
|
289
|
+
ADAPTER,
|
|
290
|
+
'Vehicle',
|
|
291
|
+
'Factory',
|
|
292
|
+
{ :child_key => [ :factory_id ], :parent_key => [ :id ] }
|
|
293
|
+
)
|
|
294
|
+
results = repository(ADAPTER) { Vehicle.all(:links => [factory]) }
|
|
295
|
+
results.should have(1).entries
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
it 'should accept a symbol of an association name as a link' do
|
|
299
|
+
results = repository(ADAPTER) { Vehicle.all(:links => [:factory]) }
|
|
300
|
+
results.should have(1).entries
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it 'should accept a string of an association name as a link' do
|
|
304
|
+
results = repository(ADAPTER) { Vehicle.all(:links => ['factory']) }
|
|
305
|
+
results.should have(1).entries
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it 'should accept a mixture of items as a set of links' do
|
|
309
|
+
region = DataMapper::Associations::Relationship.new(
|
|
310
|
+
:region,
|
|
311
|
+
ADAPTER,
|
|
312
|
+
'Factory',
|
|
313
|
+
'Region',
|
|
314
|
+
{ :child_key => [ :region_id ], :parent_key => [ :id ] }
|
|
315
|
+
)
|
|
316
|
+
results = repository(ADAPTER) { Vehicle.all(:links => ['factory',region]) }
|
|
317
|
+
results.should have(1).entries
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it 'should only accept a DM::Assoc::Relationship, String & Symbol as a link' do
|
|
321
|
+
lambda{
|
|
322
|
+
DataMapper::Query.new(repository(ADAPTER), Vehicle, :links => [1])
|
|
323
|
+
}.should raise_error(ArgumentError)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it 'should have a association by the name of the Symbol or String' do
|
|
327
|
+
lambda{
|
|
328
|
+
DataMapper::Query.new(repository(ADAPTER), Vehicle, :links=>['Sailing'])
|
|
329
|
+
}.should raise_error(ArgumentError)
|
|
330
|
+
|
|
331
|
+
lambda{
|
|
332
|
+
DataMapper::Query.new(repository(ADAPTER), Vehicle, :links=>[:sailing])
|
|
333
|
+
}.should raise_error(ArgumentError)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
it 'should create an n-level query path' do
|
|
337
|
+
Vehicle.factory.region.model.should == Region
|
|
338
|
+
Vehicle.factory.region.name.property.should == Region.properties(Region.repository.name)[:name]
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
it 'should accept a DM::QueryPath as the key to a condition' do
|
|
342
|
+
vehicle = Vehicle.first(Vehicle.factory.region.name => 'North West')
|
|
343
|
+
vehicle.name.should == '10 ton delivery truck'
|
|
344
|
+
|
|
345
|
+
vehicle = Namespace::Vehicle.first(Namespace::Vehicle.factory.region.name => 'North West')
|
|
346
|
+
vehicle.name.should == '10 ton delivery truck'
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
it "should accept a string representing a DM::QueryPath as they key to a condition" do
|
|
350
|
+
vehicle = Vehicle.first("factory.region.name" => 'North West')
|
|
351
|
+
vehicle.name.should == '10 ton delivery truck'
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
it 'should auto generate the link if a DM::Property from a different resource is in the :fields option'
|
|
355
|
+
|
|
356
|
+
it 'should create links with composite keys'
|
|
357
|
+
|
|
358
|
+
it 'should eager load associations' do
|
|
359
|
+
repository(ADAPTER) do
|
|
360
|
+
vehicle = Vehicle.first(:includes => [Vehicle.factory])
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it "should behave when using mocks" do
|
|
365
|
+
class Group
|
|
366
|
+
include DataMapper::Resource
|
|
367
|
+
property :id, Serial
|
|
368
|
+
property :name, String
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
Group.should_receive(:all).with(:order => [:id.asc])
|
|
372
|
+
Group.all(:order => [:id.asc])
|
|
373
|
+
end
|
|
374
|
+
end # describe links
|
|
375
|
+
end # DM::Query
|
|
376
|
+
end
|