ruby_odata 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.gitignore +3 -2
  2. data/.travis.yml +2 -1
  3. data/.yardopts +6 -0
  4. data/CHANGELOG.md +102 -0
  5. data/Guardfile +14 -0
  6. data/README.md +285 -0
  7. data/Rakefile +0 -7
  8. data/features/basic_auth.feature +3 -2
  9. data/features/batch_request.feature +7 -6
  10. data/features/cassettes/basic_auth_protected_resource.yml +57 -0
  11. data/features/cassettes/batch_request_additions.yml +69 -0
  12. data/features/cassettes/batch_request_deletes.yml +69 -0
  13. data/features/cassettes/batch_request_updates.yml +69 -0
  14. data/features/cassettes/clean_database_for_testing.yml +46 -0
  15. data/features/cassettes/cucumber_tags/basic_auth.yml +297 -0
  16. data/features/cassettes/cucumber_tags/batch_request.yml +1459 -0
  17. data/features/cassettes/cucumber_tags/complex_types.yml +326 -0
  18. data/features/cassettes/cucumber_tags/error_handling.yml +64 -0
  19. data/features/cassettes/cucumber_tags/query_builder.yml +2025 -0
  20. data/features/cassettes/cucumber_tags/service.yml +234 -0
  21. data/features/cassettes/cucumber_tags/service_manage.yml +937 -0
  22. data/features/cassettes/cucumber_tags/service_methods.yml +647 -0
  23. data/features/cassettes/cucumber_tags/ssl.yml +203 -0
  24. data/features/cassettes/cucumber_tags/type_conversion.yml +337 -0
  25. data/features/cassettes/service_manage_additions.yml +65 -0
  26. data/features/cassettes/service_manage_deletions.yml +58 -0
  27. data/features/cassettes/service_manage_deletions_2.yml +58 -0
  28. data/features/cassettes/unsecured_metadata.yml +89 -0
  29. data/features/complex_types.feature +4 -3
  30. data/features/error_handling.feature +14 -0
  31. data/features/query_builder.feature +30 -9
  32. data/features/service.feature +4 -3
  33. data/features/service_manage.feature +6 -5
  34. data/features/service_methods.feature +3 -2
  35. data/features/ssl.feature +8 -8
  36. data/features/step_definitions/service_steps.rb +38 -24
  37. data/features/support/env.rb +1 -3
  38. data/features/support/hooks.rb +3 -2
  39. data/features/support/pickle.rb +29 -18
  40. data/features/support/vcr.rb +24 -0
  41. data/features/type_conversion.feature +16 -17
  42. data/lib/ruby_odata/association.rb +7 -6
  43. data/lib/ruby_odata/class_builder.rb +6 -7
  44. data/lib/ruby_odata/exceptions.rb +4 -0
  45. data/lib/ruby_odata/helpers.rb +11 -0
  46. data/lib/ruby_odata/operation.rb +5 -6
  47. data/lib/ruby_odata/property_metadata.rb +4 -5
  48. data/lib/ruby_odata/query_builder.rb +98 -63
  49. data/lib/ruby_odata/service.rb +118 -103
  50. data/lib/ruby_odata/version.rb +3 -1
  51. data/lib/ruby_odata.rb +20 -18
  52. data/ruby_odata.gemspec +16 -12
  53. data/spec/query_builder_spec.rb +78 -14
  54. data/spec/service_spec.rb +83 -83
  55. data/spec/support/sample_service_matcher.rb +15 -0
  56. data/test/RubyODataService/RubyODataService/App_Data/.gitkeep +0 -0
  57. data/test/blueprints.rb +15 -9
  58. data/test/usage_samples/querying.rb +5 -1
  59. data/test/usage_samples/sample_data.rb +1 -3
  60. metadata +213 -39
  61. data/CHANGELOG.rdoc +0 -88
  62. data/README.rdoc +0 -259
data/README.rdoc DELETED
@@ -1,259 +0,0 @@
1
- = ruby_odata
2
-
3
- The <b>Open Data Protocol</b> (OData) is a fantastic way to query and update data over standard Web technologies. The ruby_odata library acts as a consumer of OData services.
4
-
5
- == Resources
6
-
7
- * Source Code (hosted on GitHub): http://github.com/visoft/ruby_odata
8
- * Documentation (hosted on rdoc.info): http://rdoc.info/projects/visoft/ruby_odata
9
- * Issue tracking (hosted on GitHub): https://github.com/visoft/ruby_odata/issues
10
- * Wiki (hosted on GitHub): http://wiki.github.com/visoft/ruby_odata/
11
- * Gem (hosted on Gemcutter): http://gemcutter.org/gems/ruby_odata
12
- * Blog articles:
13
- * {Introducing a Ruby OData Client Library}[http://bit.ly/IntroRubyOData]
14
- * {Ruby OData Update v0.0.7}[http://bit.ly/ruby_odata007]
15
- * {Ruby OData Update v0.0.8}[http://bit.ly/ruby_odata008]
16
- * {Ruby OData Update v0.0.10}[http://bit.ly/ruby_odata0010]
17
-
18
- == Installation
19
- You can install ruby_odata as a gem using:
20
- gem install ruby_odata
21
-
22
- == Usage
23
-
24
- === Instantiating the Service
25
- There are various options that you can pass when creating an instance of the service, these include:
26
- * username: username for http basic auth
27
- * password: password for http basic auth
28
- * verify_ssl: false if no verification, otherwise mode (OpenSSL::SSL::VERIFY_PEER is default)
29
- * additional_params: a hash of query string params that will be passed on all calls (query, new, update, delete, batch)
30
- * namespace: a string based namespace to create your objects in. You can specify the namespace using periods as separators (like .NET, for example <tt>VisoftInc.Sample.Models</tt>) or using double colons as separators (like Ruby <tt>VisoftInc::Sample::Models</tt>). By providing a namespace you can prevent naming collisions in your applications.
31
-
32
- === Adding
33
- When you point at a service, an AddTo<EntityName> method is created for you. This method takes in the new entity to create. To commit the change, you need to call the save_changes method on the service. To add a new category for example, you would simply do the following:
34
-
35
- require 'ruby_odata'
36
-
37
- svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc"
38
- new_category = Category.new
39
- new_category.Name = "Sample Category"
40
- svc.AddToCategories(new_category)
41
- category = svc.save_changes
42
- puts category.to_json
43
-
44
- === Updating
45
- To update an object, simply pass the modified object to the update_object method on the service. Updating, like adding requires you to call save_changes in order to persist the change. For example:
46
-
47
- require 'ruby_odata'
48
-
49
- svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc"
50
- new_category = Category.new
51
- new_category.Name = "Sample Category"
52
- svc.AddToCategories(new_category)
53
- category = svc.save_changes
54
- puts category.to_json
55
-
56
- category.Name = 'Updated Category'
57
- svc.update_object(category)
58
- result = svc.save_changes
59
- puts "Was the category updated? #{result}"
60
-
61
- === Deleting
62
- Deleting an object involves passing the tracked object to the delete_object method on the service. Deleting is another function that involves the save_changes method (to commit the change back to the server). In this example, we'll add a category and then delete it.
63
-
64
- require 'ruby_odata'
65
-
66
- svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc"
67
- new_category = Category.new
68
- new_category.Name = "Sample Category"
69
- svc.AddToCategories(new_category)
70
- category = svc.save_changes
71
- puts category.to_json
72
-
73
- svc.delete_object(category)
74
- result = svc.save_changes
75
- puts "Was the category deleted? #{result}"
76
-
77
- === Add Link
78
- Adding a linkage between entities can now be performed outside of creation or modification of the objects. See the {OData documents}[http://www.odata.org/developers/protocols/operations#CreatingLinksbetweenEntries] for more details.
79
- To add a link between entities, simply call the +add_link+ method on the Service passing the parent object, the name of the navigation property, and the child object. Like all save operations, you need to call +save_changes+ to persist the changes.
80
-
81
- svc.add_link(<Parent>, <Navigation Property Name>, <Child>)
82
- svc.save_changes
83
-
84
- === Querying
85
- Querying is easy, for example to pull all the categories from the SampleService, you simply can run:
86
-
87
- require 'ruby_odata'
88
-
89
- svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc"
90
- svc.Categories
91
- categories = svc.execute
92
- puts categories.to_json
93
-
94
- You can also expand, add filters, order, skip records, and take only the top X records to the query before executing it. For example:
95
-
96
- === Expanding
97
- Expanding allows you to eagerly load other objects that are children of the root.
98
- You can use more than one expand on a query.
99
- For expanding grandchild and lower entities, you must pass in the full path from the root, for example <tt>Products.expand('Orders').expand('Orders/LineItems')</tt>
100
-
101
- # Without expanding the query
102
- svc.Products(1)
103
- prod1 = svc.execute
104
- puts "Without expanding the query"
105
- puts "#{prod1.to_json}\n"
106
-
107
- # With expanding the query
108
- svc.Products(1).expand('Category')
109
- prod1 = svc.execute
110
- puts "With expanding the query"
111
- puts "#{prod1.to_json}\n"
112
-
113
- === Lazy Loading
114
- If you want to implement lazy loading, the ruby_odata `Service` allows you to perform this. You simply need to call the `load_property` method on the `Service` passing in the object and the navigation property to fill.
115
-
116
- # Without expanding the query
117
- svc.Products(1)
118
- prod1 = svc.execute.first
119
- puts "#{prod1.to_json}\n"
120
-
121
- # Use load_property for lazy loading
122
- svc.load_property(prod1, "Category")
123
- puts "#{prod1.to_json}\n"
124
-
125
- === Filtering
126
- The syntax for filtering can be found on the {OData Protocol URI Conventions}[http://www.odata.org/developers/protocols/uri-conventions#FilterSystemQueryOption] page.
127
- You can use more than one filter, if you call the filter method multiple times it will before an AND.
128
-
129
- # You can access by ID (but that isn't is a filter)
130
- # The syntax is just svc.ENTITYNAME(ID) which is shown in the expanding examples above
131
-
132
- svc.Products.filter("Name eq 'Product 2'")
133
- prod = svc.execute
134
- puts "Filtering on Name eq 'Product 2'"
135
- puts "#{prod.to_json}"
136
-
137
- Note you can pass more than one filter in the string, for example (querying Netflix):
138
-
139
- svc.Titles.filter("Rating eq 'PG' and ReleaseYear eq 1980")
140
-
141
- Filters can also be chained, by doing this you will create an "and" filter (just like the last example) when it is passed to the server.
142
-
143
- svc.Titles.filter("Rating eq 'PG'").filter("ReleaseYear eq 1980")
144
-
145
-
146
- === Combining Expanding and Filtering
147
- The query operations follow a {fluent interface}[http://en.wikipedia.org/wiki/Fluent_interface], although they can be added by themselves as well as chained
148
-
149
- svc.Products.filter("Name eq 'Product 2'").expand("Category")
150
- prod = svc.execute
151
- puts "Filtering on Name eq 'Product 2' and expanding"
152
- puts "#{prod.to_json}"
153
-
154
- === Order By
155
- You can order the results by properties of your choice, either ascending or descending.
156
- Order by are similar to +expands+ in that you can use more than one of them on a query.
157
- For expanding grandchild and lower entities, you must pass in the full path from the root like would do on an +expand+
158
-
159
- svc.Products.order_by("Name")
160
- products = svc.execute
161
-
162
- # Specifically requesting descending
163
- svc.Products.order_by("Name desc")
164
- products = svc.execute
165
-
166
- # Specifically requesting ascending
167
- svc.Products.order_by("Name asc")
168
- products = svc.execute
169
-
170
- Like the fiter method, order_by statements can also be chained like so:
171
-
172
- svc.Products.order_by("Name asc").order_by("Price desc")
173
-
174
-
175
- === Skip
176
- Skip allows you to skip a number of records when querying. This is often used for paging along with +top+.
177
-
178
- svc.Products.skip(5)
179
- products = svc.execute # => skips the first 5 items
180
-
181
- === Top
182
- Top allows you only retrieve the top X number of records when querying. This is often used for paging along with +skip+.
183
-
184
- svc.Products.top(5)
185
- products = svc.execute # => returns only the first 5 items
186
-
187
- === Navigation Property Links Only Query
188
- OData allows you to {query navigation properties and only return the links for the entities}[http://www.odata.org/developers/protocols/uri-conventions#AddressingLinksBetweenEntries] (instead of the data)
189
- svc.Categories(1).links("Products")
190
- product_links = svc.execute # => returns URIs for the products under the Category with an ID of 1
191
-
192
- === Partial feeds
193
- OData allows services to do server-side paging in Atom by defining a next link. The default behavior is to repeatedly consume partial feeds until the result set is complete.
194
-
195
- svc.Partials
196
- results = svc.execute # => retrieves all results in the Partials collection
197
-
198
- If desired (e.g., because the result set is too large to fit in memory), explicit traversal of partial results can be requested via options:
199
-
200
- svc = OData::Service.new "http://example.com/Example.svc", { :eager_partial => false }
201
- svc.Partials
202
- results = svc.execute # => retrieves the first set of results returned by the server
203
- if svc.partial? # => true if the last result set was a partial result set (i.e., had a next link)
204
- results.concat svc.next # => retrieves the next set of results
205
- end
206
- while svc.partial? # => to retrieve all partial result sets
207
- results.concat svc.next
208
- end
209
-
210
- === Authentication
211
- Basic HTTP Authentication is supported via sending a username and password as service constructor arguments:
212
-
213
- require 'ruby_odata'
214
-
215
- svc = OData::Service.new "http://127.0.0.1:8989/SampleService/RubyOData.svc", { :username => "bob", :password=> "12345" }
216
-
217
- === SSL/https Certificate Verification
218
- The certificate verification mode can be passed in the options hash via the :verify_ssl key. For example, to ignore verification in order to use a self-signed certificate:
219
-
220
- require 'ruby_odata'
221
-
222
- svc = OData::Service.new "https://127.0.0.1:44300/SampleService/RubyOData.svc", { :verify_ssl => false }
223
-
224
- Or an OpenSSL integer constant can be passed as well:
225
-
226
- require 'ruby_odata'
227
-
228
- svc = OData::Service.new "https://127.0.0.1:44300/SampleService/RubyOData.svc", { :verify_ssl => OpenSSL::SSL::VERIFY_PEER }
229
-
230
- Default verification is OpenSSL::SSL::VERIFY_PEER. Note due to the way Ruby's Request object implements certificate checking, you CAN NOT pass OpenSSL::SSL::VERIFY_NONE, you must instead pass a boolean false.
231
-
232
- == Function Imports / Custom Service Methods
233
- Function Imports are custom service methods exposed by the WCF Data Service. Each function import will be created as a method on the ruby_odata Service. When you make a call to one of these, they return a result immediately without the need to call +execute+ or +save_changes+.
234
-
235
- == Reflection
236
- Instead of relying on looking at the EDMX directly, ruby_odata allows you to perform basic reflection on objects
237
- === Service Level Methods
238
- * *Collections* - You can look at the collections exposed by a service by accessing the +collections+ method, which is a hash. The key is the name of the collection and the value is the hash with +edmx_type+, which returns the name of the type from the EDMX and <tt>:type</tt>, which is the local type that is created for you
239
- * *Classes* - To see the generated classes, you can utilize the +classes+ method on the service. The return result is a hash where the key is the class name and the value is the class type.
240
- * <b>Function Imports</b> - You can find any function import (custom service methods) exposed by the service by accessing the +function_imports+ method. This is a hash where the key is the Function Import name and the value is metadata about the Function Import.
241
-
242
- === Class Level Methods
243
- * *Properties* - You can call the class method +properties+ on a generated class to see the method (properties) that were created. The returned result is a hash where the key is the property name and the value is metadata for the property like if it is nullable, the EDM Type, etc.
244
-
245
- == Tests
246
- All of the tests are written using Cucumber going against a sample service (Found in test/RubyODataService/RubyODataService/*).
247
- The SampleService is an ASP.NET Web Site running a SQL Compact 4 Database, which gets generated at runtime, as well as the ADO.NET Entity Framework 4.1 and WCF Data Services October 2011 CTP. The reason for the CTP is that WCF Data Services currently shipping with .NET 4 doesn't support Entity Framework 4.1's "Code First" approach (e.g. no EDMX, all POCOs)
248
- In order to run the tests, you need to spin up IIS running a virtual directory of SampleService on port 8989 (http://localhost:8989/SampleService) and another instance running on port 44300.
249
-
250
- *NOTE* The ports (8989 and 44300) and webserver (localhost by default) here are customizable thanks to <tt>/features/contants.rb</tt>. Take a look in there for the corresponding environment variables that you can set.
251
-
252
- The SampleService requires IIS or IIS Express. IIS Express is a free download from Microsoft and the preferred approach to running the application. Once installed, there is a batch file found in /test called "iisExpress x64.bat" that will spin up the appropriate instances needed for the Cucumber tests. There is a also an "iisExpress x86.bat" file for those of you running a 32-bit machine. The only difference is the path to the Program Files directory. Once you run the batch file, the web server will spin up. To stop the server, use 'Q' and then enter or close the command window.
253
-
254
- If you are testing on a Windows machine, you may encounter a problem with using Cucumber and Ruby 1.9.2. You will get a message when you fire up cucumber about missing msvcrt-ruby18.dll. The fix for this is to make sure you have the {RubyInstaller DevKit}[https://github.com/oneclick/rubyinstaller/wiki/Development-Kit] installed, then do the following:
255
- gem uninstall json
256
- gem install json --platform=ruby -v 1.4.6
257
-
258
- Once the SampleService is running, from the BASE ruby_odata directory, simply type +rake+, which will run the RSpec and Cucumber specs. You can also run them separately <tt>rake spec</tt> for RSpec and <tt>rake features</tt> for Cucumber.
259
-