odata4 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) 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 +120 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +23 -0
  11. data/README.md +287 -0
  12. data/Rakefile +7 -0
  13. data/TODO.md +55 -0
  14. data/lib/odata4.rb +37 -0
  15. data/lib/odata4/complex_type.rb +76 -0
  16. data/lib/odata4/complex_type/property.rb +114 -0
  17. data/lib/odata4/entity.rb +319 -0
  18. data/lib/odata4/entity_set.rb +162 -0
  19. data/lib/odata4/enum_type.rb +95 -0
  20. data/lib/odata4/enum_type/property.rb +62 -0
  21. data/lib/odata4/navigation_property.rb +29 -0
  22. data/lib/odata4/navigation_property/proxy.rb +76 -0
  23. data/lib/odata4/properties.rb +25 -0
  24. data/lib/odata4/properties/binary.rb +50 -0
  25. data/lib/odata4/properties/boolean.rb +37 -0
  26. data/lib/odata4/properties/date.rb +27 -0
  27. data/lib/odata4/properties/date_time.rb +83 -0
  28. data/lib/odata4/properties/date_time_offset.rb +17 -0
  29. data/lib/odata4/properties/decimal.rb +50 -0
  30. data/lib/odata4/properties/float.rb +67 -0
  31. data/lib/odata4/properties/geography.rb +13 -0
  32. data/lib/odata4/properties/geography/base.rb +162 -0
  33. data/lib/odata4/properties/geography/line_string.rb +33 -0
  34. data/lib/odata4/properties/geography/point.rb +31 -0
  35. data/lib/odata4/properties/geography/polygon.rb +38 -0
  36. data/lib/odata4/properties/guid.rb +17 -0
  37. data/lib/odata4/properties/integer.rb +107 -0
  38. data/lib/odata4/properties/number.rb +14 -0
  39. data/lib/odata4/properties/string.rb +72 -0
  40. data/lib/odata4/properties/time.rb +40 -0
  41. data/lib/odata4/properties/time_of_day.rb +27 -0
  42. data/lib/odata4/property.rb +118 -0
  43. data/lib/odata4/property_registry.rb +41 -0
  44. data/lib/odata4/query.rb +231 -0
  45. data/lib/odata4/query/criteria.rb +92 -0
  46. data/lib/odata4/query/criteria/comparison_operators.rb +49 -0
  47. data/lib/odata4/query/criteria/date_functions.rb +61 -0
  48. data/lib/odata4/query/criteria/geography_functions.rb +21 -0
  49. data/lib/odata4/query/criteria/lambda_operators.rb +27 -0
  50. data/lib/odata4/query/criteria/string_functions.rb +40 -0
  51. data/lib/odata4/query/in_batches.rb +58 -0
  52. data/lib/odata4/query/result.rb +84 -0
  53. data/lib/odata4/query/result/atom.rb +41 -0
  54. data/lib/odata4/query/result/json.rb +42 -0
  55. data/lib/odata4/railtie.rb +19 -0
  56. data/lib/odata4/service.rb +344 -0
  57. data/lib/odata4/service_registry.rb +52 -0
  58. data/lib/odata4/version.rb +3 -0
  59. data/odata4.gemspec +34 -0
  60. data/spec/fixtures/files/entity_to_xml.xml +17 -0
  61. data/spec/fixtures/files/metadata.xml +150 -0
  62. data/spec/fixtures/files/product_0.json +10 -0
  63. data/spec/fixtures/files/product_0.xml +28 -0
  64. data/spec/fixtures/files/products.json +106 -0
  65. data/spec/fixtures/files/products.xml +308 -0
  66. data/spec/fixtures/files/supplier_0.json +26 -0
  67. data/spec/fixtures/files/supplier_0.xml +32 -0
  68. data/spec/fixtures/vcr_cassettes/complex_type_specs.yml +127 -0
  69. data/spec/fixtures/vcr_cassettes/entity_set_specs.yml +1348 -0
  70. data/spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml +183 -0
  71. data/spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml +256 -0
  72. data/spec/fixtures/vcr_cassettes/entity_set_specs/new_entry.yml +185 -0
  73. data/spec/fixtures/vcr_cassettes/entity_specs.yml +285 -0
  74. data/spec/fixtures/vcr_cassettes/navigation_property_proxy_specs.yml +346 -0
  75. data/spec/fixtures/vcr_cassettes/query/result_specs.yml +189 -0
  76. data/spec/fixtures/vcr_cassettes/query_specs.yml +663 -0
  77. data/spec/fixtures/vcr_cassettes/service_registry_specs.yml +129 -0
  78. data/spec/fixtures/vcr_cassettes/service_specs.yml +127 -0
  79. data/spec/fixtures/vcr_cassettes/usage_example_specs.yml +749 -0
  80. data/spec/odata4/complex_type_spec.rb +116 -0
  81. data/spec/odata4/entity/shared_examples.rb +82 -0
  82. data/spec/odata4/entity_set_spec.rb +168 -0
  83. data/spec/odata4/entity_spec.rb +151 -0
  84. data/spec/odata4/enum_type_spec.rb +134 -0
  85. data/spec/odata4/navigation_property/proxy_spec.rb +44 -0
  86. data/spec/odata4/navigation_property_spec.rb +55 -0
  87. data/spec/odata4/properties/binary_spec.rb +50 -0
  88. data/spec/odata4/properties/boolean_spec.rb +72 -0
  89. data/spec/odata4/properties/date_spec.rb +23 -0
  90. data/spec/odata4/properties/date_time_offset_spec.rb +30 -0
  91. data/spec/odata4/properties/date_time_spec.rb +23 -0
  92. data/spec/odata4/properties/decimal_spec.rb +24 -0
  93. data/spec/odata4/properties/float_spec.rb +45 -0
  94. data/spec/odata4/properties/geography/line_string_spec.rb +33 -0
  95. data/spec/odata4/properties/geography/point_spec.rb +29 -0
  96. data/spec/odata4/properties/geography/polygon_spec.rb +55 -0
  97. data/spec/odata4/properties/geography/shared_examples.rb +72 -0
  98. data/spec/odata4/properties/guid_spec.rb +17 -0
  99. data/spec/odata4/properties/integer_spec.rb +58 -0
  100. data/spec/odata4/properties/string_spec.rb +46 -0
  101. data/spec/odata4/properties/time_of_day_spec.rb +23 -0
  102. data/spec/odata4/properties/time_spec.rb +15 -0
  103. data/spec/odata4/property_registry_spec.rb +16 -0
  104. data/spec/odata4/property_spec.rb +32 -0
  105. data/spec/odata4/query/criteria_spec.rb +229 -0
  106. data/spec/odata4/query/result_spec.rb +53 -0
  107. data/spec/odata4/query_spec.rb +196 -0
  108. data/spec/odata4/service_registry_spec.rb +18 -0
  109. data/spec/odata4/service_spec.rb +80 -0
  110. data/spec/odata4/usage_example_spec.rb +176 -0
  111. data/spec/spec_helper.rb +32 -0
  112. data/spec/support/coverage.rb +2 -0
  113. data/spec/support/vcr.rb +9 -0
  114. metadata +380 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1a49a6ff012ef0bb66a692514d673479303e198b
4
+ data.tar.gz: 99cd07d3a97e6a972d81917949a2f4344745a735
5
+ SHA512:
6
+ metadata.gz: f176202b1e8998dc076b21c33bcfde3ff95eb360cbff5fee4073aa9ba3d16334322c26801e3e3ed065101b7895b46bb418c4cddf21b3259f6663cff8f42c185c
7
+ data.tar.gz: b0a5b08aa206f1cf4baf90ecf7e2fe19002ae81bfae49b27d29523266ee13dde9ca01e7d1dfd3471572f4bdec61c9613d75f6b60ccfc6ccafab59647c49fd114
@@ -0,0 +1,2 @@
1
+ require 'autotest/bundler'
2
+
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .idea
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ *.bundle
20
+ *.so
21
+ *.o
22
+ *.a
23
+ mkmf.log
24
+ private
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1 @@
1
+ odata
@@ -0,0 +1 @@
1
+ 2.1
@@ -0,0 +1,75 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
6
+ - 2.1.1
7
+ - 2.1.2
8
+ - 2.1.3
9
+ - 2.1.4
10
+ - 2.1.5
11
+ - jruby
12
+ - jruby-head
13
+ jdk:
14
+ - openjdk6
15
+ - openjdk7
16
+ - oraclejdk7
17
+ - oraclejdk8
18
+ branches:
19
+ only:
20
+ - master
21
+ matrix:
22
+ exclude:
23
+ - rvm: 1.9.3
24
+ jdk: openjdk6
25
+ - rvm: 1.9.3
26
+ jdk: oraclejdk7
27
+ - rvm: 1.9.3
28
+ jdk: oraclejdk8
29
+ - rvm: 2.0.0
30
+ jdk: openjdk6
31
+ - rvm: 2.0.0
32
+ jdk: oraclejdk7
33
+ - rvm: 2.0.0
34
+ jdk: oraclejdk8
35
+ - rvm: 2.1.0
36
+ jdk: openjdk6
37
+ - rvm: 2.1.0
38
+ jdk: oraclejdk7
39
+ - rvm: 2.1.0
40
+ jdk: oraclejdk8
41
+ - rvm: 2.1.1
42
+ jdk: openjdk6
43
+ - rvm: 2.1.1
44
+ jdk: oraclejdk7
45
+ - rvm: 2.1.1
46
+ jdk: oraclejdk8
47
+ - rvm: 2.1.2
48
+ jdk: openjdk6
49
+ - rvm: 2.1.2
50
+ jdk: oraclejdk7
51
+ - rvm: 2.1.2
52
+ jdk: oraclejdk8
53
+ - rvm: 2.1.3
54
+ jdk: openjdk6
55
+ - rvm: 2.1.3
56
+ jdk: oraclejdk7
57
+ - rvm: 2.1.3
58
+ jdk: oraclejdk8
59
+ - rvm: 2.1.4
60
+ jdk: openjdk6
61
+ - rvm: 2.1.4
62
+ jdk: oraclejdk7
63
+ - rvm: 2.1.4
64
+ jdk: oraclejdk8
65
+ - rvm: 2.1.5
66
+ jdk: openjdk6
67
+ - rvm: 2.1.5
68
+ jdk: oraclejdk7
69
+ - rvm: 2.1.5
70
+ jdk: oraclejdk8
71
+ allow_failures:
72
+ - rvm: jruby-head
73
+ addons:
74
+ code_climate:
75
+ repo_token: 56e2763b5bfe138f566c5f2bf23c14deee4f8990324436dbde07ee2a34bb87f8
@@ -0,0 +1,120 @@
1
+ # CHANGELOG
2
+
3
+ ## 0.7.0
4
+
5
+ Major rewrite
6
+
7
+ * Added support for OData 4.0
8
+ * Dropped support for OData 3.0
9
+
10
+ ## 0.6.18
11
+
12
+ * Minor internal fixes to OData::Query::Criteria.
13
+
14
+ ## 0.6.17
15
+
16
+ * Added more graceful handling of manually passed advanced queries to
17
+ OData::Query::Criteria.
18
+
19
+ ## 0.6.16
20
+
21
+ * Implemented OData::Query#empty? and fixed OData::Query#count.
22
+
23
+ ## 0.6.15
24
+
25
+ * Fixed minor bug in last release.
26
+
27
+ ## 0.6.14
28
+
29
+ * Changed implementation of OData::Association::Proxy#[] to properly handle
30
+ empty associations.
31
+
32
+ ## 0.6.13
33
+
34
+ * Minor bug fix in OData::Query::Result#each implementation.
35
+
36
+ ## 0.6.12
37
+
38
+ * Minor bug fix in OData::Query::Result#each implementation.
39
+
40
+ ## 0.6.11
41
+
42
+ * Added logic to allow OData::Query::Result#each to handle paginated results.
43
+
44
+ ## 0.6.10
45
+
46
+ * Changed how associations behave with mulitiplicity of one.
47
+
48
+ ## 0.6.9
49
+
50
+ * Changed how OData::Entity#from_xml functions to better work with feed results.
51
+
52
+ ## 0.6.8
53
+
54
+ * Added empty checking when checking for a nil value.
55
+
56
+ ## 0.6.7
57
+
58
+ * Changed how commit failures are handled to use logging instead of raising an
59
+ error.
60
+ * Added errors array to OData::Entity.
61
+
62
+ ## 0.6.6
63
+
64
+ * Updated OData::EntitySet#setup_entity_post_request to properly format primary
65
+ key values when posting an entity.
66
+
67
+ ## 0.6.5
68
+
69
+ * Fixed problem in OData::ComplexType#to_xml implementation.
70
+
71
+ ## 0.6.4
72
+
73
+ * Added implementation of OData::ComplexType#type.
74
+
75
+ ## 0.6.3
76
+
77
+ * Added OData::ComplexType#to_xml to make entity saving work correctly.
78
+
79
+ ## 0.6.1
80
+
81
+ * Made a minor change to internals of OData::Query::Criteria.
82
+
83
+ ## 0.6.0
84
+
85
+ * Added ability to handle associations in a reasonable way.
86
+
87
+ ## 0.5.1-8
88
+
89
+ * Tons of changes throughout the code base
90
+
91
+ ## 0.5.0
92
+
93
+ * Stopped using namespace from OData service as unique identifier in favor of
94
+ a supplied name option when opening a service.
95
+
96
+ ## 0.4.0
97
+
98
+ * Added OData::Query#execute to run query and return a result.
99
+ * Added OData::Query::Result to handle enumeration of query results.
100
+
101
+ ## 0.3.2
102
+
103
+ * Refactored internals of the query interface.
104
+
105
+ ## 0.3.1
106
+
107
+ * Resolved issues causing failure on Ruby 1.9 and JRuby.
108
+
109
+ ## 0.3.0
110
+
111
+ * Removed dependency on ActiveSupport
112
+
113
+ ## 0.2.0
114
+
115
+ * Added query interface for [System Query Options](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol#queryingcollections)
116
+ * Refactored internal uses of System Query Options
117
+
118
+ ## 0.1.0
119
+
120
+ * Core read/write behavior for OData v1-3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in odata.gemspec
4
+ gemspec
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2018 Christoph Wagner <christoph@wrstudios.com>
2
+ 2014 James Thompson <james@plainprograms.com>
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,287 @@
1
+ # OData4
2
+
3
+ The OData4 gem provides a simple wrapper around the OData Version 4.0 API protocol.
4
+ It has the ability to automatically inspect compliant APIs and expose the relevant Ruby objects dynamically.
5
+ It also provides a set of code generation tools for quickly bootstrapping more custom service libraries.
6
+
7
+ **This gem supports [OData Version 4.0](http://www.odata.org/documentation/). Support for older versions is not a goal.**
8
+
9
+ If you need a gem to integration with OData Version 3, you can use James Thompson's [original OData gem][ruby-odata], upon which this gem is based.
10
+
11
+ [![Build Status](https://app.codeship.com/projects/da1eb540-ce3f-0135-2ddc-161d5c3cc5fd/status?branch=master)](https://app.codeship.com/projects/262148)
12
+ [![Maintainability](https://api.codeclimate.com/v1/badges/f151944dc05b2c7268e5/maintainability)](https://codeclimate.com/github/wrstudios/odata4/maintainability)
13
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/f151944dc05b2c7268e5/test_coverage)](https://codeclimate.com/github/wrstudios/odata4/test_coverage)
14
+ [![Dependency Status](https://gemnasium.com/badges/github.com/wrstudios/odata4.svg)](https://gemnasium.com/github.com/wrstudios/odata4)
15
+ [![Documentation](http://inch-ci.org/github/wrstudios/odata4.png?branch=master)](http://www.rubydoc.info/github/wrstudios/odata4/master)
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's `Gemfile`:
20
+
21
+ gem 'odata4', git: 'https://github.com/wrstudios/odata4'
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install odata4
30
+
31
+ ## Usage
32
+
33
+ ### Services & the Service Registry
34
+
35
+ The OData4 gem provides a number of core classes, the two most basic ones are the `OData4::Service` and the `OData4::ServiceRegistry`.
36
+ The only time you will need to worry about the `OData4::ServiceRegistry` is when you have multiple OData4
37
+ services you are interacting with that you want to keep straight easily.
38
+ The nice thing about `OData4::Service` is that it automatically registers with the registry on creation, so there is no manual interaction with the registry necessary.
39
+
40
+ To create an `OData4::Service` simply provide the location of a service endpoint to it like this:
41
+
42
+ ```ruby
43
+ OData4::Service.open('http://services.odata.org/V4/OData/OData.service')
44
+ ```
45
+
46
+ You may also provide an options hash after the URL.
47
+ It is suggested that you supply a name for the service via this hash like so:
48
+
49
+ ```ruby
50
+ OData4::Service.open('http://services.odata.org/V4/OData/OData.service', name: 'ODataDemo')
51
+ ```
52
+
53
+ This one call will setup the service and allow for the discovery of everything the other parts of the OData4 gem need to function.
54
+ The two methods you will want to remember from `OData4::Service` are `#service_url` and `#name`.
55
+ Both of these methods are available on instances and will allow for lookup in the `OData4::ServiceRegistry`, should you need it.
56
+
57
+ Using either the service URL or the name provided as an option when creating an `OData4::Service` will allow for quick lookup in the `OData4::ServiceRegistry` like such:
58
+
59
+ ```ruby
60
+ OData4::ServiceRegistry['http://services.odata.org/V4/OData/OData.service']
61
+ OData4::ServiceRegistry['ODataDemo']
62
+ ```
63
+
64
+ Both of the above calls would retrieve the same service from the registry.
65
+ At the moment there is no protection against name collisions provided in `OData4::ServiceRegistry`.
66
+ So, looking up services by their service URL is the most exact method, but lookup by name is provided for convenience.
67
+
68
+ ### Authentication
69
+
70
+ When authenticating with your service you can set parameters to the Typhoeus gem which uses libcurl.
71
+ Use the **:typhoeus** option to set your authentication.
72
+
73
+ For example using **ntlm** authentication:
74
+
75
+ ```ruby
76
+ conn = OData4::Service.open('http://services.odata.org/V4/OData/OData.service', {
77
+ name: 'ODataDemo',
78
+ typhoeus: {
79
+ username: 'username',
80
+ password: 'password',
81
+ httpauth: :ntlm
82
+ }
83
+ })
84
+ ```
85
+
86
+ For more authentication options see [libcurl][libcurl] or [typhoeus][typhoeus].
87
+
88
+ [libcurl]: http://curl.haxx.se/libcurl/c/CURLOPT_HTTPAUTH.html
89
+ [typhoeus]: https://github.com/typhoeus/typhoeus
90
+
91
+ ### Metadata File
92
+
93
+ Typically the metadata file of a service can be quite large.
94
+ You can speed your load time by forcing the service to load the metadata from a file rather than a URL.
95
+ This is only recommended for testing purposes, as the metadata file can change.
96
+
97
+ ```ruby
98
+ conn = OData4::Service.open('http://services.odata.org/V4/OData/OData.service', {
99
+ name: 'ODataDemo',
100
+ metadata_file: "metadata.xml",
101
+ })
102
+ ```
103
+
104
+ ### Headers
105
+
106
+ You can set the headers with the **:typhoeus** param like so:
107
+
108
+ ```ruby
109
+ conn = OData4::Service.open('http://services.odata.org/V4/OData/OData.service', {
110
+ name: 'ODataDemo',
111
+ typhoeus: {
112
+ headers: {
113
+ "Authorization" => "Bearer #{token}"
114
+ }
115
+ }
116
+ })
117
+ ```
118
+
119
+ ### Entity Sets
120
+
121
+ When it comes to reading data from an OData4 service the most typical way will be via `OData4::EntitySet` instances.
122
+ Under normal circumstances you should never need to worry about an `OData4::EntitySet` directly.
123
+ For example, to get an `OData4::EntitySet` for the products in the ODataDemo service simply access the entity set through the service like this:
124
+
125
+ ```ruby
126
+ service = OData4::Service.open('http://services.odata.org/V4/OData/OData.service')
127
+ products = service['ProductsSet'] # => OData4::EntitySet
128
+ ```
129
+
130
+ `OData4::EntitySet` instances implement the `Enumerable` module, meaning you can work with them very naturally, like this:
131
+
132
+ ```ruby
133
+ products.each do |entity|
134
+ entity # => OData4::Entity for type Product
135
+ end
136
+ ```
137
+
138
+ You can get a list of all your entity sets like this:
139
+
140
+ ```ruby
141
+ service.entity_sets
142
+ ```
143
+
144
+ #### Count
145
+ Some versions of Microsoft CRM do not support count.
146
+
147
+ ```ruby
148
+ products.count
149
+ ```
150
+
151
+ #### Collections
152
+ You can you the following methods to grab a collection of Entities:
153
+
154
+ ```ruby
155
+ products.each do |entity|
156
+ ...
157
+ end
158
+ ```
159
+
160
+ The first entity object returns a single entity object.
161
+
162
+ ```ruby
163
+ products.first
164
+ ```
165
+
166
+ `first(x)` returns an array of entity objects.
167
+
168
+ ```ruby
169
+ products.first(x)
170
+ ```
171
+
172
+ #### Find a certain Entity
173
+
174
+ ```ruby
175
+ service['ProductsSet']['<guid of entity>']
176
+ ```
177
+
178
+ With certain navigation properties expanded (i.e. eagerly loaded):
179
+
180
+ ```ruby
181
+ # Eagerly load a single navigation property
182
+ service['ProductsSet', expand: 'Categories']
183
+
184
+ # Eagerly load multiple navigation properties
185
+ service['ProductsSet', expand: ['Categories', 'Supplier']]
186
+
187
+ # Eagerly load ALL navigation properties
188
+ service['ProductsSet', expand: :all]
189
+ ```
190
+
191
+ ### Entities
192
+
193
+ `OData4::Entity` instances represent individual entities, or records, in a given service.
194
+ They are returned primarily through interaction with instances of `OData4::EntitySet`.
195
+ You can access individual properties on an `OData4::Entity` like so:
196
+
197
+ ```ruby
198
+ product = products.first # => OData4::Entity
199
+ product['Name'] # => 'Bread'
200
+ product['Price'] # => 2.5 (Float)
201
+ ```
202
+
203
+ Individual properties on an `OData4::Entity` are automatically typecast by the gem, so you don't have to worry about too much when working with entities.
204
+ The way this is implemented internally guarantees that an `OData4::Entity` is always ready to save back to the service or `OData4::EntitySet`, which you do like so:
205
+
206
+ ```ruby
207
+ service['Products'] << product # Write back to the service
208
+ products << product # Write back to the Entity Set
209
+ ```
210
+
211
+ You can get a list of all your entities like this:
212
+
213
+ ```ruby
214
+ service.entity_types
215
+ ```
216
+
217
+ #### Entity Properties
218
+ Reading, parsing and instantiating all properties of an entity can add up to a significant amount of time, particularly for those entities with a large number of properties.
219
+ To speed this process up all properties are lazy loaded.
220
+ Which means it will store the name of the property, but will not parse and instantiate the property until you want to use it.
221
+
222
+ You can find all the property names of your entity with
223
+
224
+ ```ruby
225
+ product.property_names
226
+ ```
227
+
228
+ You can grab the parsed value of the property as follows:
229
+
230
+ ```ruby
231
+ product["Name"]
232
+ ```
233
+
234
+ or, you can get a hold of the property class instance using
235
+
236
+ ```ruby
237
+ product.get_property("Name")
238
+ ```
239
+
240
+ This will parse and instantiate the property if it hasn't done so yet.
241
+
242
+ ### Queries
243
+
244
+ `OData4::Query` instances form the base for finding specific entities within an `OData4::EntitySet`.
245
+ A query object exposes a number of capabilities based on
246
+ the [System Query Options](http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part1-protocol/odata-v4.0-errata03-os-part1-protocol-complete.html#_Toc453752288) provided for in the OData V4.0 specification.
247
+ Below is just a partial example of what is possible:
248
+
249
+ ```ruby
250
+ query = service['Products'].query
251
+ query.where(query[:Price].lt(15))
252
+ query.where(query[:Rating].gt(3))
253
+ query.limit(3)
254
+ query.skip(2)
255
+ query.order_by("Name")
256
+ query.select("Name,CreatedBy")
257
+ query.inline_count
258
+ results = query.execute
259
+ results.each {|product| puts product['Name']}
260
+ ```
261
+
262
+ The process of querying is kept purposely verbose to allow for lazy behavior to be implemented at higher layers.
263
+ Internally, `OData4::Query` relies on the `OData4::Query::Criteria` for the way the `where` method works.
264
+ You should refer to the published RubyDocs for full details on the various capabilities:
265
+
266
+ * [OData4::Query](http://rubydoc.info/github/wrstudios/odata4/master/OData4/Query)
267
+ * [OData4::Query::Criteria](http://rubydoc.info/github/wrstudios/odata4/master/OData4/Query/Criteria)
268
+
269
+ ## Contributing
270
+
271
+ 1. Fork it (`https://github.com/[my-github-username]/odata/fork`)
272
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
273
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
274
+ 4. Push to the branch (`git push origin my-new-feature`)
275
+ 5. Create a new Pull Request
276
+
277
+ ## Credits
278
+
279
+ Many thanks go to [James Thompson][@plainprogrammer], who wrote the [original OData (Version 3.0) gem][ruby-odata].
280
+
281
+ [@plainprogrammer]: https://github.com/plainprogrammer
282
+ [ruby-odata]: https://github.com/ruby-odata/odata
283
+
284
+ Also, I would like to thank [W+R Studios][wrstudios] for generously allowing me to work on Open Source software like this. If you want to work on interesting challenges with an awesome team, check out our [open positions][wrcareers].
285
+
286
+ [wrstudios]: http://wrstudios.com/
287
+ [wrcareers]: http://wrstudios.com/careers