frodata 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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,14 @@
1
+ module FrOData
2
+ module Properties
3
+ # Defines common behavior for FrOData numeric types.
4
+ module Number
5
+ private
6
+
7
+ def validate(value)
8
+ if value > max_value || value < min_value
9
+ validation_error "Value is outside accepted range: #{min_value} to #{max_value}"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,72 @@
1
+ module FrOData
2
+ module Properties
3
+ # Defines the String FrOData type.
4
+ class String < FrOData::Property
5
+ # Returns the property value, properly typecast
6
+ # @return [String,nil]
7
+ def value
8
+ if (@value.nil? || @value.empty?) && allows_nil?
9
+ nil
10
+ else
11
+ encode_value(@value)
12
+ end
13
+ end
14
+
15
+ # Sets the property value
16
+ # @params new_value [to_s,nil]
17
+ def value=(new_value)
18
+ validate(new_value)
19
+ @value = new_value.nil? ? nil : encode_value(new_value.to_s)
20
+ end
21
+
22
+ # Value to be used in URLs.
23
+ # @return [String]
24
+ def url_value
25
+ "'#{value}'"
26
+ end
27
+
28
+ # The FrOData type name
29
+ def type
30
+ 'Edm.String'
31
+ end
32
+
33
+ # Is the property value Unicode encoded
34
+ def is_unicode?
35
+ options[:unicode]
36
+ end
37
+
38
+ # Does the property have a default value
39
+ def has_default_value?
40
+ not(options[:default_value].nil?)
41
+ end
42
+
43
+ # The default value for the property
44
+ def default_value
45
+ options[:default_value]
46
+ end
47
+
48
+ private
49
+
50
+ def default_options
51
+ super.merge({
52
+ unicode: true,
53
+ default_value: nil
54
+ })
55
+ end
56
+
57
+ def validate(new_value)
58
+ if new_value.nil? && !allows_nil?
59
+ validation_error 'This property does not allow for nil values to be set'
60
+ end
61
+ end
62
+
63
+ def encode_value(new_value)
64
+ if options[:unicode]
65
+ new_value.encode(Encoding::UTF_8)
66
+ else
67
+ new_value.encode(Encoding::ASCII)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,40 @@
1
+ module FrOData
2
+ module Properties
3
+ # Defines the Time FrOData type.
4
+ class Time < FrOData::Property
5
+ # Returns the property value, properly typecast
6
+ # @return [Time,nil]
7
+ def value
8
+ if (@value.nil? || @value.empty?) && allows_nil?
9
+ nil
10
+ else
11
+ ::Time.strptime(@value, '%H:%M:%S%:z')
12
+ end
13
+ end
14
+
15
+ # Sets the property value
16
+ # @params new_value [Time]
17
+ def value=(new_value)
18
+ validate(new_value)
19
+ @value = parse_value(new_value)
20
+ end
21
+
22
+ # The FrOData type name
23
+ def type
24
+ 'Edm.Time'
25
+ end
26
+
27
+ private
28
+
29
+ def validate(value)
30
+ unless value.is_a?(::Time)
31
+ validation_error 'Value is not a time object'
32
+ end
33
+ end
34
+
35
+ def parse_value(value)
36
+ value.strftime('%H:%M:%S%:z')
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ require 'frodata/properties/date_time'
2
+
3
+ module FrOData
4
+ module Properties
5
+ # Defines the Date FrOData type.
6
+ class TimeOfDay < FrOData::Properties::DateTime
7
+ # The FrOData type name
8
+ def type
9
+ 'Edm.TimeOfDay'
10
+ end
11
+
12
+ def url_value
13
+ @value
14
+ end
15
+
16
+ protected
17
+
18
+ def date_class
19
+ ::Time
20
+ end
21
+
22
+ def strptime_format
23
+ '%H:%M:%S.%L'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,139 @@
1
+ module FrOData
2
+ # FrOData::Property represents an abstract property, defining the basic
3
+ # interface and required methods, with some default implementations. All
4
+ # supported property types should be implemented under the FrOData::Properties
5
+ # namespace.
6
+ class Property
7
+ # The property's name
8
+ attr_reader :name
9
+ # The property's value
10
+ attr_accessor :value
11
+ # The property's options
12
+ attr_reader :options
13
+
14
+ # Default intialization for a property with a name, value and options.
15
+ # @param name [to_s]
16
+ # @param value [to_s,nil]
17
+ # @param options [Hash]
18
+ def initialize(name, value, options = {})
19
+ @name = name.to_s
20
+ @value = value.nil? ? nil : value.to_s
21
+ @options = default_options.merge(options)
22
+ end
23
+
24
+ # Abstract implementation, should return property type, based on
25
+ # FrOData::Service metadata in proper implementation.
26
+ # @raise NotImplementedError
27
+ def type
28
+ raise NotImplementedError
29
+ end
30
+
31
+ # Provides for value-based equality checking.
32
+ # @param other [value] object for comparison
33
+ # @return [Boolean]
34
+ def ==(other)
35
+ self.value == other.value
36
+ end
37
+
38
+ # Whether the property permits a nil value.
39
+ # (Default=true)
40
+ # @return [Boolean]
41
+ def allows_nil?
42
+ options[:allows_nil]
43
+ end
44
+
45
+ # Whether the property uses strict validation.
46
+ # (Default=false)
47
+ # @return [Boolean]
48
+ def strict?
49
+ if options.key? :strict
50
+ options[:strict]
51
+ elsif service
52
+ service.options[:strict]
53
+ else
54
+ true
55
+ end
56
+ end
57
+
58
+ # The configured concurrency mode for the property.
59
+ # @return [String]
60
+ def concurrency_mode
61
+ @concurrency_mode ||= options[:concurrency_mode]
62
+ end
63
+
64
+ # Value to be used in XML.
65
+ # @return [String]
66
+ def xml_value
67
+ @value
68
+ end
69
+
70
+ # Value to be used in JSON.
71
+ # @return [*]
72
+ def json_value
73
+ value
74
+ end
75
+
76
+ # Value to be used in URLs.
77
+ # @return [String]
78
+ def url_value
79
+ @value
80
+ end
81
+
82
+ # Returns the XML representation of the property to the supplied XML
83
+ # builder.
84
+ # @param xml_builder [Nokogiri::XML::Builder]
85
+ def to_xml(xml_builder)
86
+ attributes = {
87
+ 'metadata:type' => type,
88
+ }
89
+
90
+ if value.nil?
91
+ attributes['metadata:null'] = 'true'
92
+ xml_builder['data'].send(name.to_sym, attributes)
93
+ else
94
+ xml_builder['data'].send(name.to_sym, attributes, xml_value)
95
+ end
96
+ end
97
+
98
+ # Creates a new property instance from an XML element
99
+ # @param property_xml [Nokogiri::XML::Element]
100
+ # @param options [Hash]
101
+ # @return [FrOData::Property]
102
+ def self.from_xml(property_xml, options = {})
103
+ if property_xml.attributes['null'].andand.value == 'true'
104
+ content = nil
105
+ else
106
+ content = property_xml.content
107
+ end
108
+
109
+ new(property_xml.name, content, options)
110
+ end
111
+
112
+ protected
113
+
114
+ def default_options
115
+ {
116
+ allows_nil: true,
117
+ concurrency_mode: :none
118
+ }
119
+ end
120
+
121
+ def service
122
+ options[:service]
123
+ end
124
+
125
+ def logger
126
+ # Use a dummy logger if service is not available (-> unit tests)
127
+ @logger ||= service.andand.logger || Logger.new('/dev/null')
128
+ end
129
+
130
+ def validation_error(message)
131
+ if strict?
132
+ raise ArgumentError, "#{name}: #{message}"
133
+ else
134
+ logger.warn "#{name}: #{message}"
135
+ nil
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,41 @@
1
+ require 'singleton'
2
+
3
+ module FrOData
4
+ # Provides a registry for keeping track of various property types used by
5
+ # FrOData.
6
+ class PropertyRegistry
7
+ include Singleton
8
+
9
+ # Add a property type to the registry
10
+ #
11
+ # @param type_name [String] property type name to register
12
+ # @param klass [Class] Ruby class to use for the specified type
13
+ def add(type_name, klass)
14
+ properties[type_name] = klass
15
+ end
16
+
17
+ # Lookup a property by name and get the Ruby class to use for its instances
18
+ #
19
+ # @param type_name [String] the type name to lookup
20
+ # @return [Class, nil] the proper class or nil
21
+ def [](type_name)
22
+ properties[type_name]
23
+ end
24
+
25
+ # (see #add)
26
+ def self.add(type_name, klass)
27
+ FrOData::PropertyRegistry.instance.add(type_name, klass)
28
+ end
29
+
30
+ # (see #[])
31
+ def self.[](type_name)
32
+ FrOData::PropertyRegistry.instance[type_name]
33
+ end
34
+
35
+ private
36
+
37
+ def properties
38
+ @properties ||= {}
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,233 @@
1
+ require 'frodata/query/criteria'
2
+ require 'frodata/query/in_batches'
3
+
4
+ module FrOData
5
+ # FrOData::Query provides the query interface for requesting Entities matching
6
+ # specific criteria from an FrOData::EntitySet. This class should not be
7
+ # instantiated directly, but can be. Normally you will access a Query by
8
+ # first asking for one from the FrOData::EntitySet you want to query.
9
+ class Query
10
+ attr_reader :options
11
+
12
+ include InBatches
13
+
14
+ # Create a new Query for the provided EntitySet
15
+ # @param entity_set [FrOData::EntitySet]
16
+ # @param options [Hash] Query options
17
+ def initialize(entity_set, options = {})
18
+ @entity_set = entity_set
19
+ @options = options
20
+ setup_empty_criteria_set
21
+ end
22
+
23
+ # Instantiates an FrOData::Query::Criteria for the named property.
24
+ # @param property [to_s]
25
+ def [](property)
26
+ property_instance = @entity_set.new_entity.get_property(property)
27
+ property_instance = property if property_instance.nil?
28
+ FrOData::Query::Criteria.new(property: property_instance)
29
+ end
30
+
31
+ # Find the Entity with the supplied key value.
32
+ # @param key [to_s] primary key to lookup
33
+ # @return [FrOData::Entity,nil]
34
+ def find(key)
35
+ entity = @entity_set.new_entity
36
+ key_property = entity.get_property(entity.primary_key)
37
+ key_property.value = key
38
+
39
+ pathname = "#{entity_set.name}(#{key_property.url_value})"
40
+ query = [pathname, assemble_criteria].compact.join('?')
41
+ execute(query).first
42
+ end
43
+
44
+ # Adds a filter criteria to the query.
45
+ # For filter syntax see https://msdn.microsoft.com/en-us/library/gg309461.aspx
46
+ # Syntax:
47
+ # Property Operator Value
48
+ #
49
+ # For example:
50
+ # Name eq 'Customer Service'
51
+ #
52
+ # Operators:
53
+ # eq, ne, gt, ge, lt, le, and, or, not
54
+ #
55
+ # Value
56
+ # can be 'null', can use single quotes
57
+ # @param criteria
58
+ def where(criteria)
59
+ criteria_set[:filter] << criteria
60
+ self
61
+ end
62
+
63
+ # Adds a fulltext search term to the query
64
+ # NOTE: May not be implemented by the service
65
+ # @param term [String]
66
+ def search(term)
67
+ criteria_set[:search] << term
68
+ self
69
+ end
70
+
71
+ # Adds a filter criteria to the query with 'and' logical operator.
72
+ # @param criteria
73
+ #def and(criteria)
74
+ #
75
+ #end
76
+
77
+ # Adds a filter criteria to the query with 'or' logical operator.
78
+ # @param criteria
79
+ #def or(criteria)
80
+ #
81
+ #end
82
+
83
+ # Specify properties to order the result by.
84
+ # Can use 'desc' like 'Name desc'
85
+ # @param properties [Array<Symbol>]
86
+ # @return [self]
87
+ def order_by(*properties)
88
+ criteria_set[:orderby] += properties
89
+ self
90
+ end
91
+
92
+ # Specify associations to expand in the result.
93
+ # @param associations [Array<Symbol>]
94
+ # @return [self]
95
+ def expand(*associations)
96
+ criteria_set[:expand] += associations
97
+ self
98
+ end
99
+
100
+ # Specify properties to select within the result.
101
+ # @param properties [Array<Symbol>]
102
+ # @return [self]
103
+ def select(*properties)
104
+ criteria_set[:select] += properties
105
+ self
106
+ end
107
+
108
+ # Add skip criteria to query.
109
+ # @param value [to_i]
110
+ # @return [self]
111
+ def skip(value)
112
+ criteria_set[:skip] = value.to_i
113
+ self
114
+ end
115
+
116
+ # Add limit criteria to query.
117
+ # @param value [to_i]
118
+ # @return [self]
119
+ def limit(value)
120
+ criteria_set[:top] = value.to_i
121
+ self
122
+ end
123
+
124
+ # Add inline count criteria to query.
125
+ # Not Supported in CRM2011
126
+ # @return [self]
127
+ def include_count
128
+ criteria_set[:inline_count] = true
129
+ self
130
+ end
131
+
132
+ # Convert Query to string.
133
+ # @return [String]
134
+ def to_s
135
+ [entity_set.name, assemble_criteria].compact.join('?')
136
+ end
137
+
138
+ # Execute the query.
139
+ # @return [FrOData::Service::Response]
140
+ def execute(url_chunk = self.to_s)
141
+ service.execute(url_chunk, options.merge(query: self))
142
+ end
143
+
144
+ # Executes the query to get a count of entities.
145
+ # @return [Integer]
146
+ def count
147
+ url_chunk = ["#{entity_set.name}/$count", assemble_criteria].compact.join('?')
148
+ response = self.execute(url_chunk)
149
+ # Some servers (*cough* Microsoft *cough*) seem to
150
+ # return extraneous characters in the response.
151
+ response.body.scan(/\d+/).first.to_i
152
+ end
153
+
154
+ # Checks whether a query will return any results by calling #count
155
+ # @return [Boolean]
156
+ def empty?
157
+ self.count == 0
158
+ end
159
+
160
+ # The EntitySet for this query.
161
+ # @return [FrOData::EntitySet]
162
+ # @api private
163
+ def entity_set
164
+ @entity_set
165
+ end
166
+
167
+ # The service for this query
168
+ # @return [FrOData::Service]
169
+ # @api private
170
+ def service
171
+ @service ||= entity_set.service
172
+ end
173
+
174
+ private
175
+
176
+ def criteria_set
177
+ @criteria_set
178
+ end
179
+
180
+ def setup_empty_criteria_set
181
+ @criteria_set = {
182
+ filter: [],
183
+ search: [],
184
+ select: [],
185
+ expand: [],
186
+ orderby: [],
187
+ skip: 0,
188
+ top: 0,
189
+ inline_count: false
190
+ }
191
+ end
192
+
193
+ def assemble_criteria
194
+ criteria = [
195
+ filter_criteria,
196
+ search_criteria,
197
+ list_criteria(:orderby),
198
+ list_criteria(:expand),
199
+ list_criteria(:select),
200
+ inline_count_criteria,
201
+ paging_criteria(:skip),
202
+ paging_criteria(:top)
203
+ ].compact!
204
+
205
+ criteria.empty? ? nil : criteria.join('&')
206
+ end
207
+
208
+ def filter_criteria
209
+ return nil if criteria_set[:filter].empty?
210
+ filters = criteria_set[:filter].collect(&:to_s)
211
+ "$filter=#{filters.join(' and ')}"
212
+ end
213
+
214
+ def search_criteria
215
+ return nil if criteria_set[:search].empty?
216
+ filters = criteria_set[:search].collect(&:to_s)
217
+ "$search=#{filters.join(' AND ')}"
218
+ end
219
+
220
+ def list_criteria(name)
221
+ criteria_set[name].empty? ? nil : "$#{name}=#{criteria_set[name].join(',')}"
222
+ end
223
+
224
+ # inlinecount not supported by Microsoft CRM 2011
225
+ def inline_count_criteria
226
+ criteria_set[:inline_count] ? '$count=true' : nil
227
+ end
228
+
229
+ def paging_criteria(name)
230
+ criteria_set[name] == 0 ? nil : "$#{name}=#{criteria_set[name]}"
231
+ end
232
+ end
233
+ end