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 CHANGED
@@ -1,7 +1,7 @@
1
1
  matrix:
2
2
  include:
3
- - rvm: 1.8.7
4
- gemfile: gemfiles/Gemfile.ruby187
3
+ # - rvm: 1.8.7
4
+ # gemfile: gemfiles/Gemfile.ruby187
5
5
  - rvm: 1.9.3
6
6
  gemfile: Gemfile
7
7
  - rvm: 2.0.0
data/CHANGELOG.md CHANGED
@@ -136,3 +136,11 @@
136
136
  * Updated the [VCR](https://github.com/myronmarston/vcr) and [WebMock](https://github.com/bblimke/webmock) gems to the latest versions (used for testing)
137
137
  * Specified activesupport ~> 3.0 (in gemfiles/ruby187) for Ruby 1.8.7 as activesupport 4 doesn't support Ruby < 1.9.3
138
138
 
139
+ ## 0.1.5
140
+ * **BREAKING CHANGES**
141
+ * Previously if the OData service threw an exception, ruby_odata threw a generic error with the message that would start with "HTTP Error XXX: ". Instead of the message, the Error that is thrown is an `OData::ServiceError`. It has an `http_code` property on it, thus, the message is now just the text from the OData error without the "HTTP Error XXX: " prefix. This could potentially cause you problems if you were sniffing error messages for the HTTP error code.
142
+
143
+ * New Features
144
+ * Added the ability to query the OData service using the [$select system query option](http://www.odata.org/documentation/odata-v2-documentation/uri-conventions/#48_Select_System_Query_Option_select)
145
+ * Support for Int64 keys ([issue 39](https://github.com/visoft/ruby_odata/issues/39) and [issue 40](https://github.com/visoft/ruby_odata/pull/40), thanks [@nasali](https://github.com/nasali))
146
+ * New property `is_key` added to `PropertyMetadata` in order to determine the key properties for the class (found in the service's `class_metadata` collection)
@@ -10,5 +10,4 @@ Background:
10
10
 
11
11
  Scenario: Violate a data type conversion (empty string to decimal)
12
12
  Given I call "AddToProducts" on the service with a new "Product" object with Price: ""
13
- When I save changes it should throw an exception with message containing "HTTP Error 400"
14
-
13
+ When I save changes it should throw an exception with message containing "Error encountered in converting the value"
@@ -76,7 +76,7 @@ module OData
76
76
  end
77
77
  end
78
78
  end
79
-
79
+
80
80
  def add_methods(klass)
81
81
  # Add metadata methods
82
82
  klass.send :define_method, :__metadata do
@@ -158,20 +158,20 @@ module OData
158
158
  instance_variable_set("@#{method_name}", value)
159
159
  end
160
160
  end
161
-
161
+
162
162
  # Add an id method pulling out the id from the uri (mainly for Pickle support)
163
163
  klass.send :define_method, :id do
164
164
  metadata = self.__metadata
165
165
  id = nil
166
- if metadata && metadata[:uri] =~ /\((\d+)\)$/
166
+ if metadata && metadata[:uri] =~ /\((\d+)L?\)$/
167
167
  id = $~[1]
168
168
  end
169
169
  return (true if Integer(id) rescue false) ? id.to_i : id
170
170
  end
171
-
171
+
172
172
  # Override equals
173
173
  klass.send :define_method, :== do |other|
174
- self.class == other.class &&
174
+ self.class == other.class &&
175
175
  self.id == other.id &&
176
176
  self.__metadata == other.__metadata
177
177
  end
@@ -195,14 +195,18 @@ module OData
195
195
  klass.send :define_singleton_method, 'properties' do
196
196
  context.class_metadata[klass.to_s] || {}
197
197
  end
198
-
198
+
199
199
  # Finds a single model by ID
200
200
  klass.send :define_singleton_method, 'first' do |id|
201
201
  return nil if id.nil?
202
202
  # TODO: Instead of just pluralizing the klass name, use the actual collection name
203
203
  collection = klass.to_s.pluralize
204
204
  context.send "#{collection}", id
205
- results = context.execute
205
+ begin
206
+ results = context.execute
207
+ rescue OData::ServiceError => e
208
+ return nil
209
+ end
206
210
  results.count == 0 ? nil : results.first
207
211
  end
208
212
  end
@@ -1,4 +1,11 @@
1
1
  module OData
2
2
  # Raised when a user attempts to do something that is not supported
3
3
  class NotSupportedError < StandardError; end
4
+ # Raised when the service returns an error
5
+ class ServiceError < StandardError
6
+ attr_reader :http_code
7
+ def initialize(code)
8
+ @http_code = code
9
+ end
10
+ end
4
11
  end
@@ -15,6 +15,8 @@ module OData
15
15
  attr_reader :nav_prop
16
16
  # Applies only to navigation properties; the association corresponding to the property
17
17
  attr_accessor :association
18
+ # Applies to the primary key(s)
19
+ attr_accessor :is_key
18
20
 
19
21
  # Creates a new instance of the Class Property class
20
22
  #
@@ -18,6 +18,7 @@ class QueryBuilder
18
18
  @filters = []
19
19
  @order_bys = []
20
20
  @navigation_paths = []
21
+ @select = []
21
22
  @skip = nil
22
23
  @top = nil
23
24
  @count = nil
@@ -102,6 +103,7 @@ class QueryBuilder
102
103
  # product_links = svc.execute # => returns URIs for the products under the Category with an ID of 1
103
104
  def links(navigation_property)
104
105
  raise OData::NotSupportedError.new("You cannot call both the `links` method and the `count` method in the same query.") if @count
106
+ raise OData::NotSupportedError.new("You cannot call both the `links` method and the `select` method in the same query.") unless @select.empty?
105
107
  @links_navigation_property = navigation_property
106
108
  self
107
109
  end
@@ -116,6 +118,8 @@ class QueryBuilder
116
118
  # product_count = svc.execute
117
119
  def count
118
120
  raise OData::NotSupportedError.new("You cannot call both the `links` method and the `count` method in the same query.") if @links_navigation_property
121
+ raise OData::NotSupportedError.new("You cannot call both the `select` method and the `count` method in the same query.") unless @select.empty?
122
+
119
123
  @count = true
120
124
  self
121
125
  end
@@ -131,6 +135,28 @@ class QueryBuilder
131
135
  self
132
136
  end
133
137
 
138
+ # Used to customize the properties that are returned for "ad-hoc" queries
139
+ #
140
+ # @param [Array<String>] properties to return
141
+ #
142
+ # @example
143
+ # svc.Products.select('Price', 'Rating')
144
+ def select(*fields)
145
+ raise OData::NotSupportedError.new("You cannot call both the `links` method and the `select` method in the same query.") if @links_navigation_property
146
+ raise OData::NotSupportedError.new("You cannot call both the `count` method and the `select` method in the same query.") if @count
147
+
148
+ @select |= fields
149
+
150
+ expands = fields.find_all { |f| /\// =~ f }
151
+ expands.each do |e|
152
+ parts = e.split '/'
153
+ @expands |= [parts[0...-1].join('/')]
154
+ end
155
+
156
+
157
+ self
158
+ end
159
+
134
160
  # Builds the query URI (path, not including root) incorporating expands, filters, etc.
135
161
  # This is used internally when the execute method is called on the service
136
162
  def query
@@ -150,6 +176,7 @@ class QueryBuilder
150
176
  end
151
177
 
152
178
  query_options = []
179
+ query_options << "$select=#{@select.join(',')}" unless @select.empty?
153
180
  query_options << "$expand=#{@expands.join(',')}" unless @expands.empty?
154
181
  query_options << "$filter=#{@filters.join('+and+')}" unless @filters.empty?
155
182
  query_options << "$orderby=#{@order_bys.join(',')}" unless @order_bys.empty?
@@ -24,9 +24,7 @@ class Service
24
24
  def method_missing(name, *args)
25
25
  # Queries
26
26
  if @collections.include?(name.to_s)
27
- root = "/#{name.to_s}"
28
- root << "(#{args.join(',')})" unless args.empty?
29
- @query = QueryBuilder.new(root, @additional_params)
27
+ @query = build_collection_query_object(name,@additional_params, *args)
30
28
  return @query
31
29
  # Adds
32
30
  elsif name.to_s =~ /^AddTo(.*)/
@@ -96,8 +94,13 @@ class Service
96
94
 
97
95
  # Performs query operations (Read) against the server.
98
96
  # Typically this returns an array of record instances, except in the case of count queries
97
+ # @raise [ServiceError] if there is an error when talking to the service
99
98
  def execute
100
- @response = RestClient::Resource.new(build_query_uri, @rest_options).get
99
+ begin
100
+ @response = RestClient::Resource.new(build_query_uri, @rest_options).get
101
+ rescue Exception => e
102
+ handle_exception(e)
103
+ end
101
104
  return Integer(@response) if @response =~ /^\d+$/
102
105
  handle_collection_result(@response)
103
106
  end
@@ -167,6 +170,51 @@ class Service
167
170
 
168
171
  private
169
172
 
173
+ # Constructs a QueryBuilder instance for a collection using the arguments provided.
174
+ #
175
+ # @param [String] name the name of the collection
176
+ # @param [Hash] additional_parameters the additional parameters
177
+ # @param [Array] args the arguments to use for query
178
+ def build_collection_query_object(name, additional_parameters, *args)
179
+ root = "/#{name.to_s}"
180
+ if args.empty?
181
+ #nothing to add
182
+ elsif args.size == 1
183
+ if args.first.to_s =~ /\d+/
184
+ id_metadata = find_id_metadata(name.to_s)
185
+ root << build_id_path(args.first, id_metadata)
186
+ else
187
+ root << "(#{args.first})"
188
+ end
189
+ else
190
+ root << "(#{args.join(',')})"
191
+ end
192
+ QueryBuilder.new(root, additional_parameters)
193
+ end
194
+
195
+ # Finds the metadata associated with the given collection's first id property
196
+ # Remarks: This is used for single item lookup queries using the ID, e.g. Products(1), not complex primary keys
197
+ #
198
+ # @param [String] collection_name the name of the collection
199
+ def find_id_metadata(collection_name)
200
+ collection_data = @collections.fetch(collection_name)
201
+ class_metadata = @class_metadata.fetch(collection_data[:type].to_s)
202
+ key = class_metadata.select{|k,h| h.is_key }.collect{|k,h| h.name }[0]
203
+ class_metadata[key]
204
+ end
205
+
206
+ # Builds the ID expression of a given id for query
207
+ #
208
+ # @param [Object] id_value the actual value to be used
209
+ # @param [PropertyMetadata] id_metadata the property metadata object for the id
210
+ def build_id_path(id_value, id_metadata)
211
+ if id_metadata.type == "Edm.Int64"
212
+ "(#{id_value}L)"
213
+ else
214
+ "(#{id_value})"
215
+ end
216
+ end
217
+
170
218
  def set_options!(options)
171
219
  @options = options
172
220
  if @options[:eager_partial].nil?
@@ -291,10 +339,12 @@ class Service
291
339
  end
292
340
 
293
341
  # Builds the metadata need for each property for things like feed customizations and navigation properties
294
- def build_property_metadata(props)
342
+ def build_property_metadata(props, keys=[])
295
343
  metadata = {}
296
344
  props.each do |property_element|
297
345
  prop_meta = PropertyMetadata.new(property_element)
346
+ prop_meta.is_key = keys.include?(prop_meta.name)
347
+
298
348
  # If this is a navigation property, we need to add the association to the property metadata
299
349
  prop_meta.association = Association.new(property_element, @edmx) if prop_meta.nav_prop
300
350
  metadata[prop_meta.name] = prop_meta
@@ -319,13 +369,15 @@ class Service
319
369
  error = Nokogiri::XML(e.response)
320
370
 
321
371
  message = error.xpath("m:error/m:message", @ds_namespaces).first.content
322
- raise "HTTP Error #{code}: #{message}"
372
+ raise ServiceError.new(code), message
323
373
  end
324
374
 
325
375
  # Loops through the standard properties (non-navigation) for a given class and returns the appropriate list of methods
326
376
  def collect_properties(klass_name, element, doc)
327
377
  props = element.xpath(".//edm:Property", @ds_namespaces)
328
- @class_metadata[klass_name] = build_property_metadata(props)
378
+ key_elemnts = element.xpath(".//edm:Key//edm:PropertyRef", @ds_namespaces)
379
+ keys = key_elemnts.collect { |k| k['Name'] }
380
+ @class_metadata[klass_name] = build_property_metadata(props, keys)
329
381
  methods = props.collect { |p| p['Name'] }
330
382
  unless element["BaseType"].nil?
331
383
  base = element["BaseType"].split(".").last()
@@ -1,5 +1,5 @@
1
1
  # The ruby_odata namespace
2
2
  module OData
3
3
  # The current version of ruby_odata
4
- VERSION = "0.1.4"
4
+ VERSION = "0.1.5"
5
5
  end
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
3
+ <edmx:DataServices m:DataServiceVersion="1.0" m:MaxDataServiceVersion="2.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
4
+ <Schema Namespace="Model" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
5
+ <EntityType Name="Boat">
6
+ <Key>
7
+ <PropertyRef Name="KeyId" />
8
+ </Key>
9
+ <Property Name="KeyId" Type="Edm.Int64" Nullable="false" p6:StoreGeneratedPattern="Identity" xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation" />
10
+ <Property Name="color" Type="Edm.String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="false" />
11
+ </EntityType>
12
+ </Schema>
13
+ <Schema Namespace="WebApp" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
14
+ <EntityContainer Name="adoEntities" m:IsDefaultEntityContainer="true" p6:LazyLoadingEnabled="true" xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation">
15
+ <EntitySet Name="Boats" EntityType="Model.Boat" />
16
+ </EntityContainer>
17
+ </Schema>
18
+ </edmx:DataServices>
19
+ </edmx:Edmx>
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
3
+ <edmx:DataServices m:DataServiceVersion="1.0" m:MaxDataServiceVersion="2.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
4
+ <Schema Namespace="Model" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
5
+ <EntityType Name="Car">
6
+ <Key>
7
+ <PropertyRef Name="id" />
8
+ </Key>
9
+ <Property Name="id" Type="Edm.Int64" Nullable="false" p6:StoreGeneratedPattern="Identity" xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation" />
10
+ <Property Name="color" Type="Edm.String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="false" />
11
+ <Property Name="num_spots" Type="Edm.Int32" />
12
+ <Property Name="striped" Type="Edm.Byte" />
13
+ </EntityType>
14
+ </Schema>
15
+ <Schema Namespace="WebApp" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
16
+ <EntityContainer Name="adoEntities" m:IsDefaultEntityContainer="true" p6:LazyLoadingEnabled="true" xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation">
17
+ <EntitySet Name="Cars" EntityType="Model.Car" />
18
+ </EntityContainer>
19
+ </Schema>
20
+ </edmx:DataServices>
21
+ </edmx:Edmx>
@@ -0,0 +1,26 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xml:base="http://test.com/test.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
+ <id>http://test.com/test.svc/Boats</id>
7
+ <title type="text">Boats</title>
8
+ <updated>2013-10-28T19:59:15Z</updated>
9
+ <link rel="self" title="Boats" href="Boats" />
10
+ <entry>
11
+ <id>http://test.com/test.svc/Boats(213L)</id>
12
+ <category term="Model.Boat" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
13
+ <link rel="edit" title="Boat" href="Boats(213L)" />
14
+ <title />
15
+ <updated>2013-10-28T19:59:15Z</updated>
16
+ <author>
17
+ <name />
18
+ </author>
19
+ <content type="application/xml">
20
+ <m:properties>
21
+ <d:KeyId m:type="Edm.Int64">213</d:KeyId>
22
+ <d:color>blue</d:color>
23
+ </m:properties>
24
+ </content>
25
+ </entry>
26
+ </feed>
@@ -0,0 +1,28 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xml:base="http://test.com/test.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
+ <id>http://test.com/test.svc/Cars</id>
7
+ <title type="text">Cars</title>
8
+ <updated>2013-10-28T19:59:15Z</updated>
9
+ <link rel="self" title="Cars" href="Cars" />
10
+ <entry>
11
+ <id>http://test.com/test.svc/Cars(213L)</id>
12
+ <category term="Model.Car" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
13
+ <link rel="edit" title="Car" href="Cars(213L)" />
14
+ <title />
15
+ <updated>2013-10-28T19:59:15Z</updated>
16
+ <author>
17
+ <name />
18
+ </author>
19
+ <content type="application/xml">
20
+ <m:properties>
21
+ <d:id m:type="Edm.Int64">213</d:id>
22
+ <d:color>peach</d:color>
23
+ <d:num_spots m:type="Edm.Int32" m:null="true" />
24
+ <d:striped m:type="Edm.Byte" m:null="true" />
25
+ </m:properties>
26
+ </content>
27
+ </entry>
28
+ </feed>
@@ -0,0 +1,268 @@
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/Categories</id>
9
+ <title type="text">Categories</title>
10
+ <updated>2013-07-22T14:54:47Z</updated>
11
+ <link rel="self" title="Categories" href="Categories" />
12
+ <entry>
13
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(1)</id>
14
+ <category term="RubyODataService.Category" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
15
+ <link rel="edit" title="Category" href="Categories(1)" />
16
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products" type="application/atom+xml;type=feed" title="Products" href="Categories(1)/Products">
17
+ <m:inline>
18
+ <feed>
19
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(1)/Products</id>
20
+ <title type="text">Products</title>
21
+ <updated>2013-07-22T14:54:47Z</updated>
22
+ <link rel="self" title="Products" href="Categories(1)/Products" />
23
+ <entry>
24
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Products(1)</id>
25
+ <category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
26
+ <link rel="edit" title="Product" href="Products(1)" />
27
+ <title />
28
+ <updated>2013-07-22T14:54:47Z</updated>
29
+ <author>
30
+ <name />
31
+ </author>
32
+ <content type="application/xml">
33
+ <m:properties>
34
+ <d:Name>Widget 0001</d:Name>
35
+ </m:properties>
36
+ </content>
37
+ </entry>
38
+ </feed>
39
+ </m:inline>
40
+ </link>
41
+ <title />
42
+ <updated>2013-07-22T14:54:47Z</updated>
43
+ <author>
44
+ <name />
45
+ </author>
46
+ <content type="application/xml">
47
+ <m:properties>
48
+ <d:Name>Category 0001</d:Name>
49
+ </m:properties>
50
+ </content>
51
+ </entry>
52
+ <entry>
53
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(2)</id>
54
+ <category term="RubyODataService.Category" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
55
+ <link rel="edit" title="Category" href="Categories(2)" />
56
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products" type="application/atom+xml;type=feed" title="Products" href="Categories(2)/Products">
57
+ <m:inline>
58
+ <feed>
59
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(2)/Products</id>
60
+ <title type="text">Products</title>
61
+ <updated>2013-07-22T14:54:47Z</updated>
62
+ <link rel="self" title="Products" href="Categories(2)/Products" />
63
+ <entry>
64
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Products(2)</id>
65
+ <category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
66
+ <link rel="edit" title="Product" href="Products(2)" />
67
+ <title />
68
+ <updated>2013-07-22T14:54:47Z</updated>
69
+ <author>
70
+ <name />
71
+ </author>
72
+ <content type="application/xml">
73
+ <m:properties>
74
+ <d:Name>Widget 0002</d:Name>
75
+ </m:properties>
76
+ </content>
77
+ </entry>
78
+ </feed>
79
+ </m:inline>
80
+ </link>
81
+ <title />
82
+ <updated>2013-07-22T14:54:47Z</updated>
83
+ <author>
84
+ <name />
85
+ </author>
86
+ <content type="application/xml">
87
+ <m:properties>
88
+ <d:Name>Category 0001</d:Name>
89
+ </m:properties>
90
+ </content>
91
+ </entry>
92
+ <entry>
93
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(3)</id>
94
+ <category term="RubyODataService.Category" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
95
+ <link rel="edit" title="Category" href="Categories(3)" />
96
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products" type="application/atom+xml;type=feed" title="Products" href="Categories(3)/Products">
97
+ <m:inline>
98
+ <feed>
99
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(3)/Products</id>
100
+ <title type="text">Products</title>
101
+ <updated>2013-07-22T14:54:47Z</updated>
102
+ <link rel="self" title="Products" href="Categories(3)/Products" />
103
+ <entry>
104
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Products(3)</id>
105
+ <category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
106
+ <link rel="edit" title="Product" href="Products(3)" />
107
+ <title />
108
+ <updated>2013-07-22T14:54:47Z</updated>
109
+ <author>
110
+ <name />
111
+ </author>
112
+ <content type="application/xml">
113
+ <m:properties>
114
+ <d:Name>Widget 0003</d:Name>
115
+ </m:properties>
116
+ </content>
117
+ </entry>
118
+ </feed>
119
+ </m:inline>
120
+ </link>
121
+ <title />
122
+ <updated>2013-07-22T14:54:47Z</updated>
123
+ <author>
124
+ <name />
125
+ </author>
126
+ <content type="application/xml">
127
+ <m:properties>
128
+ <d:Name>Category 0002</d:Name>
129
+ </m:properties>
130
+ </content>
131
+ </entry>
132
+ <entry>
133
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(4)</id>
134
+ <category term="RubyODataService.Category" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
135
+ <link rel="edit" title="Category" href="Categories(4)" />
136
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products" type="application/atom+xml;type=feed" title="Products" href="Categories(4)/Products">
137
+ <m:inline>
138
+ <feed>
139
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(4)/Products</id>
140
+ <title type="text">Products</title>
141
+ <updated>2013-07-22T14:54:47Z</updated>
142
+ <link rel="self" title="Products" href="Categories(4)/Products" />
143
+ <entry>
144
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Products(4)</id>
145
+ <category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
146
+ <link rel="edit" title="Product" href="Products(4)" />
147
+ <title />
148
+ <updated>2013-07-22T14:54:47Z</updated>
149
+ <author>
150
+ <name />
151
+ </author>
152
+ <content type="application/xml">
153
+ <m:properties>
154
+ <d:Name>Widget 0004</d:Name>
155
+ </m:properties>
156
+ </content>
157
+ </entry>
158
+ </feed>
159
+ </m:inline>
160
+ </link>
161
+ <title />
162
+ <updated>2013-07-22T14:54:47Z</updated>
163
+ <author>
164
+ <name />
165
+ </author>
166
+ <content type="application/xml">
167
+ <m:properties>
168
+ <d:Name>Category 0002</d:Name>
169
+ </m:properties>
170
+ </content>
171
+ </entry>
172
+ <entry>
173
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(5)</id>
174
+ <category term="RubyODataService.Category" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
175
+ <link rel="edit" title="Category" href="Categories(5)" />
176
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products" type="application/atom+xml;type=feed" title="Products" href="Categories(5)/Products">
177
+ <m:inline>
178
+ <feed>
179
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(5)/Products</id>
180
+ <title type="text">Products</title>
181
+ <updated>2013-07-22T14:54:47Z</updated>
182
+ <link rel="self" title="Products" href="Categories(5)/Products" />
183
+ <entry>
184
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Products(5)</id>
185
+ <category term="RubyODataService.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
186
+ <link rel="edit" title="Product" href="Products(5)" />
187
+ <title />
188
+ <updated>2013-07-22T14:54:47Z</updated>
189
+ <author>
190
+ <name />
191
+ </author>
192
+ <content type="application/xml">
193
+ <m:properties>
194
+ <d:Name>Widget 0005</d:Name>
195
+ </m:properties>
196
+ </content>
197
+ </entry>
198
+ </feed>
199
+ </m:inline>
200
+ </link>
201
+ <title />
202
+ <updated>2013-07-22T14:54:47Z</updated>
203
+ <author>
204
+ <name />
205
+ </author>
206
+ <content type="application/xml">
207
+ <m:properties>
208
+ <d:Name>Category 0002</d:Name>
209
+ </m:properties>
210
+ </content>
211
+ </entry>
212
+ <entry>
213
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(6)</id>
214
+ <category term="RubyODataService.Category" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
215
+ <link rel="edit" title="Category" href="Categories(6)" />
216
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products" type="application/atom+xml;type=feed" title="Products" href="Categories(6)/Products">
217
+ <m:inline>
218
+ <feed>
219
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(6)/Products</id>
220
+ <title type="text">Products</title>
221
+ <updated>2013-07-22T14:54:47Z</updated>
222
+ <link rel="self" title="Products" href="Categories(6)/Products" />
223
+ <author>
224
+ <name />
225
+ </author>
226
+ </feed>
227
+ </m:inline>
228
+ </link>
229
+ <title />
230
+ <updated>2013-07-22T14:54:47Z</updated>
231
+ <author>
232
+ <name />
233
+ </author>
234
+ <content type="application/xml">
235
+ <m:properties>
236
+ <d:Name>Category 0001</d:Name>
237
+ </m:properties>
238
+ </content>
239
+ </entry>
240
+ <entry>
241
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(7)</id>
242
+ <category term="RubyODataService.Category" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
243
+ <link rel="edit" title="Category" href="Categories(7)" />
244
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products" type="application/atom+xml;type=feed" title="Products" href="Categories(7)/Products">
245
+ <m:inline>
246
+ <feed>
247
+ <id>http://win7dev:8989/SampleService/RubyOData.svc/Categories(7)/Products</id>
248
+ <title type="text">Products</title>
249
+ <updated>2013-07-22T14:54:47Z</updated>
250
+ <link rel="self" title="Products" href="Categories(7)/Products" />
251
+ <author>
252
+ <name />
253
+ </author>
254
+ </feed>
255
+ </m:inline>
256
+ </link>
257
+ <title />
258
+ <updated>2013-07-22T14:54:47Z</updated>
259
+ <author>
260
+ <name />
261
+ </author>
262
+ <content type="application/xml">
263
+ <m:properties>
264
+ <d:Name>Category 0002</d:Name>
265
+ </m:properties>
266
+ </content>
267
+ </entry>
268
+ </feed>