ruby_odata 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -2
- data/CHANGELOG.md +8 -0
- data/features/error_handling.feature +1 -2
- data/lib/ruby_odata/class_builder.rb +11 -7
- data/lib/ruby_odata/exceptions.rb +7 -0
- data/lib/ruby_odata/property_metadata.rb +2 -0
- data/lib/ruby_odata/query_builder.rb +27 -0
- data/lib/ruby_odata/service.rb +59 -7
- data/lib/ruby_odata/version.rb +1 -1
- data/spec/fixtures/int64_ids/edmx_boat_service.xml +19 -0
- data/spec/fixtures/int64_ids/edmx_car_service.xml +21 -0
- data/spec/fixtures/int64_ids/result_boats.xml +26 -0
- data/spec/fixtures/int64_ids/result_cars.xml +28 -0
- data/spec/fixtures/sample_service/result_select_categories_expand.xml +268 -0
- data/spec/fixtures/sample_service/result_select_categories_no_property.xml +6 -0
- data/spec/fixtures/sample_service/result_select_categories_travsing_no_expand.xml +6 -0
- data/spec/fixtures/sample_service/result_select_products_name_price.xml +92 -0
- data/spec/property_metadata_spec.rb +8 -8
- data/spec/query_builder_spec.rb +60 -2
- data/spec/revised_service_spec.rb +95 -6
- data/spec/service_spec.rb +80 -3
- metadata +245 -218
@@ -0,0 +1,6 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
2
|
+
<error
|
3
|
+
xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
|
4
|
+
<code></code>
|
5
|
+
<message xml:lang="en-US">Type 'RubyODataService.Category' does not have a property named 'Price' or there is no type with 'Price' name.</message>
|
6
|
+
</error>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
2
|
+
<error
|
3
|
+
xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
|
4
|
+
<code></code>
|
5
|
+
<message xml:lang="en-US">Only properties specified in $expand can be traversed in $select query options. Property .</message>
|
6
|
+
</error>
|
@@ -0,0 +1,92 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<feed xml:base="http://win7dev:8989/SampleService/RubyOData.svc/"
|
3
|
+
xmlns="http://www.w3.org/2005/Atom"
|
4
|
+
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
|
5
|
+
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
|
6
|
+
xmlns:georss="http://www.georss.org/georss"
|
7
|
+
xmlns:gml="http://www.opengis.net/gml">
|
8
|
+
<id>http://win7dev:8989/SampleService/RubyOdata.svc/Products</id>
|
9
|
+
<title type="text">Products</title>
|
10
|
+
<updated>2013-07-19T12:29:11Z</updated>
|
11
|
+
<link rel="self" title="Products" href="Products" />
|
12
|
+
<entry>
|
13
|
+
<id>http://win7dev:8989/SampleService/RubyOData.svc/Products(1)</id>
|
14
|
+
<category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
|
15
|
+
<link rel="edit" title="Product" href="Products(1)" />
|
16
|
+
<title />
|
17
|
+
<updated>2013-07-19T12:29:11Z</updated>
|
18
|
+
<author>
|
19
|
+
<name />
|
20
|
+
</author>
|
21
|
+
<content type="application/xml">
|
22
|
+
<m:properties>
|
23
|
+
<d:Name>Widget 0001</d:Name>
|
24
|
+
<d:Price m:type="Edm.Decimal">75.50</d:Price>
|
25
|
+
</m:properties>
|
26
|
+
</content>
|
27
|
+
</entry>
|
28
|
+
<entry>
|
29
|
+
<id>http://win7dev:8989/SampleService/RubyOData.svc/Products(2)</id>
|
30
|
+
<category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
|
31
|
+
<link rel="edit" title="Product" href="Products(2)" />
|
32
|
+
<title />
|
33
|
+
<updated>2013-07-19T12:29:11Z</updated>
|
34
|
+
<author>
|
35
|
+
<name />
|
36
|
+
</author>
|
37
|
+
<content type="application/xml">
|
38
|
+
<m:properties>
|
39
|
+
<d:Name>Widget 0002</d:Name>
|
40
|
+
<d:Price m:type="Edm.Decimal">100.00</d:Price>
|
41
|
+
</m:properties>
|
42
|
+
</content>
|
43
|
+
</entry>
|
44
|
+
<entry>
|
45
|
+
<id>http://win7dev:8989/SampleService/RubyOData.svc/Products(3)</id>
|
46
|
+
<category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
|
47
|
+
<link rel="edit" title="Product" href="Products(3)" />
|
48
|
+
<title />
|
49
|
+
<updated>2013-07-19T12:29:11Z</updated>
|
50
|
+
<author>
|
51
|
+
<name />
|
52
|
+
</author>
|
53
|
+
<content type="application/xml">
|
54
|
+
<m:properties>
|
55
|
+
<d:Name>Widget 0003</d:Name>
|
56
|
+
<d:Price m:type="Edm.Decimal">10.25</d:Price>
|
57
|
+
</m:properties>
|
58
|
+
</content>
|
59
|
+
</entry>
|
60
|
+
<entry>
|
61
|
+
<id>http://win7dev:8989/SampleService/RubyOData.svc/Products(4)</id>
|
62
|
+
<category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
|
63
|
+
<link rel="edit" title="Product" href="Products(4)" />
|
64
|
+
<title />
|
65
|
+
<updated>2013-07-19T12:29:11Z</updated>
|
66
|
+
<author>
|
67
|
+
<name />
|
68
|
+
</author>
|
69
|
+
<content type="application/xml">
|
70
|
+
<m:properties>
|
71
|
+
<d:Name>Widget 0004</d:Name>
|
72
|
+
<d:Price m:type="Edm.Decimal">100.00</d:Price>
|
73
|
+
</m:properties>
|
74
|
+
</content>
|
75
|
+
</entry>
|
76
|
+
<entry>
|
77
|
+
<id>http://win7dev:8989/SampleService/RubyOData.svc/Products(5)</id>
|
78
|
+
<category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
|
79
|
+
<link rel="edit" title="Product" href="Products(5)" />
|
80
|
+
<title />
|
81
|
+
<updated>2013-07-19T12:29:11Z</updated>
|
82
|
+
<author>
|
83
|
+
<name />
|
84
|
+
</author>
|
85
|
+
<content type="application/xml">
|
86
|
+
<m:properties>
|
87
|
+
<d:Name>Widget 0005</d:Name>
|
88
|
+
<d:Price m:type="Edm.Decimal">75.50</d:Price>
|
89
|
+
</m:properties>
|
90
|
+
</content>
|
91
|
+
</entry>
|
92
|
+
</feed>
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
module OData
|
4
4
|
describe PropertyMetadata do
|
5
5
|
describe "#initialize" do
|
6
|
-
it "parses an EDMX property with the essentials (name, type, nullable, nav_prop)" do
|
6
|
+
it "parses an EDMX property with the essentials (name, type, nullable, nav_prop)" do
|
7
7
|
property_element = RSpecSupport::ElementHelpers.string_to_element('<Property Name="Id" Type="Edm.String" Nullable="false" />')
|
8
8
|
property_metadata = PropertyMetadata.new property_element
|
9
9
|
property_metadata.name.should eq "Id"
|
@@ -15,30 +15,30 @@ module OData
|
|
15
15
|
property_element = RSpecSupport::ElementHelpers.string_to_element('<Property Name="Id" Type="Edm.String" Nullable="true" />')
|
16
16
|
property_metadata = PropertyMetadata.new property_element
|
17
17
|
property_metadata.nullable.should eq true
|
18
|
-
end
|
19
|
-
it "parses an EDMX property with nil for missing attributes" do
|
18
|
+
end
|
19
|
+
it "parses an EDMX property with nil for missing attributes" do
|
20
20
|
property_element = RSpecSupport::ElementHelpers.string_to_element('<Property Name="Id" Type="Edm.String" Nullable="false" />')
|
21
21
|
property_metadata = PropertyMetadata.new property_element
|
22
22
|
property_metadata.fc_target_path.should be_nil
|
23
23
|
property_metadata.fc_keep_in_content.should be_nil
|
24
24
|
end
|
25
|
-
it "parses an EDMX property with false for missing Nullable attribute" do
|
25
|
+
it "parses an EDMX property with false for missing Nullable attribute" do
|
26
26
|
property_element = RSpecSupport::ElementHelpers.string_to_element('<Property Name="Id" Type="Edm.String" />')
|
27
27
|
property_metadata = PropertyMetadata.new property_element
|
28
28
|
property_metadata.nullable.should eq false
|
29
|
-
end
|
30
|
-
it "parses an EDMX property with the fc_target_path and fc_keep_in_content attribute" do
|
29
|
+
end
|
30
|
+
it "parses an EDMX property with the fc_target_path and fc_keep_in_content attribute" do
|
31
31
|
property_element = RSpecSupport::ElementHelpers.string_to_element('<Property xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" Name="Title" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="false" />')
|
32
32
|
property_metadata = PropertyMetadata.new property_element
|
33
33
|
property_metadata.fc_target_path.should eq "SyndicationTitle"
|
34
34
|
property_metadata.fc_keep_in_content.should eq false
|
35
35
|
end
|
36
|
-
it "parses an EDMX property where fc_keep_in_content is true" do
|
36
|
+
it "parses an EDMX property where fc_keep_in_content is true" do
|
37
37
|
property_element = RSpecSupport::ElementHelpers.string_to_element('<Property xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" Name="Title" Type="Edm.String" Nullable="true" m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="true" />')
|
38
38
|
property_metadata = PropertyMetadata.new property_element
|
39
39
|
property_metadata.fc_keep_in_content.should eq true
|
40
40
|
end
|
41
|
-
it "parses an EDMX navigation property with the name and the nav_prop set to true" do
|
41
|
+
it "parses an EDMX navigation property with the name and the nav_prop set to true" do
|
42
42
|
property_element = RSpecSupport::ElementHelpers.string_to_element('<NavigationProperty Name="Category" Relationship="Model.CategoryProduct" FromRole="Product" ToRole="Category" />')
|
43
43
|
property_metadata = PropertyMetadata.new property_element
|
44
44
|
property_metadata.name.should eq "Category"
|
data/spec/query_builder_spec.rb
CHANGED
@@ -30,11 +30,16 @@ module OData
|
|
30
30
|
builder.top(5)
|
31
31
|
builder.query.should eq "Categories(1)/$links/Products?$top=5"
|
32
32
|
end
|
33
|
-
it "should throw an
|
33
|
+
it "should throw an exception if count was already called on the builder" do
|
34
34
|
builder = QueryBuilder.new "Categories(1)"
|
35
35
|
builder.count
|
36
36
|
lambda { builder.links("Products") }.should raise_error(OData::NotSupportedError, "You cannot call both the `links` method and the `count` method in the same query.")
|
37
37
|
end
|
38
|
+
it "should throw an exception if select was already called on the builder" do
|
39
|
+
builder = QueryBuilder.new "Products"
|
40
|
+
builder.select "Price"
|
41
|
+
lambda { builder.links("Products") }.should raise_error(OData::NotSupportedError, "You cannot call both the `links` method and the `select` method in the same query.")
|
42
|
+
end
|
38
43
|
end
|
39
44
|
|
40
45
|
describe "#count" do
|
@@ -53,11 +58,64 @@ module OData
|
|
53
58
|
builder.count
|
54
59
|
builder.query.should eq "Products/$count?$filter=Name+eq+%27Widget+1%27"
|
55
60
|
end
|
56
|
-
it "should throw an
|
61
|
+
it "should throw an exception if links was already called on the builder" do
|
57
62
|
builder = QueryBuilder.new "Categories(1)"
|
58
63
|
builder.links("Products")
|
59
64
|
lambda { builder.count }.should raise_error(OData::NotSupportedError, "You cannot call both the `links` method and the `count` method in the same query.")
|
60
65
|
end
|
66
|
+
it "should throw an exception if select was already called on the builder" do
|
67
|
+
builder = QueryBuilder.new "Products"
|
68
|
+
builder.select("Price")
|
69
|
+
lambda { builder.count }.should raise_error(OData::NotSupportedError, "You cannot call both the `select` method and the `count` method in the same query.")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#select" do
|
74
|
+
it "should accept the select method" do
|
75
|
+
builder = QueryBuilder.new "Products"
|
76
|
+
lambda { builder.select }.should_not raise_error
|
77
|
+
end
|
78
|
+
it "should properly handle the select method" do
|
79
|
+
builder = QueryBuilder.new "Products"
|
80
|
+
builder.select "Price", "Rating"
|
81
|
+
builder.query.should eq "Products?$select=Price,Rating"
|
82
|
+
end
|
83
|
+
it "shouldn't add duplicate properties" do
|
84
|
+
builder = QueryBuilder.new "Products"
|
85
|
+
builder.select "Price", "Rating", "Price"
|
86
|
+
builder.query.should eq "Products?$select=Price,Rating"
|
87
|
+
end
|
88
|
+
it "should properly handle the select method with additional operators" do
|
89
|
+
builder = QueryBuilder.new "Products"
|
90
|
+
builder.filter("Name eq 'Widget 1'")
|
91
|
+
builder.select("Price", "Rating")
|
92
|
+
builder.query.should eq "Products?$select=Price,Rating&$filter=Name+eq+%27Widget+1%27"
|
93
|
+
end
|
94
|
+
it "should throw an exception if links was already called on the builder" do
|
95
|
+
builder = QueryBuilder.new "Categories(1)"
|
96
|
+
builder.links("Products")
|
97
|
+
lambda { builder.select("Price") }.should raise_error(OData::NotSupportedError, "You cannot call both the `links` method and the `select` method in the same query.")
|
98
|
+
end
|
99
|
+
it "should throw an exception if count was already called on the builder" do
|
100
|
+
builder = QueryBuilder.new "Products"
|
101
|
+
builder.count
|
102
|
+
lambda { builder.select("Price") }.should raise_error(OData::NotSupportedError, "You cannot call both the `count` method and the `select` method in the same query.")
|
103
|
+
end
|
104
|
+
it "should return itself" do
|
105
|
+
builder = QueryBuilder.new "Products"
|
106
|
+
result = builder.select("Price", "Rating")
|
107
|
+
result.should be_a(QueryBuilder)
|
108
|
+
end
|
109
|
+
it "should automatically add $expand for nested selects" do
|
110
|
+
builder = QueryBuilder.new "Categories"
|
111
|
+
result = builder.select "Name", "Products/Name"
|
112
|
+
result.query.should eq "Categories?$select=Name,Products/Name&$expand=Products"
|
113
|
+
end
|
114
|
+
it "should automatically add $expand for deeply nested selects" do
|
115
|
+
builder = QueryBuilder.new "Products"
|
116
|
+
result = builder.select "ProductName", "Order_Details/OrderID", "Order_Details/Order/Customer/CompanyName"
|
117
|
+
result.query.should eq "Products?$select=ProductName,Order_Details/OrderID,Order_Details/Order/Customer/CompanyName&$expand=Order_Details,Order_Details/Order/Customer"
|
118
|
+
end
|
61
119
|
end
|
62
120
|
|
63
121
|
describe "#navigate" do
|
@@ -10,7 +10,7 @@ module OData
|
|
10
10
|
@cat_prod_service = OData::Service.new "http://test.com/test.svc"
|
11
11
|
end
|
12
12
|
subject { @cat_prod_service }
|
13
|
-
|
13
|
+
|
14
14
|
context "methods" do
|
15
15
|
it { should respond_to :update_object }
|
16
16
|
it { should respond_to :delete_object }
|
@@ -25,7 +25,7 @@ module OData
|
|
25
25
|
it { should respond_to :collections }
|
26
26
|
it { should respond_to :options }
|
27
27
|
it { should respond_to :function_imports }
|
28
|
-
|
28
|
+
|
29
29
|
context "after parsing metadata" do
|
30
30
|
it { should respond_to :Products }
|
31
31
|
it { should respond_to :Categories }
|
@@ -43,7 +43,7 @@ module OData
|
|
43
43
|
end
|
44
44
|
it "should expose the local model type" do
|
45
45
|
subject['Products'][:type].should eq Product
|
46
|
-
subject['Categories'][:type].should eq Category
|
46
|
+
subject['Categories'][:type].should eq Category
|
47
47
|
end
|
48
48
|
end
|
49
49
|
context "class metadata" do
|
@@ -51,6 +51,7 @@ module OData
|
|
51
51
|
it { should_not be_empty}
|
52
52
|
it { should have_key 'Product' }
|
53
53
|
it { should have_key 'Category' }
|
54
|
+
|
54
55
|
context "should have keys for each property" do
|
55
56
|
subject { @cat_prod_service.class_metadata['Category'] }
|
56
57
|
it { should have_key 'Id' }
|
@@ -69,6 +70,7 @@ module OData
|
|
69
70
|
meta.fc_target_path.should be_nil
|
70
71
|
meta.fc_keep_in_content.should be_nil
|
71
72
|
meta.nav_prop.should eq false
|
73
|
+
meta.is_key.should eq true
|
72
74
|
end
|
73
75
|
it "should have correct PropertyMetadata for Category.Name" do
|
74
76
|
meta = subject['Name']
|
@@ -78,6 +80,7 @@ module OData
|
|
78
80
|
meta.fc_target_path.should be_nil
|
79
81
|
meta.fc_keep_in_content.should be_nil
|
80
82
|
meta.nav_prop.should eq false
|
83
|
+
meta.is_key.should eq false
|
81
84
|
end
|
82
85
|
it "should have correct PropertyMetadata for Category.Products" do
|
83
86
|
meta = subject['Products']
|
@@ -88,6 +91,7 @@ module OData
|
|
88
91
|
meta.fc_keep_in_content.should be_nil
|
89
92
|
meta.nav_prop.should eq true
|
90
93
|
meta.association.should_not be_nil
|
94
|
+
meta.is_key.should eq false
|
91
95
|
end
|
92
96
|
end
|
93
97
|
end
|
@@ -115,7 +119,7 @@ module OData
|
|
115
119
|
subject['EntityCategoryWebGet'][:parameters].should be_nil
|
116
120
|
subject['EntitySingleCategoryWebGet'][:parameters].should be_a Hash
|
117
121
|
subject['EntitySingleCategoryWebGet'][:parameters]['id'].should eq 'Edm.Int32'
|
118
|
-
end
|
122
|
+
end
|
119
123
|
context "after parsing function imports" do
|
120
124
|
subject { @cat_prod_service }
|
121
125
|
it { should respond_to :CleanDatabaseForTesting }
|
@@ -152,10 +156,10 @@ module OData
|
|
152
156
|
subject { @cat_prod_service }
|
153
157
|
before(:each) do
|
154
158
|
stub_request(:post, "http://test.com/test.svc/CleanDatabaseForTesting").to_return(:status => 204)
|
155
|
-
|
159
|
+
|
156
160
|
stub_request(:get, "http://test.com/test.svc/EntityCategoryWebGet").
|
157
161
|
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_entity_category_web_get.xml", __FILE__)), :headers => {})
|
158
|
-
|
162
|
+
|
159
163
|
stub_request(:get, "http://test.com/test.svc/EntitySingleCategoryWebGet?id=1").
|
160
164
|
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_entity_single_category_web_get.xml", __FILE__)), :headers => {})
|
161
165
|
|
@@ -194,4 +198,89 @@ module OData
|
|
194
198
|
end
|
195
199
|
end
|
196
200
|
end
|
201
|
+
|
202
|
+
describe Service do
|
203
|
+
describe "Collection with an int64 key Named 'id'" do
|
204
|
+
|
205
|
+
before(:all) do
|
206
|
+
stub_request(:get, "http://test.com/test.svc/$metadata").
|
207
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
208
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/int64_ids/edmx_car_service.xml", __FILE__)), :headers => {})
|
209
|
+
@svc = OData::Service.new "http://test.com/test.svc/"
|
210
|
+
end
|
211
|
+
|
212
|
+
context "has the correct metadata" do
|
213
|
+
before(:all) do
|
214
|
+
@id_meta = @svc.class_metadata['Car']['id']
|
215
|
+
end
|
216
|
+
|
217
|
+
subject { @id_meta }
|
218
|
+
|
219
|
+
its(:name) { should eq('id') }
|
220
|
+
its(:type) { should eq('Edm.Int64') }
|
221
|
+
its(:nullable) { should be_false }
|
222
|
+
its(:fc_target_path) { should be_nil }
|
223
|
+
its(:fc_keep_in_content) { should be_nil }
|
224
|
+
end
|
225
|
+
|
226
|
+
context "can parse Id correctly" do
|
227
|
+
before(:each) do
|
228
|
+
stub_request(:get, "http://test.com/test.svc/Cars(213L)").
|
229
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
230
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/int64_ids/result_cars.xml", __FILE__)), :headers => {})
|
231
|
+
|
232
|
+
@svc.Cars(213)
|
233
|
+
results = @svc.execute
|
234
|
+
@car = results.first
|
235
|
+
end
|
236
|
+
|
237
|
+
subject { @car }
|
238
|
+
|
239
|
+
its(:id) { should eq(213) }
|
240
|
+
its(:color) { should eq('peach') }
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "Collection with an int64 key named 'KeyId'" do
|
245
|
+
|
246
|
+
before(:all) do
|
247
|
+
stub_request(:get, "http://test.com/test.svc/$metadata").
|
248
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
249
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/int64_ids/edmx_boat_service.xml", __FILE__)), :headers => {})
|
250
|
+
@svc = OData::Service.new "http://test.com/test.svc/"
|
251
|
+
end
|
252
|
+
|
253
|
+
context "has the correct metadata" do
|
254
|
+
before(:all) do
|
255
|
+
@id_meta = @svc.class_metadata['Boat']['KeyId']
|
256
|
+
end
|
257
|
+
|
258
|
+
subject { @id_meta }
|
259
|
+
|
260
|
+
its(:name) { should eq('KeyId') }
|
261
|
+
its(:type) { should eq('Edm.Int64') }
|
262
|
+
its(:nullable) { should be_false }
|
263
|
+
its(:fc_target_path) { should be_nil }
|
264
|
+
its(:fc_keep_in_content) { should be_nil }
|
265
|
+
end
|
266
|
+
|
267
|
+
context "can parse Id correctly" do
|
268
|
+
before(:each) do
|
269
|
+
stub_request(:get, "http://test.com/test.svc/Boats(213L)").
|
270
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
271
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/int64_ids/result_boats.xml", __FILE__)), :headers => {})
|
272
|
+
|
273
|
+
@svc.Boats(213)
|
274
|
+
results = @svc.execute
|
275
|
+
@boat = results.first
|
276
|
+
end
|
277
|
+
|
278
|
+
subject { @boat }
|
279
|
+
|
280
|
+
its(:id) { should eq(213) }
|
281
|
+
its(:color) { should eq('blue') }
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
197
286
|
end
|
data/spec/service_spec.rb
CHANGED
@@ -770,7 +770,7 @@ module OData
|
|
770
770
|
svc.VirtualMachines
|
771
771
|
results = svc.execute
|
772
772
|
@json = results.first.as_json
|
773
|
-
end
|
773
|
+
end
|
774
774
|
|
775
775
|
it "Should quote Edm.Int64 properties" do
|
776
776
|
@json["PerfDiskBytesWrite"].should be_a(String)
|
@@ -808,7 +808,7 @@ module OData
|
|
808
808
|
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/ms_system_center/vm_templates.xml", __FILE__)), :headers => {})
|
809
809
|
|
810
810
|
end
|
811
|
-
|
811
|
+
|
812
812
|
it "should successfully parse null valued string properties" do
|
813
813
|
svc = OData::Service.new "http://test.com/test.svc/", { :username => "blabla", :password=> "", :verify_ssl => false, :namespace => "VMM" }
|
814
814
|
svc.VirtualMachines
|
@@ -905,8 +905,85 @@ module OData
|
|
905
905
|
products.first.Category.Products.first.ProductName.should eq "Chai"
|
906
906
|
end
|
907
907
|
end
|
908
|
-
end
|
909
908
|
|
909
|
+
describe "handling of custom select queries" do
|
910
|
+
|
911
|
+
context "when results are found" do
|
912
|
+
before(:each) do
|
913
|
+
stub_request(:get, "http://test.com/test.svc/$metadata").
|
914
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
915
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
|
916
|
+
|
917
|
+
stub_request(:get, "http://test.com/test.svc/Products?$select=Name,Price").
|
918
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
919
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_select_products_name_price.xml", __FILE__)), :headers => {})
|
920
|
+
end
|
921
|
+
|
922
|
+
subject do
|
923
|
+
svc = OData::Service.new "http://test.com/test.svc/"
|
924
|
+
svc.Products.select "Name", "Price"
|
925
|
+
svc.execute
|
926
|
+
end
|
927
|
+
|
928
|
+
it { should be_an Array }
|
929
|
+
it { should_not be_empty }
|
930
|
+
its(:first) { should be_a Product }
|
931
|
+
end
|
932
|
+
|
933
|
+
context "when there isn't a property by the name specified" do
|
934
|
+
before(:each) do
|
935
|
+
stub_request(:get, "http://test.com/test.svc/$metadata").
|
936
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
937
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
|
938
|
+
|
939
|
+
stub_request(:get, "http://test.com/test.svc/Categories?$select=Price").
|
940
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
941
|
+
to_return(:status => 400, :body => File.new(File.expand_path("../fixtures/sample_service/result_select_categories_no_property.xml", __FILE__)), :headers => {})
|
942
|
+
end
|
943
|
+
|
944
|
+
it "raises an exception" do
|
945
|
+
svc = OData::Service.new "http://test.com/test.svc/"
|
946
|
+
svc.Categories.select "Price"
|
947
|
+
expect { svc.execute }.to raise_error(OData::ServiceError) { |error|
|
948
|
+
error.http_code.should eq 400
|
949
|
+
error.message.should eq "Type 'RubyODataService.Category' does not have a property named 'Price' or there is no type with 'Price' name."
|
950
|
+
}
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
context "when a property requires $expand to traverse" do
|
955
|
+
before(:each) do
|
956
|
+
stub_request(:get, "http://test.com/test.svc/$metadata").
|
957
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
958
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/edmx_categories_products.xml", __FILE__)), :headers => {})
|
959
|
+
|
960
|
+
stub_request(:get, "http://test.com/test.svc/Categories?$select=Name,Products/Name").
|
961
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
962
|
+
to_return(:status => 400, :body => File.new(File.expand_path("../fixtures/sample_service/result_select_categories_travsing_no_expand.xml", __FILE__)), :headers => {})
|
963
|
+
|
964
|
+
stub_request(:get, "http://test.com/test.svc/Categories?$select=Name,Products/Name&$expand=Products").
|
965
|
+
with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).
|
966
|
+
to_return(:status => 200, :body => File.new(File.expand_path("../fixtures/sample_service/result_select_categories_expand.xml", __FILE__)), :headers => {})
|
967
|
+
end
|
968
|
+
|
969
|
+
it "doesn't error" do
|
970
|
+
svc = OData::Service.new "http://test.com/test.svc/"
|
971
|
+
svc.Categories.select "Name", "Products/Name"
|
972
|
+
expect { svc.execute }.to_not raise_error(OData::ServiceError)
|
973
|
+
end
|
974
|
+
|
975
|
+
it "returns the classes with the properties filled in" do
|
976
|
+
svc = OData::Service.new "http://test.com/test.svc/"
|
977
|
+
svc.Categories.select "Name", "Products/Name"
|
978
|
+
results = svc.execute
|
979
|
+
category = results.first
|
980
|
+
category.Name.should eq "Category 0001"
|
981
|
+
product = category.Products.first
|
982
|
+
product.Name.should eq "Widget 0001"
|
983
|
+
end
|
984
|
+
end
|
985
|
+
end
|
986
|
+
end
|
910
987
|
describe_private OData::Service do
|
911
988
|
describe "parse value" do
|
912
989
|
before(:each) do
|