odata 0.5.0 → 0.5.1
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.
- checksums.yaml +4 -4
- data/lib/odata.rb +1 -0
- data/lib/odata/complex_type.rb +67 -0
- data/lib/odata/entity.rb +28 -17
- data/lib/odata/properties.rb +2 -1
- data/lib/odata/properties/geography_point.rb +6 -0
- data/lib/odata/service.rb +32 -8
- data/lib/odata/version.rb +1 -1
- data/spec/fixtures/sample_service/supplier_0.xml +37 -0
- data/spec/fixtures/vcr_cassettes/complex_type_specs.yml +164 -0
- data/spec/odata/complex_type_spec.rb +34 -0
- data/spec/odata/entity_spec.rb +22 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0168d51fbc598d14a4ad183bf905476b1c7e0c33
|
4
|
+
data.tar.gz: 2b1678db31c28a5bd4122753d43153f9d83ac6a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 315c0846a3e364a234fa63595618d89e8a6d340d0046440c815ba9153ec7db419136443027203ae6d307ba82883d089af0fcb02379c1c33010b53f21979f3251
|
7
|
+
data.tar.gz: 53b3c627ab42f413d264c23aa8dfea0f64e559e87c0cd747ceba9e786de2c0f537836c6fdf528d27bcc6fd1cdfa32c4746350c681a22daed1664f3dfcfa63cd6
|
data/lib/odata.rb
CHANGED
@@ -0,0 +1,67 @@
|
|
1
|
+
module OData
|
2
|
+
# ComplexTypes are used in OData to either encapsulate richer data types for
|
3
|
+
# use as Entity properties. ComplexTypes are composed of properties the same
|
4
|
+
# way that Entities are and, so, the interface for working with the various
|
5
|
+
# properties of a ComplexType mimics that of Entities.
|
6
|
+
class ComplexType
|
7
|
+
# The name of the ComplexType
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
# Creates a new ComplexType based on the supplied options.
|
11
|
+
# @param options [Hash]
|
12
|
+
# @return [self]
|
13
|
+
def initialize(options = {})
|
14
|
+
validate_options(options)
|
15
|
+
|
16
|
+
@name = options[:name].to_s
|
17
|
+
@service = options[:service]
|
18
|
+
|
19
|
+
collect_properties
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the namespace this ComplexType belongs to.
|
23
|
+
# @return [String]
|
24
|
+
def namespace
|
25
|
+
@namespace ||= service.namespace
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a list of this ComplexType's property names.
|
29
|
+
# @return [Array<String>]
|
30
|
+
def property_names
|
31
|
+
@property_names ||= properties.collect {|name, property| name}
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the value of the requested property.
|
35
|
+
# @param property_name [to_s]
|
36
|
+
# @return [*]
|
37
|
+
def [](property_name)
|
38
|
+
properties[property_name.to_s].value
|
39
|
+
end
|
40
|
+
|
41
|
+
# Sets the value of the named property.
|
42
|
+
# @param property_name [to_s]
|
43
|
+
# @param value [*]
|
44
|
+
# @return [*]
|
45
|
+
def []=(property_name, value)
|
46
|
+
properties[property_name.to_s].value = value
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def service
|
52
|
+
@service
|
53
|
+
end
|
54
|
+
|
55
|
+
def properties
|
56
|
+
@properties
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_options(options)
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def collect_properties
|
64
|
+
@properties = service.properties_for_complex_type(name)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/odata/entity.rb
CHANGED
@@ -30,22 +30,22 @@ module OData
|
|
30
30
|
# @param property_name [to_s]
|
31
31
|
# @return [*]
|
32
32
|
def [](property_name)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
if properties[property_name.to_s].is_a?(::OData::ComplexType)
|
34
|
+
properties[property_name.to_s]
|
35
|
+
else
|
36
|
+
properties[property_name.to_s].value
|
37
37
|
end
|
38
|
+
rescue NoMethodError
|
39
|
+
raise ArgumentError, "Unknown property: #{property_name}"
|
38
40
|
end
|
39
41
|
|
40
42
|
# Set property value
|
41
43
|
# @param property_name [to_s]
|
42
44
|
# @param value [*]
|
43
45
|
def []=(property_name, value)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
raise ArgumentError, "Unknown property: #{property_name}"
|
48
|
-
end
|
46
|
+
properties[property_name.to_s].value = value
|
47
|
+
rescue NoMethodError
|
48
|
+
raise ArgumentError, "Unknown property: #{property_name}"
|
49
49
|
end
|
50
50
|
|
51
51
|
# Create Entity with provided properties and options.
|
@@ -55,7 +55,7 @@ module OData
|
|
55
55
|
def self.with_properties(new_properties = {}, options = {})
|
56
56
|
entity = OData::Entity.new(options)
|
57
57
|
entity.instance_eval do
|
58
|
-
service.
|
58
|
+
service.properties_for_entity(name).each do |name, instance|
|
59
59
|
set_property(name, instance)
|
60
60
|
end
|
61
61
|
|
@@ -118,10 +118,20 @@ module OData
|
|
118
118
|
|
119
119
|
private
|
120
120
|
|
121
|
-
def
|
121
|
+
def instantiate_property(property_name, value)
|
122
122
|
value_type = service.get_property_type(name, property_name)
|
123
|
-
|
124
|
-
|
123
|
+
if value_type =~ /^#{namespace}\./
|
124
|
+
type_name = value_type.gsub(/^#{namespace}\./, '')
|
125
|
+
property = ::OData::ComplexType.new(name: type_name, service: service)
|
126
|
+
value.element_children.each do |node|
|
127
|
+
property[node.name] = node.content
|
128
|
+
end
|
129
|
+
property
|
130
|
+
else
|
131
|
+
klass_name = value_type.gsub(/^Edm\./, '')
|
132
|
+
value = value.content unless value.nil?
|
133
|
+
::OData::Properties.const_get(klass_name).new(property_name, value)
|
134
|
+
end
|
125
135
|
end
|
126
136
|
|
127
137
|
def properties
|
@@ -144,9 +154,9 @@ module OData
|
|
144
154
|
property_xml.attributes['null'].value == 'true'
|
145
155
|
value = nil
|
146
156
|
else
|
147
|
-
value = property_xml
|
157
|
+
value = property_xml
|
148
158
|
end
|
149
|
-
property =
|
159
|
+
property = instantiate_property(property_name, value)
|
150
160
|
set_property(property_name, property)
|
151
161
|
end
|
152
162
|
end
|
@@ -154,9 +164,10 @@ module OData
|
|
154
164
|
|
155
165
|
def self.process_feed_property(entity, xml_doc, property_name)
|
156
166
|
entity.instance_eval do
|
157
|
-
property_value = xml_doc.xpath("//#{property_name}").first
|
167
|
+
property_value = xml_doc.xpath("//#{property_name}").first
|
158
168
|
property_name = service.send("get_#{property_name}_property_name", name)
|
159
|
-
|
169
|
+
return if property_name.nil?
|
170
|
+
property = instantiate_property(property_name, property_value)
|
160
171
|
set_property(property_name, property)
|
161
172
|
end
|
162
173
|
end
|
data/lib/odata/properties.rb
CHANGED
data/lib/odata/service.rb
CHANGED
@@ -142,6 +142,8 @@ module OData
|
|
142
142
|
# @return [String] the name of the property used as the entity summary
|
143
143
|
def get_summary_property_name(entity_name)
|
144
144
|
metadata.xpath("//EntityType[@Name='#{entity_name}']/Property[@FC_TargetPath='SyndicationSummary']").first.attributes['Name'].value
|
145
|
+
rescue NoMethodError
|
146
|
+
nil
|
145
147
|
end
|
146
148
|
|
147
149
|
# Get the primary key for the supplied Entity.
|
@@ -154,20 +156,32 @@ module OData
|
|
154
156
|
|
155
157
|
# Get the list of properties and their various options for the supplied
|
156
158
|
# Entity name.
|
157
|
-
#
|
158
159
|
# @param entity_name [to_s]
|
159
160
|
# @return [Hash]
|
160
|
-
|
161
|
+
# @api private
|
162
|
+
def properties_for_entity(entity_name)
|
161
163
|
type_definition = metadata.xpath("//EntityType[@Name='#{entity_name}']").first
|
162
164
|
raise ArgumentError, "Unknown EntityType: #{entity_name}" if type_definition.nil?
|
163
165
|
properties_to_return = {}
|
164
166
|
type_definition.xpath('./Property').each do |property_xml|
|
165
|
-
property_name = property_xml
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
167
|
+
property_name, property = process_property_from_xml(property_xml)
|
168
|
+
properties_to_return[property_name] = property
|
169
|
+
end
|
170
|
+
properties_to_return
|
171
|
+
end
|
172
|
+
|
173
|
+
# Get list of properties and their various options for the supplied
|
174
|
+
# ComplexType name.
|
175
|
+
# @param type_name [to_s]
|
176
|
+
# @return [Hash]
|
177
|
+
# @api private
|
178
|
+
def properties_for_complex_type(type_name)
|
179
|
+
type_definition = metadata.xpath("//ComplexType[@Name='#{type_name}']").first
|
180
|
+
raise ArgumentError, "Unknown ComplexType: #{type_name}" if type_definition.nil?
|
181
|
+
properties_to_return = {}
|
182
|
+
type_definition.xpath('./Property').each do |property_xml|
|
183
|
+
property_name, property = process_property_from_xml(property_xml)
|
184
|
+
properties_to_return[property_name] = property
|
171
185
|
end
|
172
186
|
properties_to_return
|
173
187
|
end
|
@@ -197,5 +211,15 @@ module OData
|
|
197
211
|
::Nokogiri::XML(response.body).remove_namespaces!
|
198
212
|
}.call
|
199
213
|
end
|
214
|
+
|
215
|
+
def process_property_from_xml(property_xml)
|
216
|
+
property_name = property_xml.attributes['Name'].value
|
217
|
+
value_type = property_xml.attributes['Type'].value
|
218
|
+
property_options = {}
|
219
|
+
property_options[:allows_nil] = false if property_xml.attributes['Nullable'] == 'false'
|
220
|
+
klass_name = value_type.gsub(/^Edm\./, '')
|
221
|
+
property = get_property_class(klass_name).new(property_name, nil, property_options)
|
222
|
+
return [property_name, property]
|
223
|
+
end
|
200
224
|
end
|
201
225
|
end
|
data/lib/odata/version.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<entry xml:base="http://services.odata.org/OData/OData.svc/" xmlns="http://www.w3.org/2005/Atom"
|
3
|
+
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
|
4
|
+
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
|
5
|
+
xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:etag="W/"0"">
|
6
|
+
<id>http://services.odata.org/OData/OData.svc/Suppliers(0)</id>
|
7
|
+
<category term="ODataDemo.Supplier" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
|
8
|
+
<link rel="edit" title="Supplier" href="Suppliers(0)"/>
|
9
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products"
|
10
|
+
type="application/atom+xml;type=feed" title="Products" href="Suppliers(0)/Products"/>
|
11
|
+
<title type="text">Exotic Liquids</title>
|
12
|
+
<updated>2014-09-15T04:34:42Z</updated>
|
13
|
+
<author>
|
14
|
+
<name/>
|
15
|
+
</author>
|
16
|
+
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks/Products" type="application/xml"
|
17
|
+
title="Products" href="Suppliers(0)/$links/Products"/>
|
18
|
+
<content type="application/xml">
|
19
|
+
<m:properties>
|
20
|
+
<d:ID m:type="Edm.Int32">0</d:ID>
|
21
|
+
<d:Name>Exotic Liquids</d:Name>
|
22
|
+
<d:Address m:type="ODataDemo.Address">
|
23
|
+
<d:Street>NE 228th</d:Street>
|
24
|
+
<d:City>Sammamish</d:City>
|
25
|
+
<d:State>WA</d:State>
|
26
|
+
<d:ZipCode>98074</d:ZipCode>
|
27
|
+
<d:Country>USA</d:Country>
|
28
|
+
</d:Address>
|
29
|
+
<d:Location m:type="Edm.GeographyPoint">
|
30
|
+
<gml:Point gml:srsName="http://www.opengis.net/def/crs/EPSG/0/4326">
|
31
|
+
<gml:pos>47.6316604614258 -122.03547668457</gml:pos>
|
32
|
+
</gml:Point>
|
33
|
+
</d:Location>
|
34
|
+
<d:Concurrency m:type="Edm.Int32">0</d:Concurrency>
|
35
|
+
</m:properties>
|
36
|
+
</content>
|
37
|
+
</entry>
|
@@ -0,0 +1,164 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://services.odata.org/OData/OData.svc/$metadata
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Typhoeus - https://github.com/typhoeus/typhoeus
|
12
|
+
response:
|
13
|
+
status:
|
14
|
+
code: 200
|
15
|
+
message: OK
|
16
|
+
headers:
|
17
|
+
Cache-Control:
|
18
|
+
- no-cache
|
19
|
+
Content-Length:
|
20
|
+
- '10034'
|
21
|
+
Content-Type:
|
22
|
+
- application/xml;charset=utf-8
|
23
|
+
Server:
|
24
|
+
- Microsoft-IIS/8.0
|
25
|
+
X-Content-Type-Options:
|
26
|
+
- nosniff
|
27
|
+
DataServiceVersion:
|
28
|
+
- 3.0;
|
29
|
+
X-AspNet-Version:
|
30
|
+
- 4.0.30319
|
31
|
+
X-Powered-By:
|
32
|
+
- ASP.NET
|
33
|
+
Access-Control-Allow-Origin:
|
34
|
+
- "*"
|
35
|
+
Access-Control-Allow-Methods:
|
36
|
+
- GET
|
37
|
+
Access-Control-Allow-Headers:
|
38
|
+
- Accept, Origin, Content-Type, MaxDataServiceVersion
|
39
|
+
Access-Control-Expose-Headers:
|
40
|
+
- DataServiceVersion
|
41
|
+
Set-Cookie:
|
42
|
+
- ARRAffinity=9df27d486a924e1ae61bad0640ee28788b5a0f49ab9983f64ad6636df0c674a5;Path=/;Domain=services.odata.org
|
43
|
+
Date:
|
44
|
+
- Wed, 23 Jul 2014 17:40:38 GMT
|
45
|
+
body:
|
46
|
+
encoding: UTF-8
|
47
|
+
string: <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"><edmx:DataServices
|
48
|
+
m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><Schema
|
49
|
+
Namespace="ODataDemo" xmlns="http://schemas.microsoft.com/ado/2009/11/edm"><EntityType
|
50
|
+
Name="Product"><Key><PropertyRef Name="ID" /></Key><Property Name="ID" Type="Edm.Int32"
|
51
|
+
Nullable="false" /><Property Name="Name" Type="Edm.String" m:FC_TargetPath="SyndicationTitle"
|
52
|
+
m:FC_ContentKind="text" m:FC_KeepInContent="false" /><Property Name="Description"
|
53
|
+
Type="Edm.String" m:FC_TargetPath="SyndicationSummary" m:FC_ContentKind="text"
|
54
|
+
m:FC_KeepInContent="false" /><Property Name="ReleaseDate" Type="Edm.DateTime"
|
55
|
+
Nullable="false" /><Property Name="DiscontinuedDate" Type="Edm.DateTime" /><Property
|
56
|
+
Name="Rating" Type="Edm.Int16" Nullable="false" /><Property Name="Price" Type="Edm.Double"
|
57
|
+
Nullable="false" /><NavigationProperty Name="Categories" Relationship="ODataDemo.Product_Categories_Category_Products"
|
58
|
+
ToRole="Category_Products" FromRole="Product_Categories" /><NavigationProperty
|
59
|
+
Name="Supplier" Relationship="ODataDemo.Product_Supplier_Supplier_Products"
|
60
|
+
ToRole="Supplier_Products" FromRole="Product_Supplier" /><NavigationProperty
|
61
|
+
Name="ProductDetail" Relationship="ODataDemo.Product_ProductDetail_ProductDetail_Product"
|
62
|
+
ToRole="ProductDetail_Product" FromRole="Product_ProductDetail" /></EntityType><EntityType
|
63
|
+
Name="FeaturedProduct" BaseType="ODataDemo.Product"><NavigationProperty Name="Advertisement"
|
64
|
+
Relationship="ODataDemo.FeaturedProduct_Advertisement_Advertisement_FeaturedProduct"
|
65
|
+
ToRole="Advertisement_FeaturedProduct" FromRole="FeaturedProduct_Advertisement"
|
66
|
+
/></EntityType><EntityType Name="ProductDetail"><Key><PropertyRef Name="ProductID"
|
67
|
+
/></Key><Property Name="ProductID" Type="Edm.Int32" Nullable="false" /><Property
|
68
|
+
Name="Details" Type="Edm.String" /><NavigationProperty Name="Product" Relationship="ODataDemo.Product_ProductDetail_ProductDetail_Product"
|
69
|
+
ToRole="Product_ProductDetail" FromRole="ProductDetail_Product" /></EntityType><EntityType
|
70
|
+
Name="Category" OpenType="true"><Key><PropertyRef Name="ID" /></Key><Property
|
71
|
+
Name="ID" Type="Edm.Int32" Nullable="false" /><Property Name="Name" Type="Edm.String"
|
72
|
+
m:FC_TargetPath="SyndicationTitle" m:FC_ContentKind="text" m:FC_KeepInContent="true"
|
73
|
+
/><NavigationProperty Name="Products" Relationship="ODataDemo.Product_Categories_Category_Products"
|
74
|
+
ToRole="Product_Categories" FromRole="Category_Products" /></EntityType><EntityType
|
75
|
+
Name="Supplier"><Key><PropertyRef Name="ID" /></Key><Property Name="ID" Type="Edm.Int32"
|
76
|
+
Nullable="false" /><Property Name="Name" Type="Edm.String" m:FC_TargetPath="SyndicationTitle"
|
77
|
+
m:FC_ContentKind="text" m:FC_KeepInContent="true" /><Property Name="Address"
|
78
|
+
Type="ODataDemo.Address" /><Property Name="Location" Type="Edm.GeographyPoint"
|
79
|
+
SRID="Variable" /><Property Name="Concurrency" Type="Edm.Int32" ConcurrencyMode="Fixed"
|
80
|
+
Nullable="false" /><NavigationProperty Name="Products" Relationship="ODataDemo.Product_Supplier_Supplier_Products"
|
81
|
+
ToRole="Product_Supplier" FromRole="Supplier_Products" /></EntityType><ComplexType
|
82
|
+
Name="Address"><Property Name="Street" Type="Edm.String" /><Property Name="City"
|
83
|
+
Type="Edm.String" /><Property Name="State" Type="Edm.String" /><Property Name="ZipCode"
|
84
|
+
Type="Edm.String" /><Property Name="Country" Type="Edm.String" /></ComplexType><EntityType
|
85
|
+
Name="Person"><Key><PropertyRef Name="ID" /></Key><Property Name="ID" Type="Edm.Int32"
|
86
|
+
Nullable="false" /><Property Name="Name" Type="Edm.String" /><NavigationProperty
|
87
|
+
Name="PersonDetail" Relationship="ODataDemo.Person_PersonDetail_PersonDetail_Person"
|
88
|
+
ToRole="PersonDetail_Person" FromRole="Person_PersonDetail" /></EntityType><EntityType
|
89
|
+
Name="Customer" BaseType="ODataDemo.Person"><Property Name="TotalExpense"
|
90
|
+
Type="Edm.Decimal" Nullable="false" /></EntityType><EntityType Name="Employee"
|
91
|
+
BaseType="ODataDemo.Person"><Property Name="EmployeeID" Type="Edm.Int64" Nullable="false"
|
92
|
+
/><Property Name="HireDate" Type="Edm.DateTime" Nullable="false" /><Property
|
93
|
+
Name="Salary" Type="Edm.Single" Nullable="false" /></EntityType><EntityType
|
94
|
+
Name="PersonDetail"><Key><PropertyRef Name="PersonID" /></Key><Property Name="PersonID"
|
95
|
+
Type="Edm.Int32" Nullable="false" /><Property Name="Age" Type="Edm.Byte" Nullable="false"
|
96
|
+
/><Property Name="Gender" Type="Edm.Boolean" Nullable="false" /><Property
|
97
|
+
Name="Phone" Type="Edm.String" /><Property Name="Address" Type="ODataDemo.Address"
|
98
|
+
/><Property Name="Photo" Type="Edm.Stream" Nullable="false" /><NavigationProperty
|
99
|
+
Name="Person" Relationship="ODataDemo.Person_PersonDetail_PersonDetail_Person"
|
100
|
+
ToRole="Person_PersonDetail" FromRole="PersonDetail_Person" /></EntityType><EntityType
|
101
|
+
Name="Advertisement" m:HasStream="true"><Key><PropertyRef Name="ID" /></Key><Property
|
102
|
+
Name="ID" Type="Edm.Guid" Nullable="false" /><Property Name="Name" Type="Edm.String"
|
103
|
+
/><Property Name="AirDate" Type="Edm.DateTime" Nullable="false" /><NavigationProperty
|
104
|
+
Name="FeaturedProduct" Relationship="ODataDemo.FeaturedProduct_Advertisement_Advertisement_FeaturedProduct"
|
105
|
+
ToRole="FeaturedProduct_Advertisement" FromRole="Advertisement_FeaturedProduct"
|
106
|
+
/></EntityType><Association Name="Product_Categories_Category_Products"><End
|
107
|
+
Type="ODataDemo.Category" Role="Category_Products" Multiplicity="*" /><End
|
108
|
+
Type="ODataDemo.Product" Role="Product_Categories" Multiplicity="*" /></Association><Association
|
109
|
+
Name="Product_Supplier_Supplier_Products"><End Type="ODataDemo.Supplier" Role="Supplier_Products"
|
110
|
+
Multiplicity="0..1" /><End Type="ODataDemo.Product" Role="Product_Supplier"
|
111
|
+
Multiplicity="*" /></Association><Association Name="Product_ProductDetail_ProductDetail_Product"><End
|
112
|
+
Type="ODataDemo.ProductDetail" Role="ProductDetail_Product" Multiplicity="0..1"
|
113
|
+
/><End Type="ODataDemo.Product" Role="Product_ProductDetail" Multiplicity="0..1"
|
114
|
+
/></Association><Association Name="FeaturedProduct_Advertisement_Advertisement_FeaturedProduct"><End
|
115
|
+
Type="ODataDemo.Advertisement" Role="Advertisement_FeaturedProduct" Multiplicity="0..1"
|
116
|
+
/><End Type="ODataDemo.FeaturedProduct" Role="FeaturedProduct_Advertisement"
|
117
|
+
Multiplicity="0..1" /></Association><Association Name="Person_PersonDetail_PersonDetail_Person"><End
|
118
|
+
Type="ODataDemo.PersonDetail" Role="PersonDetail_Person" Multiplicity="0..1"
|
119
|
+
/><End Type="ODataDemo.Person" Role="Person_PersonDetail" Multiplicity="0..1"
|
120
|
+
/></Association><EntityContainer Name="DemoService" m:IsDefaultEntityContainer="true"><EntitySet
|
121
|
+
Name="Products" EntityType="ODataDemo.Product" /><EntitySet Name="ProductDetails"
|
122
|
+
EntityType="ODataDemo.ProductDetail" /><EntitySet Name="Categories" EntityType="ODataDemo.Category"
|
123
|
+
/><EntitySet Name="Suppliers" EntityType="ODataDemo.Supplier" /><EntitySet
|
124
|
+
Name="Persons" EntityType="ODataDemo.Person" /><EntitySet Name="PersonDetails"
|
125
|
+
EntityType="ODataDemo.PersonDetail" /><EntitySet Name="Advertisements" EntityType="ODataDemo.Advertisement"
|
126
|
+
/><FunctionImport Name="GetProductsByRating" ReturnType="Collection(ODataDemo.Product)"
|
127
|
+
EntitySet="Products" m:HttpMethod="GET"><Parameter Name="rating" Type="Edm.Int16"
|
128
|
+
Nullable="false" /></FunctionImport><AssociationSet Name="Products_Advertisement_Advertisements"
|
129
|
+
Association="ODataDemo.FeaturedProduct_Advertisement_Advertisement_FeaturedProduct"><End
|
130
|
+
Role="FeaturedProduct_Advertisement" EntitySet="Products" /><End Role="Advertisement_FeaturedProduct"
|
131
|
+
EntitySet="Advertisements" /></AssociationSet><AssociationSet Name="Products_Categories_Categories"
|
132
|
+
Association="ODataDemo.Product_Categories_Category_Products"><End Role="Product_Categories"
|
133
|
+
EntitySet="Products" /><End Role="Category_Products" EntitySet="Categories"
|
134
|
+
/></AssociationSet><AssociationSet Name="Products_Supplier_Suppliers" Association="ODataDemo.Product_Supplier_Supplier_Products"><End
|
135
|
+
Role="Product_Supplier" EntitySet="Products" /><End Role="Supplier_Products"
|
136
|
+
EntitySet="Suppliers" /></AssociationSet><AssociationSet Name="Products_ProductDetail_ProductDetails"
|
137
|
+
Association="ODataDemo.Product_ProductDetail_ProductDetail_Product"><End Role="Product_ProductDetail"
|
138
|
+
EntitySet="Products" /><End Role="ProductDetail_Product" EntitySet="ProductDetails"
|
139
|
+
/></AssociationSet><AssociationSet Name="Persons_PersonDetail_PersonDetails"
|
140
|
+
Association="ODataDemo.Person_PersonDetail_PersonDetail_Person"><End Role="Person_PersonDetail"
|
141
|
+
EntitySet="Persons" /><End Role="PersonDetail_Person" EntitySet="PersonDetails"
|
142
|
+
/></AssociationSet></EntityContainer><Annotations Target="ODataDemo.DemoService"><ValueAnnotation
|
143
|
+
Term="Org.OData.Display.V1.Description" String="This is a sample OData service
|
144
|
+
with vocabularies" /></Annotations><Annotations Target="ODataDemo.Product"><ValueAnnotation
|
145
|
+
Term="Org.OData.Display.V1.Description" String="All Products available in
|
146
|
+
the online store" /></Annotations><Annotations Target="ODataDemo.Product/Name"><ValueAnnotation
|
147
|
+
Term="Org.OData.Display.V1.DisplayName" String="Product Name" /></Annotations><Annotations
|
148
|
+
Target="ODataDemo.DemoService/Suppliers"><ValueAnnotation Term="Org.OData.Publication.V1.PublisherName"
|
149
|
+
String="Microsoft Corp." /><ValueAnnotation Term="Org.OData.Publication.V1.PublisherId"
|
150
|
+
String="MSFT" /><ValueAnnotation Term="Org.OData.Publication.V1.Keywords"
|
151
|
+
String="Inventory, Supplier, Advertisers, Sales, Finance" /><ValueAnnotation
|
152
|
+
Term="Org.OData.Publication.V1.AttributionUrl" String="http://www.odata.org/"
|
153
|
+
/><ValueAnnotation Term="Org.OData.Publication.V1.AttributionDescription"
|
154
|
+
String="All rights reserved" /><ValueAnnotation Term="Org.OData.Publication.V1.DocumentationUrl
|
155
|
+
" String="http://www.odata.org/" /><ValueAnnotation Term="Org.OData.Publication.V1.TermsOfUseUrl"
|
156
|
+
String="All rights reserved" /><ValueAnnotation Term="Org.OData.Publication.V1.PrivacyPolicyUrl"
|
157
|
+
String="http://www.odata.org/" /><ValueAnnotation Term="Org.OData.Publication.V1.LastModified"
|
158
|
+
String="4/2/2013" /><ValueAnnotation Term="Org.OData.Publication.V1.ImageUrl
|
159
|
+
" String="http://www.odata.org/" /></Annotations></Schema></edmx:DataServices></edmx:Edmx>
|
160
|
+
http_version: '1.1'
|
161
|
+
adapter_metadata:
|
162
|
+
effective_url: http://services.odata.org/OData/OData.svc/$metadata
|
163
|
+
recorded_at: Wed, 23 Jul 2014 17:40:40 GMT
|
164
|
+
recorded_with: VCR 2.9.2
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OData::ComplexType, vcr: {cassette_name: 'complex_type_specs'} do
|
4
|
+
before(:example) do
|
5
|
+
OData::Service.open('http://services.odata.org/OData/OData.svc', name: 'ODataDemo')
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:subject) { OData::ComplexType.new(name: 'Address', service: service) }
|
9
|
+
let(:service) { OData::ServiceRegistry['ODataDemo'] }
|
10
|
+
|
11
|
+
it { expect(subject).to respond_to(:name) }
|
12
|
+
it { expect(subject).to respond_to(:namespace) }
|
13
|
+
it { expect(subject).to respond_to(:property_names) }
|
14
|
+
it { expect(subject).to respond_to(:[]) }
|
15
|
+
it { expect(subject).to respond_to(:[]=) }
|
16
|
+
|
17
|
+
describe 'is properly parsed from service metadata' do
|
18
|
+
it { expect(subject.name).to eq('Address') }
|
19
|
+
it { expect(subject.namespace).to eq('ODataDemo') }
|
20
|
+
it { expect(subject.property_names).to eq(%w{Street City State ZipCode Country}) }
|
21
|
+
|
22
|
+
it { expect(subject['Street']).to be_nil }
|
23
|
+
it { expect(subject['City']).to be_nil }
|
24
|
+
it { expect(subject['State']).to be_nil }
|
25
|
+
it { expect(subject['ZipCode']).to be_nil }
|
26
|
+
it { expect(subject['Country']).to be_nil }
|
27
|
+
|
28
|
+
it { subject['Street'] = 'Test'; expect(subject['Street']).to eq('Test') }
|
29
|
+
it { subject['City'] = 'Test'; expect(subject['City']).to eq('Test') }
|
30
|
+
it { subject['State'] = 'Test'; expect(subject['State']).to eq('Test') }
|
31
|
+
it { subject['ZipCode'] = 'Test'; expect(subject['ZipCode']).to eq('Test') }
|
32
|
+
it { subject['Country'] = 'Test'; expect(subject['Country']).to eq('Test') }
|
33
|
+
end
|
34
|
+
end
|
data/spec/odata/entity_spec.rb
CHANGED
@@ -45,5 +45,27 @@ describe OData::Entity, vcr: {cassette_name: 'entity_specs'} do
|
|
45
45
|
|
46
46
|
it { expect {subject['NonExistant']}.to raise_error(ArgumentError) }
|
47
47
|
it { expect {subject['NonExistant'] = 5}.to raise_error(ArgumentError) }
|
48
|
+
|
49
|
+
context 'with a complex type property' do
|
50
|
+
let(:options) { {
|
51
|
+
type: 'ODataDemo.Supplier',
|
52
|
+
namespace: 'ODataDemo',
|
53
|
+
service_name: 'ODataDemo'
|
54
|
+
} }
|
55
|
+
|
56
|
+
let(:subject) { OData::Entity.from_xml(supplier_xml, options) }
|
57
|
+
let(:supplier_xml) {
|
58
|
+
document = ::Nokogiri::XML(File.open('spec/fixtures/sample_service/supplier_0.xml'))
|
59
|
+
document.remove_namespaces!
|
60
|
+
document.xpath('//entry').first
|
61
|
+
}
|
62
|
+
|
63
|
+
it { expect(subject.name).to eq('Supplier') }
|
64
|
+
it { expect(subject.type).to eq('ODataDemo.Supplier') }
|
65
|
+
|
66
|
+
it { expect(subject['Address']).to be_a(OData::ComplexType) }
|
67
|
+
it { expect(subject['Address']['Street']).to eq('NE 228th') }
|
68
|
+
it { expect(subject['Address']['City']).to eq('Sammamish') }
|
69
|
+
end
|
48
70
|
end
|
49
71
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: odata
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Thompson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -153,6 +153,7 @@ files:
|
|
153
153
|
- README.md
|
154
154
|
- Rakefile
|
155
155
|
- lib/odata.rb
|
156
|
+
- lib/odata/complex_type.rb
|
156
157
|
- lib/odata/entity.rb
|
157
158
|
- lib/odata/entity_set.rb
|
158
159
|
- lib/odata/properties.rb
|
@@ -162,6 +163,7 @@ files:
|
|
162
163
|
- lib/odata/properties/date_time_offset.rb
|
163
164
|
- lib/odata/properties/decimal.rb
|
164
165
|
- lib/odata/properties/float.rb
|
166
|
+
- lib/odata/properties/geography_point.rb
|
165
167
|
- lib/odata/properties/guid.rb
|
166
168
|
- lib/odata/properties/integer.rb
|
167
169
|
- lib/odata/properties/number.rb
|
@@ -187,6 +189,8 @@ files:
|
|
187
189
|
- spec/fixtures/sample_service/products_skip0_top5.xml
|
188
190
|
- spec/fixtures/sample_service/products_skip10_top5.xml
|
189
191
|
- spec/fixtures/sample_service/products_skip5_top5.xml
|
192
|
+
- spec/fixtures/sample_service/supplier_0.xml
|
193
|
+
- spec/fixtures/vcr_cassettes/complex_type_specs.yml
|
190
194
|
- spec/fixtures/vcr_cassettes/entity_set_specs.yml
|
191
195
|
- spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml
|
192
196
|
- spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml
|
@@ -196,6 +200,7 @@ files:
|
|
196
200
|
- spec/fixtures/vcr_cassettes/query_specs.yml
|
197
201
|
- spec/fixtures/vcr_cassettes/service_registry_specs.yml
|
198
202
|
- spec/fixtures/vcr_cassettes/service_specs.yml
|
203
|
+
- spec/odata/complex_type_spec.rb
|
199
204
|
- spec/odata/entity_set_spec.rb
|
200
205
|
- spec/odata/entity_spec.rb
|
201
206
|
- spec/odata/properties/binary_spec.rb
|
@@ -251,6 +256,8 @@ test_files:
|
|
251
256
|
- spec/fixtures/sample_service/products_skip0_top5.xml
|
252
257
|
- spec/fixtures/sample_service/products_skip10_top5.xml
|
253
258
|
- spec/fixtures/sample_service/products_skip5_top5.xml
|
259
|
+
- spec/fixtures/sample_service/supplier_0.xml
|
260
|
+
- spec/fixtures/vcr_cassettes/complex_type_specs.yml
|
254
261
|
- spec/fixtures/vcr_cassettes/entity_set_specs.yml
|
255
262
|
- spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml
|
256
263
|
- spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml
|
@@ -260,6 +267,7 @@ test_files:
|
|
260
267
|
- spec/fixtures/vcr_cassettes/query_specs.yml
|
261
268
|
- spec/fixtures/vcr_cassettes/service_registry_specs.yml
|
262
269
|
- spec/fixtures/vcr_cassettes/service_specs.yml
|
270
|
+
- spec/odata/complex_type_spec.rb
|
263
271
|
- spec/odata/entity_set_spec.rb
|
264
272
|
- spec/odata/entity_spec.rb
|
265
273
|
- spec/odata/properties/binary_spec.rb
|