odata4 0.7.0
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 +7 -0
- data/.autotest +2 -0
- data/.gitignore +24 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +75 -0
- data/CHANGELOG.md +120 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +23 -0
- data/README.md +287 -0
- data/Rakefile +7 -0
- data/TODO.md +55 -0
- data/lib/odata4.rb +37 -0
- data/lib/odata4/complex_type.rb +76 -0
- data/lib/odata4/complex_type/property.rb +114 -0
- data/lib/odata4/entity.rb +319 -0
- data/lib/odata4/entity_set.rb +162 -0
- data/lib/odata4/enum_type.rb +95 -0
- data/lib/odata4/enum_type/property.rb +62 -0
- data/lib/odata4/navigation_property.rb +29 -0
- data/lib/odata4/navigation_property/proxy.rb +76 -0
- data/lib/odata4/properties.rb +25 -0
- data/lib/odata4/properties/binary.rb +50 -0
- data/lib/odata4/properties/boolean.rb +37 -0
- data/lib/odata4/properties/date.rb +27 -0
- data/lib/odata4/properties/date_time.rb +83 -0
- data/lib/odata4/properties/date_time_offset.rb +17 -0
- data/lib/odata4/properties/decimal.rb +50 -0
- data/lib/odata4/properties/float.rb +67 -0
- data/lib/odata4/properties/geography.rb +13 -0
- data/lib/odata4/properties/geography/base.rb +162 -0
- data/lib/odata4/properties/geography/line_string.rb +33 -0
- data/lib/odata4/properties/geography/point.rb +31 -0
- data/lib/odata4/properties/geography/polygon.rb +38 -0
- data/lib/odata4/properties/guid.rb +17 -0
- data/lib/odata4/properties/integer.rb +107 -0
- data/lib/odata4/properties/number.rb +14 -0
- data/lib/odata4/properties/string.rb +72 -0
- data/lib/odata4/properties/time.rb +40 -0
- data/lib/odata4/properties/time_of_day.rb +27 -0
- data/lib/odata4/property.rb +118 -0
- data/lib/odata4/property_registry.rb +41 -0
- data/lib/odata4/query.rb +231 -0
- data/lib/odata4/query/criteria.rb +92 -0
- data/lib/odata4/query/criteria/comparison_operators.rb +49 -0
- data/lib/odata4/query/criteria/date_functions.rb +61 -0
- data/lib/odata4/query/criteria/geography_functions.rb +21 -0
- data/lib/odata4/query/criteria/lambda_operators.rb +27 -0
- data/lib/odata4/query/criteria/string_functions.rb +40 -0
- data/lib/odata4/query/in_batches.rb +58 -0
- data/lib/odata4/query/result.rb +84 -0
- data/lib/odata4/query/result/atom.rb +41 -0
- data/lib/odata4/query/result/json.rb +42 -0
- data/lib/odata4/railtie.rb +19 -0
- data/lib/odata4/service.rb +344 -0
- data/lib/odata4/service_registry.rb +52 -0
- data/lib/odata4/version.rb +3 -0
- data/odata4.gemspec +34 -0
- data/spec/fixtures/files/entity_to_xml.xml +17 -0
- data/spec/fixtures/files/metadata.xml +150 -0
- data/spec/fixtures/files/product_0.json +10 -0
- data/spec/fixtures/files/product_0.xml +28 -0
- data/spec/fixtures/files/products.json +106 -0
- data/spec/fixtures/files/products.xml +308 -0
- data/spec/fixtures/files/supplier_0.json +26 -0
- data/spec/fixtures/files/supplier_0.xml +32 -0
- data/spec/fixtures/vcr_cassettes/complex_type_specs.yml +127 -0
- data/spec/fixtures/vcr_cassettes/entity_set_specs.yml +1348 -0
- data/spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml +183 -0
- data/spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml +256 -0
- data/spec/fixtures/vcr_cassettes/entity_set_specs/new_entry.yml +185 -0
- data/spec/fixtures/vcr_cassettes/entity_specs.yml +285 -0
- data/spec/fixtures/vcr_cassettes/navigation_property_proxy_specs.yml +346 -0
- data/spec/fixtures/vcr_cassettes/query/result_specs.yml +189 -0
- data/spec/fixtures/vcr_cassettes/query_specs.yml +663 -0
- data/spec/fixtures/vcr_cassettes/service_registry_specs.yml +129 -0
- data/spec/fixtures/vcr_cassettes/service_specs.yml +127 -0
- data/spec/fixtures/vcr_cassettes/usage_example_specs.yml +749 -0
- data/spec/odata4/complex_type_spec.rb +116 -0
- data/spec/odata4/entity/shared_examples.rb +82 -0
- data/spec/odata4/entity_set_spec.rb +168 -0
- data/spec/odata4/entity_spec.rb +151 -0
- data/spec/odata4/enum_type_spec.rb +134 -0
- data/spec/odata4/navigation_property/proxy_spec.rb +44 -0
- data/spec/odata4/navigation_property_spec.rb +55 -0
- data/spec/odata4/properties/binary_spec.rb +50 -0
- data/spec/odata4/properties/boolean_spec.rb +72 -0
- data/spec/odata4/properties/date_spec.rb +23 -0
- data/spec/odata4/properties/date_time_offset_spec.rb +30 -0
- data/spec/odata4/properties/date_time_spec.rb +23 -0
- data/spec/odata4/properties/decimal_spec.rb +24 -0
- data/spec/odata4/properties/float_spec.rb +45 -0
- data/spec/odata4/properties/geography/line_string_spec.rb +33 -0
- data/spec/odata4/properties/geography/point_spec.rb +29 -0
- data/spec/odata4/properties/geography/polygon_spec.rb +55 -0
- data/spec/odata4/properties/geography/shared_examples.rb +72 -0
- data/spec/odata4/properties/guid_spec.rb +17 -0
- data/spec/odata4/properties/integer_spec.rb +58 -0
- data/spec/odata4/properties/string_spec.rb +46 -0
- data/spec/odata4/properties/time_of_day_spec.rb +23 -0
- data/spec/odata4/properties/time_spec.rb +15 -0
- data/spec/odata4/property_registry_spec.rb +16 -0
- data/spec/odata4/property_spec.rb +32 -0
- data/spec/odata4/query/criteria_spec.rb +229 -0
- data/spec/odata4/query/result_spec.rb +53 -0
- data/spec/odata4/query_spec.rb +196 -0
- data/spec/odata4/service_registry_spec.rb +18 -0
- data/spec/odata4/service_spec.rb +80 -0
- data/spec/odata4/usage_example_spec.rb +176 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/coverage.rb +2 -0
- data/spec/support/vcr.rb +9 -0
- metadata +380 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
module OData4
|
|
2
|
+
# This class represents a set of entities within an OData4 service. It is
|
|
3
|
+
# instantiated whenever an OData4::Service is asked for an EntitySet via the
|
|
4
|
+
# OData4::Service#[] method call. It also provides Enumerable behavior so that
|
|
5
|
+
# you can interact with the entities within a set in a very comfortable way.
|
|
6
|
+
#
|
|
7
|
+
# This class also implements a query interface for finding certain entities
|
|
8
|
+
# based on query criteria or limiting the result set returned by the set. This
|
|
9
|
+
# functionality is implemented through transparent proxy objects.
|
|
10
|
+
class EntitySet
|
|
11
|
+
include Enumerable
|
|
12
|
+
|
|
13
|
+
# The name of the EntitySet
|
|
14
|
+
attr_reader :name
|
|
15
|
+
# The Entity type for the EntitySet
|
|
16
|
+
attr_reader :type
|
|
17
|
+
# The OData4::Service's namespace
|
|
18
|
+
attr_reader :namespace
|
|
19
|
+
# The OData4::Service's identifiable name
|
|
20
|
+
attr_reader :service_name
|
|
21
|
+
# The EntitySet's container name
|
|
22
|
+
attr_reader :container
|
|
23
|
+
|
|
24
|
+
# Sets up the EntitySet to permit querying for the resources in the set.
|
|
25
|
+
#
|
|
26
|
+
# @param options [Hash] the options to setup the EntitySet
|
|
27
|
+
# @return [OData4::EntitySet] an instance of the EntitySet
|
|
28
|
+
def initialize(options = {})
|
|
29
|
+
@name = options[:name]
|
|
30
|
+
@type = options[:type]
|
|
31
|
+
@namespace = options[:namespace]
|
|
32
|
+
@service_name = options[:service_name]
|
|
33
|
+
@container = options[:container]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Provided for Enumerable functionality
|
|
37
|
+
#
|
|
38
|
+
# @param block [block] a block to evaluate
|
|
39
|
+
# @return [OData4::Entity] each entity in turn from this set
|
|
40
|
+
def each(&block)
|
|
41
|
+
query.execute.each(&block)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Return the first `n` Entities for the set.
|
|
45
|
+
# If count is 1 it returns the single entity, otherwise its an array of entities
|
|
46
|
+
# @return [OData4::EntitySet]
|
|
47
|
+
def first(count = 1)
|
|
48
|
+
result = query.limit(count).execute
|
|
49
|
+
count == 1 ? result.first : result.to_a
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns the number of entities within the set.
|
|
53
|
+
# Not supported in Microsoft CRM2011
|
|
54
|
+
# @return [Integer]
|
|
55
|
+
def count
|
|
56
|
+
query.count
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Create a new Entity for this set with the given properties.
|
|
60
|
+
# @param properties [Hash] property name as key and it's initial value
|
|
61
|
+
# @return [OData4::Entity]
|
|
62
|
+
def new_entity(properties = {})
|
|
63
|
+
OData4::Entity.with_properties(properties, entity_options)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Returns a query targetted at the current EntitySet.
|
|
67
|
+
# @param options [Hash] query options
|
|
68
|
+
# @return [OData4::Query]
|
|
69
|
+
def query(options = {})
|
|
70
|
+
OData4::Query.new(self, options)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Find the Entity with the supplied key value.
|
|
74
|
+
# @param key [to_s] primary key to lookup
|
|
75
|
+
# @return [OData4::Entity,nil]
|
|
76
|
+
def [](key, options={})
|
|
77
|
+
properties_to_expand = if options[:expand] == :all
|
|
78
|
+
new_entity.navigation_property_names
|
|
79
|
+
else
|
|
80
|
+
[ options[:expand] ].compact.flatten
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
query.expand(*properties_to_expand).find(key)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Write supplied entity back to the service.
|
|
87
|
+
# TODO Test this more with CRM2011
|
|
88
|
+
# @param entity [OData4::Entity] entity to save or update in the service
|
|
89
|
+
# @return [OData4::Entity]
|
|
90
|
+
def <<(entity)
|
|
91
|
+
url_chunk, options = setup_entity_post_request(entity)
|
|
92
|
+
result = execute_entity_post_request(options, url_chunk)
|
|
93
|
+
if entity.is_new?
|
|
94
|
+
doc = ::Nokogiri::XML(result.body).remove_namespaces!
|
|
95
|
+
primary_key_node = doc.xpath("//content/properties/#{entity.primary_key}").first
|
|
96
|
+
entity[entity.primary_key] = primary_key_node.content unless primary_key_node.nil?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
unless result.code.to_s =~ /^2[0-9][0-9]$/
|
|
100
|
+
entity.errors << ['could not commit entity']
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
entity
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# The OData4::Service this EntitySet is associated with.
|
|
107
|
+
# @return [OData4::Service]
|
|
108
|
+
# @api private
|
|
109
|
+
def service
|
|
110
|
+
@service ||= OData4::ServiceRegistry[service_name]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Options used for instantiating a new OData4::Entity for this set.
|
|
114
|
+
# @return [Hash]
|
|
115
|
+
# @api private
|
|
116
|
+
def entity_options
|
|
117
|
+
{
|
|
118
|
+
namespace: namespace,
|
|
119
|
+
service_name: service_name,
|
|
120
|
+
type: type,
|
|
121
|
+
entity_set: self
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def execute_entity_post_request(options, url_chunk)
|
|
128
|
+
result = service.execute(url_chunk, options)
|
|
129
|
+
unless result.code.to_s =~ /^2[0-9][0-9]$/
|
|
130
|
+
service.logger.debug <<-EOS
|
|
131
|
+
[ODATA: #{service_name}]
|
|
132
|
+
An error was encountered committing your entity:
|
|
133
|
+
|
|
134
|
+
POSTed URL:
|
|
135
|
+
#{url_chunk}
|
|
136
|
+
|
|
137
|
+
POSTed Entity:
|
|
138
|
+
#{options[:body]}
|
|
139
|
+
|
|
140
|
+
Result Body:
|
|
141
|
+
#{result.body}
|
|
142
|
+
EOS
|
|
143
|
+
service.logger.info "[ODATA: #{service_name}] Unable to commit data to #{url_chunk}"
|
|
144
|
+
end
|
|
145
|
+
result
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def setup_entity_post_request(entity)
|
|
149
|
+
primary_key = entity.get_property(entity.primary_key).url_value
|
|
150
|
+
chunk = entity.is_new? ? name : "#{name}(#{primary_key})"
|
|
151
|
+
options = {
|
|
152
|
+
method: :post,
|
|
153
|
+
body: entity.to_xml.gsub(/\n\s+/, ''),
|
|
154
|
+
headers: {
|
|
155
|
+
'Accept' => 'application/atom+xml',
|
|
156
|
+
'Content-Type' => 'application/atom+xml'
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return chunk, options
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require 'odata4/enum_type/property'
|
|
2
|
+
|
|
3
|
+
module OData4
|
|
4
|
+
# Enumeration types are nominal types that represent a series of related values.
|
|
5
|
+
# Enumeration types expose these related values as members of the enumeration.
|
|
6
|
+
class EnumType
|
|
7
|
+
# Creates a new EnumType based on the supplied options.
|
|
8
|
+
# @param type_xml [Nokogiri::XML::Element]
|
|
9
|
+
# @param service [OData4::Service]
|
|
10
|
+
# @return [self]
|
|
11
|
+
def initialize(type_definition, service)
|
|
12
|
+
@type_definition = type_definition
|
|
13
|
+
@service = service
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# The name of the EnumType
|
|
17
|
+
# @return [String]
|
|
18
|
+
def name
|
|
19
|
+
options['Name']
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns the namespaced type for the EnumType.
|
|
23
|
+
# @return [String]
|
|
24
|
+
def type
|
|
25
|
+
"#{namespace}.#{name}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Whether this EnumType supports setting multiple values.
|
|
29
|
+
# @return [Boolean]
|
|
30
|
+
def is_flags?
|
|
31
|
+
options['IsFlags'] == 'true'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# The underlying type of this EnumType.
|
|
35
|
+
# @return [String]
|
|
36
|
+
def underlying_type
|
|
37
|
+
options['UnderlyingType'] || 'Edm.Int32'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Returns the namespace this EnumType belongs to.
|
|
41
|
+
# @return [String]
|
|
42
|
+
def namespace
|
|
43
|
+
@namespace ||= service.namespace
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns the members of this EnumType and their values.
|
|
47
|
+
# @return [Hash]
|
|
48
|
+
def members
|
|
49
|
+
@members ||= collect_members
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns the property class that implements this `EnumType`.
|
|
53
|
+
# @return [Class < OData4::EnumType::Property]
|
|
54
|
+
def property_class
|
|
55
|
+
@property_class ||= lambda { |type, members, is_flags|
|
|
56
|
+
klass = Class.new ::OData4::EnumType::Property
|
|
57
|
+
klass.send(:define_method, :type) { type }
|
|
58
|
+
klass.send(:define_method, :members) { members }
|
|
59
|
+
klass.send(:define_method, :is_flags?) { is_flags }
|
|
60
|
+
klass
|
|
61
|
+
}.call(type, members, is_flags?)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns the value of the requested member.
|
|
65
|
+
# @param member_name [to_s]
|
|
66
|
+
# @return [*]
|
|
67
|
+
def [](member_name)
|
|
68
|
+
members.invert[member_name.to_s]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def service
|
|
74
|
+
@service
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def type_definition
|
|
78
|
+
@type_definition
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def options
|
|
82
|
+
@options = type_definition.attributes.map do |name, attr|
|
|
83
|
+
[name, attr.value]
|
|
84
|
+
end.to_h
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def collect_members
|
|
88
|
+
Hash[type_definition.xpath('./Member').map.with_index do |member_xml, index|
|
|
89
|
+
member_name = member_xml.attributes['Name'].value
|
|
90
|
+
member_value = member_xml.attributes['Value'].andand.value.andand.to_i
|
|
91
|
+
[member_value || index, member_name]
|
|
92
|
+
end]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module OData4
|
|
2
|
+
class EnumType
|
|
3
|
+
# Abstract base class for OData4 EnumTypes
|
|
4
|
+
# @see [OData4::EnumType]
|
|
5
|
+
class Property < OData4::Property
|
|
6
|
+
# Returns the property value, properly typecast
|
|
7
|
+
# @return [String, nil]
|
|
8
|
+
def value
|
|
9
|
+
if @value.nil? && allows_nil?
|
|
10
|
+
nil
|
|
11
|
+
else
|
|
12
|
+
@value
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Sets the property value
|
|
17
|
+
# @params new_value [String]
|
|
18
|
+
def value=(new_value)
|
|
19
|
+
parsed_value = validate(new_value)
|
|
20
|
+
@value = is_flags? ? parsed_value : parsed_value.first
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Value to be used in URLs.
|
|
24
|
+
# @return [String]
|
|
25
|
+
def url_value
|
|
26
|
+
"#{type}'#{@value}'"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def members
|
|
32
|
+
raise NotImplementedError, 'Subclass must override'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def validate(value)
|
|
36
|
+
return [] if value.nil? && allows_nil?
|
|
37
|
+
values = parse_value(value)
|
|
38
|
+
|
|
39
|
+
if values.length > 1 && !is_flags?
|
|
40
|
+
raise ArgumentError, 'Multiple values are not allowed for this property'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
values.map do |value|
|
|
44
|
+
if members.keys.include?(value)
|
|
45
|
+
members[value]
|
|
46
|
+
elsif members.values.include?(value)
|
|
47
|
+
value
|
|
48
|
+
else
|
|
49
|
+
raise ArgumentError, "Property '#{name}': Value must be one of #{members.to_a}, but was: '#{value}'" if strict?
|
|
50
|
+
end
|
|
51
|
+
end.compact
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def parse_value(value)
|
|
55
|
+
return nil if value.nil?
|
|
56
|
+
value.to_s.split(',').map(&:strip).map do |val|
|
|
57
|
+
val =~ /^[0-9]+$/ ? val.to_i : val
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'odata4/navigation_property/proxy'
|
|
2
|
+
|
|
3
|
+
module OData4
|
|
4
|
+
class NavigationProperty
|
|
5
|
+
attr_reader :name, :type, :nullable, :partner
|
|
6
|
+
|
|
7
|
+
def initialize(options)
|
|
8
|
+
@name = options[:name] or raise ArgumentError, 'Name is required'
|
|
9
|
+
@type = options[:type] or raise ArgumentError, 'Type is required'
|
|
10
|
+
@nullable = options[:nullable] || true
|
|
11
|
+
@partner = options[:partner]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def nav_type
|
|
15
|
+
@nav_type ||= type =~ /^Collection/ ? :collection : :entity
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def entity_type
|
|
19
|
+
@entity_type ||= type.split(/[()]/).last
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.build(nav_property_xml)
|
|
23
|
+
options = nav_property_xml.attributes.map do |name, attr|
|
|
24
|
+
[name.downcase.to_sym, attr.value]
|
|
25
|
+
end.to_h
|
|
26
|
+
new(options)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module OData4
|
|
2
|
+
class NavigationProperty
|
|
3
|
+
class Proxy
|
|
4
|
+
def initialize(entity, nav_name)
|
|
5
|
+
@entity = entity
|
|
6
|
+
@nav_name = nav_name
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def value=(value)
|
|
10
|
+
@value = value
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def value
|
|
14
|
+
if link.nil?
|
|
15
|
+
if nav_property.nav_type == :collection
|
|
16
|
+
[]
|
|
17
|
+
else
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
@value ||= fetch_result
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
attr_reader :entity, :nav_name
|
|
28
|
+
|
|
29
|
+
def service
|
|
30
|
+
@service ||= OData4::ServiceRegistry[entity.service_name]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def namespace
|
|
34
|
+
@namespace ||= service.namespace
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def entity_type
|
|
38
|
+
@entity_type ||= entity.name
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def link
|
|
42
|
+
entity.links[nav_name]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def nav_property
|
|
46
|
+
service.navigation_properties[entity_type][nav_name]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def fetch_result
|
|
50
|
+
raise "Invalid navigation link for #{nav_name}" unless link[:href]
|
|
51
|
+
|
|
52
|
+
options = {
|
|
53
|
+
type: nav_property.entity_type,
|
|
54
|
+
namespace: namespace,
|
|
55
|
+
service_name: entity.service_name
|
|
56
|
+
}
|
|
57
|
+
entity_set = Struct.new(:service, :entity_options)
|
|
58
|
+
.new(entity.service, options)
|
|
59
|
+
|
|
60
|
+
query = OData4::Query.new(entity_set)
|
|
61
|
+
begin
|
|
62
|
+
result = query.execute(link[:href])
|
|
63
|
+
rescue => ex
|
|
64
|
+
raise ex unless ex.message =~ /Not Found/
|
|
65
|
+
result = []
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if nav_property.nav_type == :collection
|
|
69
|
+
result
|
|
70
|
+
else
|
|
71
|
+
result.first
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Modules
|
|
2
|
+
require 'odata4/properties/number'
|
|
3
|
+
|
|
4
|
+
# Implementations
|
|
5
|
+
require 'odata4/properties/binary'
|
|
6
|
+
require 'odata4/properties/boolean'
|
|
7
|
+
require 'odata4/properties/date'
|
|
8
|
+
require 'odata4/properties/date_time'
|
|
9
|
+
require 'odata4/properties/date_time_offset'
|
|
10
|
+
require 'odata4/properties/decimal'
|
|
11
|
+
require 'odata4/properties/float'
|
|
12
|
+
require 'odata4/properties/geography'
|
|
13
|
+
require 'odata4/properties/guid'
|
|
14
|
+
require 'odata4/properties/integer'
|
|
15
|
+
require 'odata4/properties/string'
|
|
16
|
+
require 'odata4/properties/time'
|
|
17
|
+
require 'odata4/properties/time_of_day'
|
|
18
|
+
|
|
19
|
+
OData4::Properties.constants.each do |property_name|
|
|
20
|
+
klass = OData4::Properties.const_get(property_name)
|
|
21
|
+
if klass.is_a?(Class)
|
|
22
|
+
property = klass.new('test', nil)
|
|
23
|
+
OData4::PropertyRegistry.add(property.type, property.class)
|
|
24
|
+
end
|
|
25
|
+
end
|