Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added the ability to perform a basic count (and cleaned up single quo…

…tes/spaces)
  • Loading branch information...
commit 0068bd5a6be22bc48e7945ba407cc05b1cae002b 1 parent 523de8c
@visoft authored
View
28 features/query_builder.feature
@@ -1,7 +1,7 @@
Feature: Query Builder
In order to query OData services
As a user
- I want to be able to perform valid OData protocol operations
+ I want to be able to perform valid OData protocol operations
Background:
Given a HTTP ODataService exists
@@ -12,7 +12,7 @@ Scenario: Navigation Properties should be able to be eager loaded
Given I call "AddToCategories" on the service with a new "Category" object with Name: "Test Category"
And I save changes
And I call "AddToProducts" on the service with a new "Product" object with Category: "@@LastSave.first"
- And I save changes
+ And I save changes
And I call "Products" on the service with args: "1"
And I expand the query to include "Category"
When I run the query
@@ -99,14 +99,14 @@ Scenario: Skip should be allowed on the root level entity
| Product 2 |
| Product 3 |
| Product 4 |
- | Product 5 |
+ | Product 5 |
When I call "Products" on the service
And I skip 3
And I run the query
Then the result should be:
| Name |
| Product 4 |
- | Product 5 |
+ | Product 5 |
# Top
@@ -117,14 +117,14 @@ Scenario: Top should be allowed on the root level entity
| Product 2 |
| Product 3 |
| Product 4 |
- | Product 5 |
+ | Product 5 |
When I call "Products" on the service
And I ask for the top 3
And I run the query
Then the result should be:
| Name |
| Product 1 |
- | Product 2 |
+ | Product 2 |
| Product 3 |
Scenario: Top should be able to be used along with skip for paging
@@ -134,8 +134,8 @@ Scenario: Top should be able to be used along with skip for paging
| Product 2 |
| Product 3 |
| Product 4 |
- | Product 5 |
- | Product 6 |
+ | Product 5 |
+ | Product 6 |
When I call "Products" on the service
And I skip 2
And I ask for the top 2
@@ -143,7 +143,7 @@ Scenario: Top should be able to be used along with skip for paging
Then the result should be:
| Name |
| Product 3 |
- | Product 4 |
+ | Product 4 |
# Links
@@ -160,3 +160,13 @@ Scenario: Navigation Properties should be able to represented as links
And I run the query
Then the result count should be 3
Then the method "path" on the first result should equal: "/SampleService/RubyOData.svc/Products(1)"
+
+# Count
+Scenario: Count should be able to be used on a root collection
+ Given 4 products exist
+ When I call "Products" on the service
+ And I ask for the count
+ And I run the query
+ Then the integer result should be 4
+
+
View
4 features/step_definitions/service_steps.rb
@@ -122,6 +122,10 @@
@service_query.top(top)
end
+When /^I ask for the count$/ do
+ @service_query.count
+end
+
When /^I ask for the links for "([^\"]*)"$/ do |nav_prop|
@service_query.links(nav_prop)
end
View
1  lib/ruby_odata.rb
@@ -13,6 +13,7 @@
require "bigdecimal/util"
require "backports"
+require lib + "/ruby_odata/exceptions"
require lib + "/ruby_odata/association"
require lib + "/ruby_odata/property_metadata"
require lib + "/ruby_odata/query_builder"
View
3  lib/ruby_odata/exceptions.rb
@@ -0,0 +1,3 @@
+module OData
+ class NotSupportedError < StandardError; end
+end
View
19 lib/ruby_odata/query_builder.rb
@@ -19,7 +19,7 @@ def initialize(root, additional_params = {})
@order_bys = []
@skip = nil
@top = nil
- @links = nil
+ @count = nil
@additional_params = additional_params
end
@@ -98,10 +98,22 @@ def top(num)
# svc.Categories(1).links("Products")
# product_links = svc.execute # => returns URIs for the products under the Category with an ID of 1
def links(navigation_property)
+ raise OData::NotSupportedError.new("You cannot call both the `links` method and the `count` method in the same query.") if @count
@navigation_property = navigation_property
self
end
+ # Used to return a count of objects instead of the objects themselves
+ # ==== Example
+ # svc.Products
+ # svc.count
+ # product_count = svc.execute
+ def count
+ raise OData::NotSupportedError.new("You cannot call both the `links` method and the `count` method in the same query.") if @navigation_property
+ @count = true
+ self
+ end
+
# Builds the query URI (path, not including root) incorporating expands, filters, etc.
# This is used internally when the execute method is called on the service
def query
@@ -112,6 +124,11 @@ def query
q << "/$links/#{@navigation_property}"
end
+ # Handle count queries, this isn't just a standard query option
+ if @count
+ q << "/$count"
+ end
+
query_options = []
query_options << "$expand=#{@expands.join(',')}" unless @expands.empty?
query_options << "$filter=#{@filters.join('+and+')}" unless @filters.empty?
View
4 lib/ruby_odata/service.rb
@@ -96,9 +96,11 @@ def save_changes
end
end
- # Performs query operations (Read) against the server, returns an array of record instances.
+ # Performs query operations (Read) against the server.
+ # Typically this returns an array of record instances, except in the case of count queries
def execute
result = RestClient::Resource.new(build_query_uri, @rest_options).get
+ return Integer(result) if result =~ /^\d+$/
handle_collection_result(result)
end
View
43 spec/query_builder_spec.rb
@@ -1,34 +1,55 @@
-require 'spec_helper'
+require "spec_helper"
module OData
describe QueryBuilder do
describe "#initialize" do
- it "handles additional parameters" do
- builder = QueryBuilder.new 'Products', { :x=>1, :y=>2 }
+ it "handles additional parameters" do
+ builder = QueryBuilder.new "Products", { :x=>1, :y=>2 }
builder.query.should eq "Products?x=1&y=2"
end
- it "handles empty additional parameters" do
- builder = QueryBuilder.new 'Products'
+ it "handles empty additional parameters" do
+ builder = QueryBuilder.new "Products"
builder.query.should eq "Products"
- end
+ end
end
describe "#query" do
it "should append additional parameters to the end" do
- builder = QueryBuilder.new 'Products', { :x=>1, :y=>2 }
+ builder = QueryBuilder.new "Products", { :x=>1, :y=>2 }
builder.top(10)
builder.query.should eq "Products?$top=10&x=1&y=2"
end
it "should properly handle queries for links" do
- builder = QueryBuilder.new 'Categories(1)'
- builder.links('Products')
+ builder = QueryBuilder.new "Categories(1)"
+ builder.links("Products")
builder.query.should eq "Categories(1)/$links/Products"
end
it "should properly handle queries for links with additional operations" do
- builder = QueryBuilder.new 'Categories(1)'
- builder.links('Products')
+ builder = QueryBuilder.new "Categories(1)"
+ builder.links("Products")
builder.top(5)
builder.query.should eq "Categories(1)/$links/Products?$top=5"
end
+ it "should throw an execption if count was already called on the builder" do
+ builder = QueryBuilder.new "Categories(1)"
+ builder.count
+ lambda { builder.links("Products") }.should raise_error(OData::NotSupportedError, "You cannot call both the `links` method and the `count` method in the same query.")
+ end
+ context "count" do
+ it "should accept the count method" do
+ builder = QueryBuilder.new "Products"
+ lambda { builder.count }.should_not raise_error
+ end
+ it "should properly handle the count method" do
+ builder = QueryBuilder.new "Products"
+ builder.count
+ builder.query.should eq "Products/$count"
+ end
+ it "should throw an execption if links was already called on the builder" do
+ builder = QueryBuilder.new "Categories(1)"
+ builder.links("Products")
+ lambda { builder.count }.should raise_error(OData::NotSupportedError, "You cannot call both the `links` method and the `count` method in the same query.")
+ end
+ end
end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.