frodata 0.9.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.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +2 -0
  3. data/.gitignore +24 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +75 -0
  8. data/CHANGELOG.md +150 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +23 -0
  11. data/README.md +427 -0
  12. data/Rakefile +7 -0
  13. data/TODO.md +55 -0
  14. data/frodata.gemspec +34 -0
  15. data/lib/frodata.rb +36 -0
  16. data/lib/frodata/entity.rb +332 -0
  17. data/lib/frodata/entity_container.rb +75 -0
  18. data/lib/frodata/entity_set.rb +161 -0
  19. data/lib/frodata/errors.rb +68 -0
  20. data/lib/frodata/navigation_property.rb +29 -0
  21. data/lib/frodata/navigation_property/proxy.rb +80 -0
  22. data/lib/frodata/properties.rb +32 -0
  23. data/lib/frodata/properties/binary.rb +50 -0
  24. data/lib/frodata/properties/boolean.rb +37 -0
  25. data/lib/frodata/properties/collection.rb +50 -0
  26. data/lib/frodata/properties/complex.rb +114 -0
  27. data/lib/frodata/properties/date.rb +27 -0
  28. data/lib/frodata/properties/date_time.rb +83 -0
  29. data/lib/frodata/properties/date_time_offset.rb +17 -0
  30. data/lib/frodata/properties/decimal.rb +50 -0
  31. data/lib/frodata/properties/enum.rb +62 -0
  32. data/lib/frodata/properties/float.rb +67 -0
  33. data/lib/frodata/properties/geography.rb +13 -0
  34. data/lib/frodata/properties/geography/base.rb +162 -0
  35. data/lib/frodata/properties/geography/line_string.rb +33 -0
  36. data/lib/frodata/properties/geography/point.rb +31 -0
  37. data/lib/frodata/properties/geography/polygon.rb +38 -0
  38. data/lib/frodata/properties/guid.rb +17 -0
  39. data/lib/frodata/properties/integer.rb +107 -0
  40. data/lib/frodata/properties/number.rb +14 -0
  41. data/lib/frodata/properties/string.rb +72 -0
  42. data/lib/frodata/properties/time.rb +40 -0
  43. data/lib/frodata/properties/time_of_day.rb +27 -0
  44. data/lib/frodata/property.rb +139 -0
  45. data/lib/frodata/property_registry.rb +41 -0
  46. data/lib/frodata/query.rb +233 -0
  47. data/lib/frodata/query/criteria.rb +92 -0
  48. data/lib/frodata/query/criteria/comparison_operators.rb +49 -0
  49. data/lib/frodata/query/criteria/date_functions.rb +61 -0
  50. data/lib/frodata/query/criteria/geography_functions.rb +21 -0
  51. data/lib/frodata/query/criteria/lambda_operators.rb +27 -0
  52. data/lib/frodata/query/criteria/string_functions.rb +40 -0
  53. data/lib/frodata/query/in_batches.rb +58 -0
  54. data/lib/frodata/railtie.rb +19 -0
  55. data/lib/frodata/schema.rb +155 -0
  56. data/lib/frodata/schema/complex_type.rb +79 -0
  57. data/lib/frodata/schema/enum_type.rb +95 -0
  58. data/lib/frodata/service.rb +254 -0
  59. data/lib/frodata/service/request.rb +85 -0
  60. data/lib/frodata/service/response.rb +162 -0
  61. data/lib/frodata/service/response/atom.rb +40 -0
  62. data/lib/frodata/service/response/json.rb +41 -0
  63. data/lib/frodata/service/response/plain.rb +36 -0
  64. data/lib/frodata/service/response/xml.rb +40 -0
  65. data/lib/frodata/service_registry.rb +52 -0
  66. data/lib/frodata/version.rb +3 -0
  67. data/spec/fixtures/files/entity_to_xml.xml +17 -0
  68. data/spec/fixtures/files/error.xml +5 -0
  69. data/spec/fixtures/files/metadata.xml +150 -0
  70. data/spec/fixtures/files/product_0.json +10 -0
  71. data/spec/fixtures/files/product_0.xml +28 -0
  72. data/spec/fixtures/files/products.json +106 -0
  73. data/spec/fixtures/files/products.xml +308 -0
  74. data/spec/fixtures/files/supplier_0.json +26 -0
  75. data/spec/fixtures/files/supplier_0.xml +32 -0
  76. data/spec/fixtures/vcr_cassettes/entity_set_specs.yml +1635 -0
  77. data/spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml +183 -0
  78. data/spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml +256 -0
  79. data/spec/fixtures/vcr_cassettes/entity_set_specs/new_entry.yml +185 -0
  80. data/spec/fixtures/vcr_cassettes/entity_specs.yml +285 -0
  81. data/spec/fixtures/vcr_cassettes/navigation_property_proxy_specs.yml +346 -0
  82. data/spec/fixtures/vcr_cassettes/query/result_specs.yml +189 -0
  83. data/spec/fixtures/vcr_cassettes/query_specs.yml +1060 -0
  84. data/spec/fixtures/vcr_cassettes/schema/complex_type_specs.yml +127 -0
  85. data/spec/fixtures/vcr_cassettes/service/request_specs.yml +193 -0
  86. data/spec/fixtures/vcr_cassettes/service_registry_specs.yml +129 -0
  87. data/spec/fixtures/vcr_cassettes/service_specs.yml +127 -0
  88. data/spec/fixtures/vcr_cassettes/usage_example_specs.yml +1330 -0
  89. data/spec/frodata/entity/shared_examples.rb +82 -0
  90. data/spec/frodata/entity_container_spec.rb +38 -0
  91. data/spec/frodata/entity_set_spec.rb +168 -0
  92. data/spec/frodata/entity_spec.rb +151 -0
  93. data/spec/frodata/errors_spec.rb +48 -0
  94. data/spec/frodata/navigation_property/proxy_spec.rb +44 -0
  95. data/spec/frodata/navigation_property_spec.rb +55 -0
  96. data/spec/frodata/properties/binary_spec.rb +50 -0
  97. data/spec/frodata/properties/boolean_spec.rb +72 -0
  98. data/spec/frodata/properties/collection_spec.rb +44 -0
  99. data/spec/frodata/properties/date_spec.rb +23 -0
  100. data/spec/frodata/properties/date_time_offset_spec.rb +30 -0
  101. data/spec/frodata/properties/date_time_spec.rb +23 -0
  102. data/spec/frodata/properties/decimal_spec.rb +51 -0
  103. data/spec/frodata/properties/float_spec.rb +45 -0
  104. data/spec/frodata/properties/geography/line_string_spec.rb +33 -0
  105. data/spec/frodata/properties/geography/point_spec.rb +29 -0
  106. data/spec/frodata/properties/geography/polygon_spec.rb +55 -0
  107. data/spec/frodata/properties/geography/shared_examples.rb +72 -0
  108. data/spec/frodata/properties/guid_spec.rb +17 -0
  109. data/spec/frodata/properties/integer_spec.rb +58 -0
  110. data/spec/frodata/properties/string_spec.rb +46 -0
  111. data/spec/frodata/properties/time_of_day_spec.rb +23 -0
  112. data/spec/frodata/properties/time_spec.rb +15 -0
  113. data/spec/frodata/property_registry_spec.rb +16 -0
  114. data/spec/frodata/property_spec.rb +71 -0
  115. data/spec/frodata/query/criteria_spec.rb +229 -0
  116. data/spec/frodata/query_spec.rb +199 -0
  117. data/spec/frodata/schema/complex_type_spec.rb +96 -0
  118. data/spec/frodata/schema/enum_type_spec.rb +112 -0
  119. data/spec/frodata/schema_spec.rb +97 -0
  120. data/spec/frodata/service/request_spec.rb +49 -0
  121. data/spec/frodata/service/response_spec.rb +85 -0
  122. data/spec/frodata/service_registry_spec.rb +18 -0
  123. data/spec/frodata/service_spec.rb +191 -0
  124. data/spec/frodata/usage_example_spec.rb +188 -0
  125. data/spec/spec_helper.rb +32 -0
  126. data/spec/support/coverage.rb +2 -0
  127. data/spec/support/vcr.rb +9 -0
  128. metadata +401 -0
@@ -0,0 +1,162 @@
1
+ require 'frodata/service/response/atom'
2
+ require 'frodata/service/response/json'
3
+ require 'frodata/service/response/plain'
4
+ require 'frodata/service/response/xml'
5
+
6
+ module FrOData
7
+ class Service
8
+ # The result of executing a FrOData::Service::Request.
9
+ class Response
10
+ include Enumerable
11
+
12
+ # The service that generated this response
13
+ attr_reader :service
14
+ # The underlying (raw) response
15
+ attr_reader :response
16
+ # The query that generated the response (optional)
17
+ attr_reader :query
18
+
19
+ # Create a new response given a service and a raw response.
20
+ # @param service [FrOData::Service] The executing service.
21
+ # @param query [FrOData::Query] The related query (optional).
22
+ # @param
23
+ def initialize(service, query = nil, &block)
24
+ @service = service
25
+ @query = query
26
+ @timed_out = false
27
+ execute(&block)
28
+ end
29
+
30
+ # Returns the HTTP status code.
31
+ def status
32
+ response.status
33
+ end
34
+
35
+ # Whether the request was successful.
36
+ def success?
37
+ 200 <= status && status < 300
38
+ end
39
+
40
+ # Returns the content type of the resonse.
41
+ def content_type
42
+ response.headers['Content-Type'] || ''
43
+ end
44
+
45
+ def is_atom?
46
+ content_type =~ /#{Regexp.escape FrOData::Service::MIME_TYPES[:atom]}/
47
+ end
48
+
49
+ def is_json?
50
+ content_type =~ /#{Regexp.escape FrOData::Service::MIME_TYPES[:json]}/
51
+ end
52
+
53
+ def is_plain?
54
+ content_type =~ /#{Regexp.escape FrOData::Service::MIME_TYPES[:plain]}/
55
+ end
56
+
57
+ def is_xml?
58
+ content_type =~ /#{Regexp.escape FrOData::Service::MIME_TYPES[:xml]}/
59
+ end
60
+
61
+ # Whether the response contained any entities.
62
+ # @return [Boolean]
63
+ def empty?
64
+ @empty ||= find_entities.empty?
65
+ end
66
+
67
+ # Whether the response failed due to a timeout
68
+ def timed_out?
69
+ @timed_out
70
+ end
71
+
72
+ # Iterates over all entities in the response, using
73
+ # automatic paging if necessary.
74
+ # Provided for Enumerable functionality.
75
+ # @param block [block] a block to evaluate
76
+ # @return [FrOData::Entity] each entity in turn for the query result
77
+ def each(&block)
78
+ unless empty?
79
+ process_results(&block)
80
+ unless next_page.nil?
81
+ # ensure request gets executed with the same options
82
+ query.execute(URI.decode next_page_url).each(&block)
83
+ end
84
+ end
85
+ end
86
+
87
+ # Returns the response body.
88
+ def body
89
+ response.body
90
+ end
91
+
92
+ # Validates the response. Throws an exception with
93
+ # an appropriate message if a 4xx or 5xx status code
94
+ # occured.
95
+ #
96
+ # @return [self]
97
+ def validate_response!
98
+ if error = FrOData::Errors::ERROR_MAP[status]
99
+ raise error, response, error_message
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def execute(&block)
106
+ @response = block.call
107
+ logger.debug <<-EOS
108
+ [FrOData: #{service.name}] Received response:
109
+ Headers: #{response.headers}
110
+ Body: #{response.body}
111
+ EOS
112
+ check_content_type
113
+ validate_response!
114
+ rescue Faraday::TimeoutError
115
+ logger.info "Request timed out."
116
+ @timed_out = true
117
+ end
118
+
119
+ def logger
120
+ service.logger
121
+ end
122
+
123
+ def check_content_type
124
+ # Dynamically extend instance with methods for
125
+ # processing the current result type
126
+ if is_atom?
127
+ extend FrOData::Service::Response::Atom
128
+ elsif is_json?
129
+ extend FrOData::Service::Response::JSON
130
+ elsif is_xml?
131
+ extend FrOData::Service::Response::XML
132
+ elsif is_plain?
133
+ extend FrOData::Service::Response::Plain
134
+ elsif response.body.empty?
135
+ # Some services (*cough* Microsoft *cough*) return
136
+ # an empty response with no `Content-Type` header set.
137
+ # We catch that here and bypass content type detection.
138
+ @empty = true
139
+ else
140
+ raise RequestError, response, "Invalid response type '#{content_type}'"
141
+ end
142
+ end
143
+
144
+ def entity_options
145
+ if query
146
+ query.entity_set.entity_options
147
+ else
148
+ {
149
+ service_name: service.name,
150
+ }
151
+ end
152
+ end
153
+
154
+ def process_results(&block)
155
+ find_entities.each do |entity_data|
156
+ entity = parse_entity(entity_data, entity_options)
157
+ block_given? ? block.call(entity) : yield(entity)
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,40 @@
1
+ module FrOData
2
+ class Service
3
+ class Response
4
+ module Atom
5
+ def parse_entity(entity_xml, entity_options)
6
+ FrOData::Entity.from_xml(entity_xml, entity_options)
7
+ end
8
+
9
+ def next_page
10
+ result_xml.xpath("/feed/link[@rel='next']").first
11
+ end
12
+
13
+ def next_page_url
14
+ next_page.attributes['href'].value.gsub(service.service_url, '')
15
+ end
16
+
17
+ def error_message
18
+ result_xml.xpath('//error/message').first.andand.text
19
+ end
20
+
21
+ def parsed_body
22
+ result_xml
23
+ end
24
+
25
+ private
26
+
27
+ def result_xml
28
+ @result_xml ||= ::Nokogiri::XML(response.body).remove_namespaces!
29
+ end
30
+
31
+ # Find entity entries in a result set
32
+ #
33
+ # @return [Nokogiri::XML::NodeSet]
34
+ def find_entities
35
+ result_xml.xpath('//entry')
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ module FrOData
2
+ class Service
3
+ class Response
4
+ module JSON
5
+ def parse_entity(entity_json, entity_options)
6
+ FrOData::Entity.from_json(entity_json, entity_options)
7
+ end
8
+
9
+ def next_page
10
+ result_json['@odata.nextLink']
11
+ end
12
+
13
+ def next_page_url
14
+ next_page.gsub(service.service_url, '')
15
+ end
16
+
17
+ def error_message
18
+ result_json['error'].andand['message']
19
+ end
20
+
21
+ def parsed_body
22
+ result_json
23
+ end
24
+
25
+ private
26
+
27
+ def result_json
28
+ @result_json ||= ::JSON.parse(response.body)
29
+ end
30
+
31
+ def single_entity?
32
+ result_json['@odata.context'] =~ /\$entity$/
33
+ end
34
+
35
+ def find_entities
36
+ single_entity? ? [result_json] : result_json['value']
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ module FrOData
2
+ class Service
3
+ class Response
4
+ module Plain
5
+ def parse_entity(entity_data, entity_options)
6
+ raise NotImplementedError, 'Not Available'
7
+ end
8
+
9
+ def next_page
10
+ raise NotImplementedError, 'Not available'
11
+ end
12
+
13
+ def next_page_url
14
+ raise NotImplementedError, 'Not available'
15
+ end
16
+
17
+ def error_message
18
+ response.body
19
+ end
20
+
21
+ def parsed_body
22
+ response.body
23
+ end
24
+
25
+ private
26
+
27
+ # Find entity entries in a response set
28
+ #
29
+ # @return [Array]
30
+ def find_entities
31
+ []
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ module FrOData
2
+ class Service
3
+ class Response
4
+ module XML
5
+ def parse_entity(entity_data, entity_options)
6
+ raise NotImplementedError, 'Not Available'
7
+ end
8
+
9
+ def next_page
10
+ raise NotImplementedError, 'Not Available'
11
+ end
12
+
13
+ def next_page_url
14
+ raise NotImplementedError, 'Not Available'
15
+ end
16
+
17
+ def error_message
18
+ response_xml.xpath('//error/message').first.andand.text
19
+ end
20
+
21
+ def parsed_body
22
+ response_xml
23
+ end
24
+
25
+ private
26
+
27
+ def response_xml
28
+ @response_xml ||= ::Nokogiri::XML(response.body).remove_namespaces!
29
+ end
30
+
31
+ # Find entity entries in a response set
32
+ #
33
+ # @return [Array]
34
+ def find_entities
35
+ []
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,52 @@
1
+ require 'singleton'
2
+
3
+ module FrOData
4
+ # Provides a registry for keeping track of multiple FrOData::Service instances
5
+ class ServiceRegistry
6
+ include Singleton
7
+
8
+ # Add a service to the Registry
9
+ #
10
+ # @param service [FrOData::Service] service to add to the registry
11
+ def add(service)
12
+ initialize_instance_variables
13
+ @services << service if service.is_a?(FrOData::Service) && !@services.include?(service)
14
+ @services_by_name[service.name] = @services.find_index(service)
15
+ @services_by_url[service.service_url] = @services.find_index(service)
16
+ end
17
+
18
+ # Lookup a service by URL or name
19
+ #
20
+ # @param lookup_key [String] the URL or name to lookup
21
+ # @return [FrOData::Service, nil] the FrOData::Service or nil
22
+ def [](lookup_key)
23
+ initialize_instance_variables
24
+ index = @services_by_name[lookup_key] || @services_by_url[lookup_key]
25
+ index.nil? ? nil : @services[index]
26
+ end
27
+
28
+ # (see #add)
29
+ def self.add(service)
30
+ FrOData::ServiceRegistry.instance.add(service)
31
+ end
32
+
33
+ # (see #[])
34
+ def self.[](lookup_key)
35
+ FrOData::ServiceRegistry.instance[lookup_key]
36
+ end
37
+
38
+ private
39
+
40
+ def initialize_instance_variables
41
+ @services ||= []
42
+ @services_by_name ||= {}
43
+ @services_by_url ||= {}
44
+ end
45
+
46
+ def flush
47
+ @services = []
48
+ @services_by_name = {}
49
+ @services_by_url = {}
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module FrOData
2
+ VERSION = '0.9.1'
3
+ end
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0"?>
2
+ <entry xmlns="http://www.w3.org/2005/Atom" xmlns:data="http://docs.oasis-open.org/odata/ns/data" xmlns:metadata="http://docs.oasis-open.org/odata/ns/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xml:base="http://services.odata.org/V4/OData/OData.svc">
3
+ <category term="ODataDemo.Product" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
4
+ <author>
5
+ <name/>
6
+ </author>
7
+ <content type="application/xml">
8
+ <metadata:properties>
9
+ <data:Name metadata:type="Edm.String">Bread</data:Name>
10
+ <data:Description metadata:type="Edm.String">Whole grain bread</data:Description>
11
+ <data:ReleaseDate metadata:type="Edm.DateTimeOffset">1992-01-01T00:00:00Z</data:ReleaseDate>
12
+ <data:DiscontinuedDate metadata:type="Edm.DateTimeOffset" metadata:null="true"/>
13
+ <data:Rating metadata:type="Edm.Int16">4</data:Rating>
14
+ <data:Price metadata:type="Edm.Double">2.5</data:Price>
15
+ </metadata:properties>
16
+ </content>
17
+ </entry>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <m:error xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
3
+ <m:code />
4
+ <m:message>Resource not found for the segment 'Products'.</m:message>
5
+ </m:error>
@@ -0,0 +1,150 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
3
+ <edmx:DataServices>
4
+ <Schema Namespace="ODataDemo" xmlns="http://docs.oasis-open.org/odata/ns/edm">
5
+ <EntityType Name="Product">
6
+ <Key>
7
+ <PropertyRef Name="ID" />
8
+ </Key>
9
+ <Property Name="ID" Type="Edm.Int32" Nullable="false" />
10
+ <Property Name="Name" Type="Edm.String" />
11
+ <Property Name="Description" Type="Edm.String" />
12
+ <Property Name="ReleaseDate" Type="Edm.DateTimeOffset" Nullable="false" />
13
+ <Property Name="DiscontinuedDate" Type="Edm.DateTimeOffset" />
14
+ <Property Name="Rating" Type="Edm.Int16" Nullable="false" />
15
+ <Property Name="Price" Type="Edm.Double" Nullable="false" />
16
+ <Property Name="ProductStatus" Type="ODataDemo.ProductStatus" Nullable="false" />
17
+ <NavigationProperty Name="Categories" Type="Collection(ODataDemo.Category)" Partner="Products" />
18
+ <NavigationProperty Name="Supplier" Type="ODataDemo.Supplier" Partner="Products" />
19
+ <NavigationProperty Name="ProductDetail" Type="ODataDemo.ProductDetail" Partner="Product" />
20
+ </EntityType>
21
+ <EnumType Name="ProductStatus" UnderlyingType="Edm.Byte">
22
+ <Member Name="Available" />
23
+ <Member Name="LowStock" />
24
+ <Member Name="Backordered" />
25
+ <Member Name="Discontinued" />
26
+ </EnumType>
27
+ <EntityType Name="FeaturedProduct" BaseType="ODataDemo.Product">
28
+ <NavigationProperty Name="Advertisement" Type="ODataDemo.Advertisement" Partner="FeaturedProduct" />
29
+ </EntityType>
30
+ <EntityType Name="ProductDetail">
31
+ <Key>
32
+ <PropertyRef Name="ProductID" />
33
+ </Key>
34
+ <Property Name="ProductID" Type="Edm.Int32" Nullable="false" />
35
+ <Property Name="Details" Type="Edm.String" />
36
+ <NavigationProperty Name="Product" Type="ODataDemo.Product" Partner="ProductDetail" />
37
+ </EntityType>
38
+ <EntityType Name="Category" OpenType="true">
39
+ <Key>
40
+ <PropertyRef Name="ID" />
41
+ </Key>
42
+ <Property Name="ID" Type="Edm.Int32" Nullable="false" />
43
+ <Property Name="Name" Type="Edm.String" />
44
+ <NavigationProperty Name="Products" Type="Collection(ODataDemo.Product)" Partner="Categories" />
45
+ </EntityType>
46
+ <EntityType Name="Supplier">
47
+ <Key>
48
+ <PropertyRef Name="ID" />
49
+ </Key>
50
+ <Property Name="ID" Type="Edm.Int32" Nullable="false" />
51
+ <Property Name="Name" Type="Edm.String" />
52
+ <Property Name="Address" Type="ODataDemo.Address" />
53
+ <Property Name="Location" Type="Edm.GeographyPoint" SRID="Variable" />
54
+ <Property Name="Concurrency" Type="Edm.Int32" ConcurrencyMode="Fixed" Nullable="false" />
55
+ <NavigationProperty Name="Products" Type="Collection(ODataDemo.Product)" Partner="Supplier" />
56
+ </EntityType>
57
+ <ComplexType Name="Address">
58
+ <Property Name="Street" Type="Edm.String" />
59
+ <Property Name="City" Type="Edm.String" />
60
+ <Property Name="State" Type="Edm.String" />
61
+ <Property Name="ZipCode" Type="Edm.String" />
62
+ <Property Name="Country" Type="Edm.String" />
63
+ </ComplexType>
64
+ <EntityType Name="Person">
65
+ <Key>
66
+ <PropertyRef Name="ID" />
67
+ </Key>
68
+ <Property Name="ID" Type="Edm.Int32" Nullable="false" />
69
+ <Property Name="Name" Type="Edm.String" />
70
+ <NavigationProperty Name="PersonDetail" Type="ODataDemo.PersonDetail" Partner="Person" />
71
+ </EntityType>
72
+ <EntityType Name="Customer" BaseType="ODataDemo.Person">
73
+ <Property Name="TotalExpense" Type="Edm.Decimal" Nullable="false" />
74
+ </EntityType>
75
+ <EntityType Name="Employee" BaseType="ODataDemo.Person">
76
+ <Property Name="EmployeeID" Type="Edm.Int64" Nullable="false" />
77
+ <Property Name="HireDate" Type="Edm.DateTimeOffset" Nullable="false" />
78
+ <Property Name="Salary" Type="Edm.Single" Nullable="false" />
79
+ </EntityType>
80
+ <EntityType Name="PersonDetail">
81
+ <Key>
82
+ <PropertyRef Name="PersonID" />
83
+ </Key>
84
+ <Property Name="PersonID" Type="Edm.Int32" Nullable="false" />
85
+ <Property Name="Age" Type="Edm.Byte" Nullable="false" />
86
+ <Property Name="Gender" Type="Edm.Boolean" Nullable="false" />
87
+ <Property Name="Phone" Type="Edm.String" />
88
+ <Property Name="Address" Type="ODataDemo.Address" />
89
+ <Property Name="Photo" Type="Edm.Stream" Nullable="false" />
90
+ <NavigationProperty Name="Person" Type="ODataDemo.Person" Partner="PersonDetail" />
91
+ </EntityType>
92
+ <EntityType Name="Advertisement" HasStream="true">
93
+ <Key>
94
+ <PropertyRef Name="ID" />
95
+ </Key>
96
+ <Property Name="ID" Type="Edm.Guid" Nullable="false" />
97
+ <Property Name="Name" Type="Edm.String" />
98
+ <Property Name="AirDate" Type="Edm.DateTimeOffset" Nullable="false" />
99
+ <NavigationProperty Name="FeaturedProduct" Type="ODataDemo.FeaturedProduct" Partner="Advertisement" />
100
+ </EntityType>
101
+ <EntityContainer Name="DemoService">
102
+ <EntitySet Name="Products" EntityType="ODataDemo.Product">
103
+ <NavigationPropertyBinding Path="ODataDemo.FeaturedProduct/Advertisement" Target="Advertisements" />
104
+ <NavigationPropertyBinding Path="Categories" Target="Categories" />
105
+ <NavigationPropertyBinding Path="Supplier" Target="Suppliers" />
106
+ <NavigationPropertyBinding Path="ProductDetail" Target="ProductDetails" />
107
+ </EntitySet>
108
+ <EntitySet Name="ProductDetails" EntityType="ODataDemo.ProductDetail">
109
+ <NavigationPropertyBinding Path="Product" Target="Products" />
110
+ </EntitySet>
111
+ <EntitySet Name="Categories" EntityType="ODataDemo.Category">
112
+ <NavigationPropertyBinding Path="Products" Target="Products" />
113
+ </EntitySet>
114
+ <EntitySet Name="Suppliers" EntityType="ODataDemo.Supplier">
115
+ <NavigationPropertyBinding Path="Products" Target="Products" />
116
+ </EntitySet>
117
+ <EntitySet Name="Persons" EntityType="ODataDemo.Person">
118
+ <NavigationPropertyBinding Path="PersonDetail" Target="PersonDetails" />
119
+ </EntitySet>
120
+ <EntitySet Name="PersonDetails" EntityType="ODataDemo.PersonDetail">
121
+ <NavigationPropertyBinding Path="Person" Target="Persons" />
122
+ </EntitySet>
123
+ <EntitySet Name="Advertisements" EntityType="ODataDemo.Advertisement">
124
+ <NavigationPropertyBinding Path="FeaturedProduct" Target="Products" />
125
+ </EntitySet>
126
+ </EntityContainer>
127
+ <Annotations Target="ODataDemo.DemoService">
128
+ <Annotation Term="Org.OData.Display.V1.Description" String="This is a sample OData service with vocabularies" />
129
+ </Annotations>
130
+ <Annotations Target="ODataDemo.Product">
131
+ <Annotation Term="Org.OData.Display.V1.Description" String="All Products available in the online store" />
132
+ </Annotations>
133
+ <Annotations Target="ODataDemo.Product/Name">
134
+ <Annotation Term="Org.OData.Display.V1.DisplayName" String="Product Name" />
135
+ </Annotations>
136
+ <Annotations Target="ODataDemo.DemoService/Suppliers">
137
+ <Annotation Term="Org.OData.Publication.V1.PublisherName" String="Microsoft Corp." />
138
+ <Annotation Term="Org.OData.Publication.V1.PublisherId" String="MSFT" />
139
+ <Annotation Term="Org.OData.Publication.V1.Keywords" String="Inventory, Supplier, Advertisers, Sales, Finance" />
140
+ <Annotation Term="Org.OData.Publication.V1.AttributionUrl" String="http://www.odata.org/" />
141
+ <Annotation Term="Org.OData.Publication.V1.AttributionDescription" String="All rights reserved" />
142
+ <Annotation Term="Org.OData.Publication.V1.DocumentationUrl " String="http://www.odata.org/" />
143
+ <Annotation Term="Org.OData.Publication.V1.TermsOfUseUrl" String="All rights reserved" />
144
+ <Annotation Term="Org.OData.Publication.V1.PrivacyPolicyUrl" String="http://www.odata.org/" />
145
+ <Annotation Term="Org.OData.Publication.V1.LastModified" String="4/2/2013" />
146
+ <Annotation Term="Org.OData.Publication.V1.ImageUrl " String="http://www.odata.org/" />
147
+ </Annotations>
148
+ </Schema>
149
+ </edmx:DataServices>
150
+ </edmx:Edmx>