ruby_odata 0.1.4 → 0.1.5
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/.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
|