ruby_odata 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,13 +1,22 @@
1
1
  = ruby_odata Change Log
2
2
 
3
3
  === 0.0.1
4
- * Basic CRUD Operations
5
- * Query: Filters
6
- * Query: Expands
4
+ * New Features
5
+ * Basic CRUD Operations
6
+ * Query Enhancement: Filters
7
+ * Query Enhancement: Expands
7
8
 
8
9
  === 0.0.2
9
- * Query: Order By
10
+ * New Features
11
+ * Query Enhancement: Order By (both desc and asc)
10
12
 
11
13
  === 0.0.3
12
- * Rearranged code to match the gem name. Things were mismatched between odata_ruby and ruby_odata.
14
+ * Bug Fixes
15
+ * Rearranged code to match the gem name. Things were mismatched between odata_ruby and ruby_odata.
13
16
 
17
+ === 0.0.4
18
+ * New Features
19
+ * Query Enhancement: skip
20
+ * Query Enhancement: top
21
+ * Ability to perform paging using skip and top together
22
+ * Updated README with examples for order_by, skip, and top
@@ -1,3 +1,4 @@
1
+ Error: The word "DATABASE SETUP - DO THIS FIRST*" is invalid. The character ' ' (U+20) may not appear in the middle of a word.
1
2
  = ruby_odata
2
3
 
3
4
  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.
@@ -60,9 +61,12 @@ Querying is easy, for example to pull all the categories from the SampleService,
60
61
  categories = svc.execute
61
62
  puts categories.to_json
62
63
 
63
- You can also expand and add filters to the query before executing it. For example:
64
+ You can also expand, add filters, order, skip records, and take only the top X records to the query before executing it. For example:
64
65
 
65
66
  === Expanding
67
+ Expanding allows you to eagerly load other objects that are children of the root.
68
+ You can use more than one expand on a query.
69
+ For expanding grandchild and lower entities, you must pass in the full path from the root, for example +Products.expand('Orders').expand('Orders/LineItems')+
66
70
 
67
71
  # Without expanding the query
68
72
  svc.Products(1)
@@ -78,6 +82,8 @@ You can also expand and add filters to the query before executing it. For examp
78
82
 
79
83
 
80
84
  === Filtering
85
+ The syntax for filtering can be found on the {OData Protocol URI Conventions}[http://www.odata.org/developers/protocols/uri-conventions#FilterSystemQueryOption] page.
86
+ You can use more than one filter, if you call the filter method multiple times it will before an AND.
81
87
 
82
88
  # You can access by ID (but that isn't is a filter)
83
89
  # The syntax is just svc.ENTITYNAME(ID) which is shown in the expanding examples above
@@ -88,17 +94,44 @@ You can also expand and add filters to the query before executing it. For examp
88
94
  puts "#{prod.to_json}"
89
95
 
90
96
  === Combining Expanding and Filtering
97
+ 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
91
98
 
92
99
  svc.Products.filter("Name eq 'Product 2'").expand("Category")
93
100
  prod = svc.execute
94
101
  puts "Filtering on Name eq 'Product 2' and expanding"
95
102
  puts "#{prod.to_json}"
96
103
 
104
+ === Order By
105
+ You can order the results by properties of your choice, either ascending or descending.
106
+ Order by are similar to +expand+s in that you can use more than one of them on a query.
107
+ For expanding grandchild and lower entities, you must pass in the full path from the root like would do on an +expand+
97
108
 
109
+ svc.Products.order_by("Name")
110
+ products = svc.execute
111
+
112
+ # Specifically requesting descending
113
+ svc.Products.order_by("Name desc")
114
+ products = svc.execute
115
+
116
+ # Specifically requesting ascending
117
+ svc.Products.order_by("Name asc")
118
+ products = svc.execute
119
+
120
+ === Skip
121
+ Skip allows you to skip a number of records when querying. This is often used for paging along with +top+.
122
+
123
+ svc.Products.skip(5)
124
+ products = svc.execute # => skips the first 5 items
125
+
126
+ === Top
127
+ Top allows you only retrieve the top X number of records when querying. This is often used for paging along with +skip+.
128
+
129
+ svc.Products.top(5)
130
+ products = svc.execute # => returns only the first 5 items
98
131
 
99
132
  == Tests
100
133
  *DATABASE SETUP - DO THIS FIRST*
101
- Within /test/SampleService/App_Data/ rename _TestDB*.* to TestDB*.*. This file is just the inital database, and needs to be renamed so that unwanted changes to that DB aren't persisted in source control.
134
+ Within /test/SampleService/App_Data/ rename _TestDB*.* to TestDB*.*. This file is just the initial database, and needs to be renamed so that unwanted changes to that DB aren't persisted in source control.
102
135
 
103
136
  All of the tests are written using Cucumber going against a sample service (Found in /test/SampleService/*). The SampleService is an ASP.NET Web Site running a SQLEXPRESS 2008 R2 Database (TestDB), as well as the ADO.NET Entity Framework and a WCF Data Service. In order to run the tests, you need to spin up the SampleService and have it running on port 8888 (http://localhost:8888/SampleService).
104
137
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.4
@@ -21,8 +21,9 @@ Scenario: Navigation Properties should be able to be eager loaded
21
21
  And the method "Id" on the result's method "Category" should equal: "1"
22
22
 
23
23
 
24
- # Filter
24
+ # Filters
25
25
  Scenario: Filters should be allowed on the root level entity
26
+ # Filter
26
27
  Given I call "AddToProducts" on the service with a new "Product" object with Name: "Test Product"
27
28
  When I save changes
28
29
  When I call "Products" on the service
@@ -90,6 +91,62 @@ Scenario: Order by should access sorting acsending
90
91
  | Product 5 |
91
92
 
92
93
 
94
+ # Skip
95
+ Scenario: Skip should be allowed on the root level entity
96
+ Given the following Products exist:
97
+ | Name |
98
+ | Product 1 |
99
+ | Product 2 |
100
+ | Product 3 |
101
+ | Product 4 |
102
+ | Product 5 |
103
+ When I call "Products" on the service
104
+ And I skip 3
105
+ And I run the query
106
+ Then the result should be:
107
+ | Name |
108
+ | Product 4 |
109
+ | Product 5 |
110
+
111
+
112
+ # Top
113
+ Scenario: Top should be allowed on the root level entity
114
+ Given the following Products exist:
115
+ | Name |
116
+ | Product 1 |
117
+ | Product 2 |
118
+ | Product 3 |
119
+ | Product 4 |
120
+ | Product 5 |
121
+ When I call "Products" on the service
122
+ And I ask for the top 3
123
+ And I run the query
124
+ Then the result should be:
125
+ | Name |
126
+ | Product 1 |
127
+ | Product 2 |
128
+ | Product 3 |
129
+
130
+ Scenario: Top should be able to be used along with skip for paging
131
+ Given the following Products exist:
132
+ | Name |
133
+ | Product 1 |
134
+ | Product 2 |
135
+ | Product 3 |
136
+ | Product 4 |
137
+ | Product 5 |
138
+ | Product 6 |
139
+ When I call "Products" on the service
140
+ And I skip 2
141
+ And I ask for the top 2
142
+ And I run the query
143
+ Then the result should be:
144
+ | Name |
145
+ | Product 3 |
146
+ | Product 4 |
147
+
148
+
149
+
93
150
 
94
151
 
95
152
 
@@ -62,6 +62,13 @@ When /^I order by: "([^\"]*)"$/ do |order|
62
62
  @service_query.order_by(order)
63
63
  end
64
64
 
65
+ When /^I skip (\d+)$/ do |skip|
66
+ @service_query.skip(skip)
67
+ end
68
+
69
+ When /^I ask for the top (\d+)$/ do |top|
70
+ @service_query.top(top)
71
+ end
65
72
 
66
73
  Then /^the method "([^\"]*)" on the result should be of type "([^\"]*)"$/ do |method, type|
67
74
  result = @service_result.send(method.to_sym)
@@ -15,6 +15,8 @@ class QueryBuilder
15
15
  @expands = []
16
16
  @filters = []
17
17
  @order_bys = []
18
+ @skip = nil
19
+ @top = nil
18
20
  end
19
21
 
20
22
  # Used to eagerly-load data for nested objects, for example, obtaining a Category for a Product within one call to the server
@@ -36,7 +38,7 @@ class QueryBuilder
36
38
 
37
39
  # Used to filter data being returned
38
40
  # ==== Required Attributes
39
- # - filter: The path of the entity to expand relative to the root
41
+ # - filter: The conditions to apply to the query
40
42
  #
41
43
  # ==== Example
42
44
  # svc.Products.filter("Name eq 'Product 2'")
@@ -58,6 +60,32 @@ class QueryBuilder
58
60
  self
59
61
  end
60
62
 
63
+ # Used to skip a number of records
64
+ # This is typically used for paging, where it would be used along with the +top+ method.
65
+ # ==== Required Attributes
66
+ # - num: The number of items to skip
67
+ #
68
+ # ==== Example
69
+ # svc.Products.skip(5)
70
+ # products = svc.execute # => skips the first 5 items
71
+ def skip(num)
72
+ @skip = num
73
+ self
74
+ end
75
+
76
+ # Used to take only the top X records
77
+ # This is typically used for paging, where it would be used along with the +skip+ method.
78
+ # ==== Required Attributes
79
+ # - num: The number of items to return
80
+ #
81
+ # ==== Example
82
+ # svc.Products.top(5)
83
+ # products = svc.execute # => returns only the first 5 items
84
+ def top(num)
85
+ @top = num
86
+ self
87
+ end
88
+
61
89
  # Builds the query URI (path, not including root) incorporating expands, filters, etc.
62
90
  # This is used internally when the execute method is called on the service
63
91
  def query
@@ -66,6 +94,8 @@ class QueryBuilder
66
94
  query_options << "$expand=#{@expands.join(',')}" unless @expands.empty?
67
95
  query_options << "$filter=#{@filters.join('+and+')}" unless @filters.empty?
68
96
  query_options << "$orderby=#{@order_bys.join(',')}" unless @order_bys.empty?
97
+ query_options << "$skip=#{@skip}" unless @skip.nil?
98
+ query_options << "$top=#{@top}" unless @top.nil?
69
99
  if !query_options.empty?
70
100
  q << "?"
71
101
  q << query_options.join('&')
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruby_odata}
8
- s.version = "0.0.3"
8
+ s.version = "0.0.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Damien White"]
@@ -1,7 +1,7 @@
1
1
  Sham.define do
2
- category_name { |i| "Category #{i}" }
3
- product_name { |i| "Widget #{i}" }
4
- price { ['5.00', '10.00', '20.00', '15.00' , '25.00', '7.50'].rand }
2
+ category_name { |i| "Category #{i}" }
3
+ product_name { |i| "Widget #{i}" }
4
+ price(:unique => false) { ['5.00', '10.00', '20.00', '15.00' , '25.00', '7.50'].rand }
5
5
  end
6
6
 
7
7
  Product.blueprint do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_odata
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 3
10
- version: 0.0.3
9
+ - 4
10
+ version: 0.0.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Damien White