odata_server 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +12 -0
- data/MIT-LICENSE +20 -0
- data/README +14 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/app/controllers/o_data_controller.rb +145 -0
- data/app/helpers/o_data_helper.rb +203 -0
- data/app/views/o_data/metadata.xml.builder +62 -0
- data/app/views/o_data/resource.atom.builder +8 -0
- data/app/views/o_data/resource.json.erb +1 -0
- data/app/views/o_data/service.xml.builder +11 -0
- data/config/routes.rb +11 -0
- data/init.rb +3 -0
- data/install.rb +1 -0
- data/lib/o_data/abstract_query.rb +27 -0
- data/lib/o_data/abstract_query/base.rb +133 -0
- data/lib/o_data/abstract_query/countable.rb +22 -0
- data/lib/o_data/abstract_query/errors.rb +117 -0
- data/lib/o_data/abstract_query/option.rb +58 -0
- data/lib/o_data/abstract_query/options/enumerated_option.rb +39 -0
- data/lib/o_data/abstract_query/options/expand_option.rb +81 -0
- data/lib/o_data/abstract_query/options/format_option.rb +19 -0
- data/lib/o_data/abstract_query/options/inlinecount_option.rb +20 -0
- data/lib/o_data/abstract_query/options/orderby_option.rb +79 -0
- data/lib/o_data/abstract_query/options/select_option.rb +74 -0
- data/lib/o_data/abstract_query/options/skip_option.rb +32 -0
- data/lib/o_data/abstract_query/options/top_option.rb +32 -0
- data/lib/o_data/abstract_query/parser.rb +77 -0
- data/lib/o_data/abstract_query/segment.rb +43 -0
- data/lib/o_data/abstract_query/segments/collection_segment.rb +24 -0
- data/lib/o_data/abstract_query/segments/count_segment.rb +38 -0
- data/lib/o_data/abstract_query/segments/entity_type_and_key_values_segment.rb +116 -0
- data/lib/o_data/abstract_query/segments/entity_type_segment.rb +31 -0
- data/lib/o_data/abstract_query/segments/links_segment.rb +49 -0
- data/lib/o_data/abstract_query/segments/navigation_property_segment.rb +82 -0
- data/lib/o_data/abstract_query/segments/property_segment.rb +50 -0
- data/lib/o_data/abstract_query/segments/value_segment.rb +40 -0
- data/lib/o_data/abstract_schema.rb +9 -0
- data/lib/o_data/abstract_schema/association.rb +29 -0
- data/lib/o_data/abstract_schema/base.rb +48 -0
- data/lib/o_data/abstract_schema/comparable.rb +42 -0
- data/lib/o_data/abstract_schema/end.rb +50 -0
- data/lib/o_data/abstract_schema/entity_type.rb +64 -0
- data/lib/o_data/abstract_schema/navigation_property.rb +37 -0
- data/lib/o_data/abstract_schema/property.rb +35 -0
- data/lib/o_data/abstract_schema/schema_object.rb +37 -0
- data/lib/o_data/abstract_schema/serializable.rb +79 -0
- data/lib/o_data/active_record_schema.rb +8 -0
- data/lib/o_data/active_record_schema/association.rb +130 -0
- data/lib/o_data/active_record_schema/base.rb +37 -0
- data/lib/o_data/active_record_schema/entity_type.rb +128 -0
- data/lib/o_data/active_record_schema/navigation_property.rb +45 -0
- data/lib/o_data/active_record_schema/property.rb +45 -0
- data/lib/o_data/active_record_schema/serializable.rb +36 -0
- data/lib/odata_server.rb +12 -0
- data/public/clientaccesspolicy.xml +13 -0
- data/tasks/o_data_server_tasks.rake +4 -0
- data/test/helper.rb +17 -0
- data/uninstall.rb +1 -0
- metadata +171 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
class Segment
|
4
|
+
attr_reader :query, :value
|
5
|
+
|
6
|
+
def self.parse!(query, str)
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.segment_name
|
11
|
+
name.to_s.demodulize.sub(/Segment$/, '')
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(query, value)
|
15
|
+
@query = query
|
16
|
+
@value = value
|
17
|
+
|
18
|
+
raise Errors::InvalidSegmentContext.new(@query, self) unless can_follow?(@query.segments.last)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.can_follow?(anOtherSegment)
|
22
|
+
# self (Segment class) can_follow? anOtherSegment (instance of Segment class)
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def can_follow?(anOtherSegment)
|
27
|
+
self.class.can_follow?(anOtherSegment)
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute!(acc)
|
31
|
+
acc
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
"#<< #{@query.schema.namespace.to_s}(#{self.class.segment_name}: #{self.value.inspect}) >>"
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid?(results)
|
39
|
+
!results.blank?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
module Segments
|
4
|
+
class CollectionSegment < EntityTypeAndKeyValuesSegment
|
5
|
+
def self.parse!(query, str)
|
6
|
+
return nil unless query.segments.empty?
|
7
|
+
schema_object_name, key_values, keys = extract_schema_object_name_and_key_values_and_keys(str)
|
8
|
+
return nil if schema_object_name.blank?
|
9
|
+
|
10
|
+
entity_type = query.schema.find_entity_type(:name => schema_object_name.singularize)
|
11
|
+
return nil if entity_type.blank?
|
12
|
+
|
13
|
+
sanitized_key_values = sanitize_key_values_and_keys_for!(query, entity_type, key_values, keys)
|
14
|
+
|
15
|
+
query.Segment(self, entity_type, sanitized_key_values)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.can_follow?(anOtherSegment)
|
19
|
+
anOtherSegment.blank?
|
20
|
+
end
|
21
|
+
end # CollectionSegment
|
22
|
+
end # Segments
|
23
|
+
end # AbstractQuery
|
24
|
+
end # OData
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
module Segments
|
4
|
+
class CountSegment < OData::AbstractQuery::Segment
|
5
|
+
def self.parse!(query, str)
|
6
|
+
return nil unless str.to_s == segment_name
|
7
|
+
|
8
|
+
query.Segment(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.segment_name
|
12
|
+
"$count"
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(query)
|
16
|
+
super(query, self.class.segment_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.can_follow?(anOtherSegment)
|
20
|
+
if anOtherSegment.is_a?(Class)
|
21
|
+
anOtherSegment == CollectionSegment || anOtherSegment == NavigationPropertySegment
|
22
|
+
else
|
23
|
+
(anOtherSegment.is_a?(CollectionSegment) || anOtherSegment.is_a?(NavigationPropertySegment)) && anOtherSegment.countable?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute!(acc)
|
28
|
+
return acc.length if acc.respond_to?(:length)
|
29
|
+
1
|
30
|
+
end
|
31
|
+
|
32
|
+
def valid?(results)
|
33
|
+
results.is_a?(Fixnum)
|
34
|
+
end
|
35
|
+
end # CountSegment
|
36
|
+
end # Segments
|
37
|
+
end # AbstractQuery
|
38
|
+
end # OData
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
module Segments
|
4
|
+
class EntityTypeAndKeyValuesSegment < EntityTypeSegment
|
5
|
+
def self.remove_quotes(str)
|
6
|
+
str.to_s.sub(/^\'(.*?)\'$/, '\1')
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.extract_schema_object_name_and_key_values_and_keys(str)
|
10
|
+
if md1 = str.to_s.match(/^([^\(]+)(?:\(([^\)]+)\)|\(\s*\))?$/)
|
11
|
+
schema_object_name = md1[1]
|
12
|
+
key_values = {}
|
13
|
+
keys = []
|
14
|
+
|
15
|
+
if key_values_string = md1[2]
|
16
|
+
key_values_string.split(/\s*,\s*/).each do |key_value_pair|
|
17
|
+
key, value = key_value_pair.split('=', 2)
|
18
|
+
|
19
|
+
if value
|
20
|
+
key_values[key.to_sym] = remove_quotes(value)
|
21
|
+
else
|
22
|
+
keys << remove_quotes(key)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
[schema_object_name, key_values, keys]
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.sanitize_key_values_and_keys_for!(query, entity_type, key_values = {}, keys = [])
|
34
|
+
key_property_name = entity_type.key_property.name
|
35
|
+
|
36
|
+
sanitized_key_values = key_values.inject({}) { |acc, key_value_pair|
|
37
|
+
key, value = key_value_pair
|
38
|
+
|
39
|
+
property = entity_type.properties.find { |p| p.name == key.to_s }
|
40
|
+
raise OData::AbstractQuery::Errors::PropertyNotFound.new(query, key) if property.blank?
|
41
|
+
|
42
|
+
raise OData::AbstractQuery::Errors::AbstractQueryKeyValueException.new(query, key, value) unless acc[key.to_sym].blank?
|
43
|
+
|
44
|
+
acc[property.name.to_sym] = value
|
45
|
+
acc
|
46
|
+
}
|
47
|
+
|
48
|
+
keys.inject(sanitized_key_values) { |acc, key_value|
|
49
|
+
raise OData::AbstractQuery::Errors::AbstractQueryKeyValueException.new(query, key_property_name, key_value) unless acc[key_property_name.to_sym].blank?
|
50
|
+
|
51
|
+
acc[key_property_name.to_sym] = key_value
|
52
|
+
acc
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_reader :key_values
|
57
|
+
|
58
|
+
def initialize(query, entity_type, key_values = {})
|
59
|
+
@key_values = key_values
|
60
|
+
|
61
|
+
super(query, entity_type)
|
62
|
+
end
|
63
|
+
|
64
|
+
def countable?
|
65
|
+
!key?
|
66
|
+
end
|
67
|
+
|
68
|
+
def execute!(acc)
|
69
|
+
return [] if self.entity_type.blank?
|
70
|
+
|
71
|
+
if key?
|
72
|
+
self.entity_type.find_one(key_property_value)
|
73
|
+
else
|
74
|
+
self.entity_type.find_all(@key_values)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def key?
|
79
|
+
!self.entity_type.blank? && self.class.key?(self.entity_type, @key_values)
|
80
|
+
end
|
81
|
+
|
82
|
+
def key_property_value
|
83
|
+
return nil if self.entity_type.blank?
|
84
|
+
|
85
|
+
self.class.key_property_value_for(self.entity_type, @key_values)
|
86
|
+
end
|
87
|
+
|
88
|
+
def value
|
89
|
+
if @key_values.blank?
|
90
|
+
super
|
91
|
+
elsif key?
|
92
|
+
super + '(' + key_property_value.to_s + ')'
|
93
|
+
else
|
94
|
+
super + '(' + @key_values.collect { |key, value| "#{key}=#{value}" }.join(',') + ')'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.key?(entity_type, key_values = {})
|
99
|
+
!!key_property_value_for(entity_type, key_values)
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.key_property_value_for(entity_type, key_values = {})
|
103
|
+
return nil if entity_type.blank?
|
104
|
+
|
105
|
+
return nil if key_values.blank?
|
106
|
+
return nil unless key_values.size == 1
|
107
|
+
|
108
|
+
key_property = entity_type.key_property
|
109
|
+
return nil if key_property.blank?
|
110
|
+
|
111
|
+
key_values[key_property.name.to_sym]
|
112
|
+
end
|
113
|
+
end # EntityTypeAndKeyValuesSegment
|
114
|
+
end # Segments
|
115
|
+
end # AbstractQuery
|
116
|
+
end # OData
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
module Segments
|
4
|
+
class EntityTypeSegment < OData::AbstractQuery::Segment
|
5
|
+
include OData::AbstractQuery::Countable
|
6
|
+
|
7
|
+
attr_reader :entity_type
|
8
|
+
|
9
|
+
def initialize(query, entity_type, value = nil)
|
10
|
+
@entity_type = entity_type
|
11
|
+
|
12
|
+
super(query, value || (@entity_type.is_a?(OData::AbstractSchema::EntityType) ? @entity_type.plural_name : @entity_type))
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.can_follow?(anOtherSegment)
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute!(acc)
|
20
|
+
return [] if @entity_type.blank?
|
21
|
+
|
22
|
+
@entity_type.find_all
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid?(results)
|
26
|
+
countable? ? results.is_a?(Array) : !results.blank?
|
27
|
+
end
|
28
|
+
end # EntityTypeSegment
|
29
|
+
end # Segments
|
30
|
+
end # AbstractQuery
|
31
|
+
end # OData
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
module Segments
|
4
|
+
class LinksSegment < OData::AbstractQuery::Segment
|
5
|
+
include OData::AbstractQuery::Countable
|
6
|
+
|
7
|
+
def self.parse!(query, str)
|
8
|
+
return nil unless str.to_s == segment_name
|
9
|
+
|
10
|
+
query.Segment(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.segment_name
|
14
|
+
"$links"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.countable?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(query)
|
22
|
+
super(query, self.class.segment_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.can_follow?(anOtherSegment)
|
26
|
+
if anOtherSegment.is_a?(Class)
|
27
|
+
anOtherSegment == CollectionSegment || anOtherSegment == NavigationPropertySegment
|
28
|
+
else
|
29
|
+
(anOtherSegment.is_a?(CollectionSegment) || anOtherSegment.is_a?(NavigationPropertySegment)) # && anOtherSegment.countable?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def execute!(acc)
|
34
|
+
[acc].flatten.compact.collect { |one|
|
35
|
+
if entity_type = self.query.schema.entity_types.find { |et| et.name == one.class.name }
|
36
|
+
[one, entity_type.plural_name + '(' + entity_type.primary_key_for(one).to_s + ')']
|
37
|
+
else
|
38
|
+
[one, nil]
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def valid?(results)
|
44
|
+
results.all? { |pair| !pair[1].blank? }
|
45
|
+
end
|
46
|
+
end # LinksSegment
|
47
|
+
end # Segments
|
48
|
+
end # AbstractQuery
|
49
|
+
end # OData
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
module Segments
|
4
|
+
class NavigationPropertySegment < EntityTypeAndKeyValuesSegment
|
5
|
+
def self.parse!(query, str)
|
6
|
+
return nil if query.segments.empty?
|
7
|
+
return nil unless query.segments.last.respond_to?(:entity_type)
|
8
|
+
entity_type = query.segments.last.entity_type
|
9
|
+
return nil if entity_type.blank?
|
10
|
+
|
11
|
+
schema_object_name, key_values, keys = extract_schema_object_name_and_key_values_and_keys(str)
|
12
|
+
return nil if schema_object_name.blank?
|
13
|
+
|
14
|
+
navigation_property = entity_type.navigation_properties.find { |np| np.name == schema_object_name }
|
15
|
+
return nil if navigation_property.blank?
|
16
|
+
|
17
|
+
if navigation_property.to_end.polymorphic?
|
18
|
+
raise OData::AbstractQuery::Errors::AbstractQueryKeyValueException.new(query, key_values.keys.first, key_values.values.first) unless key_values.empty?
|
19
|
+
raise OData::AbstractQuery::Errors::AbstractQueryKeyValueException.new(query, '$polymorphic#Key', keys.first) unless keys.empty?
|
20
|
+
|
21
|
+
query.Segment(self, entity_type, navigation_property.to_end.return_type, navigation_property, {})
|
22
|
+
else
|
23
|
+
sanitized_key_values = sanitize_key_values_and_keys_for!(query, navigation_property.to_end.entity_type, key_values, keys)
|
24
|
+
|
25
|
+
unless sanitized_key_values.empty?
|
26
|
+
raise OData::AbstractQuery::Errors::AbstractQueryKeyValueException.new(query, sanitized_key_values.keys.first, sanitized_key_values.values.first) unless navigation_property.to_end.multiple?
|
27
|
+
end
|
28
|
+
|
29
|
+
query.Segment(self, entity_type, navigation_property.to_end.entity_type, navigation_property, sanitized_key_values)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :to_entity_type, :entity_type
|
34
|
+
|
35
|
+
attr_reader :navigation_property
|
36
|
+
|
37
|
+
def initialize(query, from_entity_type, to_entity_type, navigation_property, key_values = {})
|
38
|
+
@from_entity_type = from_entity_type
|
39
|
+
@navigation_property = navigation_property
|
40
|
+
|
41
|
+
super(query, to_entity_type, key_values)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.can_follow?(anOtherSegment)
|
45
|
+
if anOtherSegment.is_a?(Class)
|
46
|
+
anOtherSegment == CollectionSegment || anOtherSegment == NavigationPropertySegment
|
47
|
+
else
|
48
|
+
(anOtherSegment.is_a?(CollectionSegment) || anOtherSegment.is_a?(NavigationPropertySegment)) && !anOtherSegment.countable?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def countable?
|
53
|
+
multiple? && super
|
54
|
+
end
|
55
|
+
|
56
|
+
def execute!(acc)
|
57
|
+
[acc].flatten.compact.collect { |one|
|
58
|
+
if key?
|
59
|
+
@navigation_property.find_one(one, key_property_value)
|
60
|
+
else
|
61
|
+
@navigation_property.find_all(one, @key_values)
|
62
|
+
end
|
63
|
+
}.first
|
64
|
+
end
|
65
|
+
|
66
|
+
def multiple?
|
67
|
+
@navigation_property.to_end.multiple?
|
68
|
+
end
|
69
|
+
|
70
|
+
def value
|
71
|
+
if self.key_values.blank? || !multiple?
|
72
|
+
@navigation_property.name
|
73
|
+
elsif key?
|
74
|
+
@navigation_property.name + '(' + key_property_value.to_s + ')'
|
75
|
+
else
|
76
|
+
@navigation_property.name + '(' + self.key_values.collect { |key, value| "#{key}=#{value}" }.join(',') + ')'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end # NavigationPropertySegment
|
80
|
+
end # Segments
|
81
|
+
end # AbstractQuery
|
82
|
+
end # OData
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
module Segments
|
4
|
+
class PropertySegment < EntityTypeSegment
|
5
|
+
attr_reader :property
|
6
|
+
|
7
|
+
def self.parse!(query, str)
|
8
|
+
return nil if query.segments.empty?
|
9
|
+
return nil unless query.segments.last.respond_to?(:entity_type)
|
10
|
+
entity_type = query.segments.last.entity_type
|
11
|
+
return nil if entity_type.nil?
|
12
|
+
property = entity_type.properties.find { |p| p.name == str }
|
13
|
+
return nil if property.blank?
|
14
|
+
|
15
|
+
query.Segment(self, entity_type, property)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(query, entity_type, property)
|
19
|
+
@property = property
|
20
|
+
|
21
|
+
super(query, entity_type, @property.name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.can_follow?(anOtherSegment)
|
25
|
+
if anOtherSegment.is_a?(Class)
|
26
|
+
anOtherSegment == CollectionSegment || anOtherSegment == NavigationPropertySegment
|
27
|
+
else
|
28
|
+
(anOtherSegment.is_a?(CollectionSegment) || anOtherSegment.is_a?(NavigationPropertySegment)) && !anOtherSegment.countable?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def countable?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute!(acc)
|
37
|
+
# [acc].flatten.compact.collect { |one|
|
38
|
+
# [one, @property.value_for(one)]
|
39
|
+
# }
|
40
|
+
{ @property => @property.value_for([acc].flatten.compact.first) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def valid?(results)
|
44
|
+
# results.is_a?(Array)
|
45
|
+
!results.blank?
|
46
|
+
end
|
47
|
+
end # PropertySegment
|
48
|
+
end # Segments
|
49
|
+
end # AbstractQuery
|
50
|
+
end # OData
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module OData
|
2
|
+
module AbstractQuery
|
3
|
+
module Segments
|
4
|
+
class ValueSegment < OData::AbstractQuery::Segment
|
5
|
+
def self.parse!(query, str)
|
6
|
+
return nil unless str.to_s == segment_name
|
7
|
+
|
8
|
+
query.Segment(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.segment_name
|
12
|
+
"$value"
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(query)
|
16
|
+
super(query, self.class.segment_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.can_follow?(anOtherSegment)
|
20
|
+
if anOtherSegment.is_a?(Class)
|
21
|
+
anOtherSegment == PropertySegment
|
22
|
+
else
|
23
|
+
anOtherSegment.is_a?(PropertySegment)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute!(acc)
|
28
|
+
# acc
|
29
|
+
acc.values.first
|
30
|
+
end
|
31
|
+
|
32
|
+
def valid?(results)
|
33
|
+
# # results.is_a?(Array)
|
34
|
+
# !results.blank?
|
35
|
+
true
|
36
|
+
end
|
37
|
+
end # ValueSegment
|
38
|
+
end # Segments
|
39
|
+
end # AbstractQuery
|
40
|
+
end # OData
|