odata_server 0.0.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.
- 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
|