odata-model 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/lib/odata/model/query.rb +39 -4
- data/lib/odata/model/query_proxy.rb +88 -0
- data/lib/odata/model/version.rb +1 -1
- data/lib/odata/model.rb +1 -2
- data/odata-model.gemspec +2 -2
- data/spec/model/query_interface_spec.rb +23 -6
- data/spec/model/query_proxy_spec.rb +117 -0
- data/spec/spec_helper.rb +1 -1
- metadata +10 -17
- data/lib/odata/query/builder.rb +0 -219
- data/spec/query/builder/filters_spec.rb +0 -41
- data/spec/query/builder/order_by_spec.rb +0 -22
- data/spec/query/builder/pagination_spec.rb +0 -19
- data/spec/query/builder/select_spec.rb +0 -12
- data/spec/query/builder_spec.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0653979dfb88ea7148ac214b771b1133922e63bd
|
4
|
+
data.tar.gz: 12e5004a1054dc4645ef2a4b8a7e779eda35a000
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23e898b61aec37dafb51611b3e8778d0eb449783c0e5820786ac8e5d41ae3939a454963267f369399ad6932b93c2e692f129a8c45f99607df788d304d9785333
|
7
|
+
data.tar.gz: 4ebcf488bac36ae7c4fb17c8531bec5f77530c53f1ddc80c541e237426b838a3a5f1b6c814caf6f48b5835e0a264dfd99f366aa7845a32dd0a2bf6fb8e994add
|
data/CHANGELOG.md
ADDED
data/lib/odata/model/query.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module OData
|
2
2
|
module Model
|
3
|
+
# Provides the methods that make up the query interface for OData::Model.
|
3
4
|
module Query
|
4
5
|
extend ActiveSupport::Concern
|
5
6
|
|
@@ -9,10 +10,44 @@ module OData
|
|
9
10
|
|
10
11
|
# Methods mixed in at the class level.
|
11
12
|
module ClassMethods
|
12
|
-
# Starts a chain for
|
13
|
-
# @
|
14
|
-
|
15
|
-
|
13
|
+
# Starts a query chain with a filter for a given property's name.
|
14
|
+
# @param property_name [to_sym]
|
15
|
+
# @return [OData::Model::Query]
|
16
|
+
def where(property_name)
|
17
|
+
query_proxy = OData::Model::QueryProxy.new(self)
|
18
|
+
query_proxy.where(property_name.to_sym)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Starts a query chain with a limit to entities returned.
|
22
|
+
# @param value [to_i]
|
23
|
+
# @return [OData::Model::Query]
|
24
|
+
def limit(value)
|
25
|
+
query_proxy = OData::Model::QueryProxy.new(self)
|
26
|
+
query_proxy.limit(value.to_i)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Starts a query chain with the number of entities to skip.
|
30
|
+
# @param value [to_i]
|
31
|
+
# @return [OData::Model::Query]
|
32
|
+
def skip(value)
|
33
|
+
query_proxy = OData::Model::QueryProxy.new(self)
|
34
|
+
query_proxy.skip(value.to_i)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Starts a query chain with a order operator for a given property's name.
|
38
|
+
# @param property_name [to_sym]
|
39
|
+
# @return [OData::Model::Query]
|
40
|
+
def order_by(property_name)
|
41
|
+
query_proxy = OData::Model::QueryProxy.new(self)
|
42
|
+
query_proxy.order_by(property_name.to_sym)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Starts a query chain with a list of properties to select.
|
46
|
+
# @param property_name [to_sym]
|
47
|
+
# @return [OData::Model::Query]
|
48
|
+
def select(property_name)
|
49
|
+
query_proxy = OData::Model::QueryProxy.new(self)
|
50
|
+
query_proxy.select(property_name.to_sym)
|
16
51
|
end
|
17
52
|
|
18
53
|
# Enables lookup of model entities by their primary key.
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module OData
|
2
|
+
module Model
|
3
|
+
# Provides the proxy between OData::Query and OData::Model.
|
4
|
+
class QueryProxy
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
# Last filter criteria set on the query.
|
8
|
+
attr_reader :last_criteria
|
9
|
+
|
10
|
+
# Instantiates a new QueryProxy for the supplied OData::Model class.
|
11
|
+
# @param model_class [Class]
|
12
|
+
# @api private
|
13
|
+
def initialize(model_class)
|
14
|
+
@target = model_class
|
15
|
+
@query = target.odata_entity_set.query
|
16
|
+
@last_criteria = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# Sets up a new criteria for filters for the given property name.
|
20
|
+
# @param property_name [Symbol]
|
21
|
+
# @return [self]
|
22
|
+
# @api private
|
23
|
+
def where(property_name)
|
24
|
+
@last_criteria = query[target.property_map[property_name]]
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
# Sets up last criteria with supplied argument sets.
|
29
|
+
# @param arguments [Hash]
|
30
|
+
# @return [self]
|
31
|
+
def is(arguments)
|
32
|
+
raise ArgumentError 'can only accept Hash argument' unless arguments.is_a?(Hash)
|
33
|
+
property_name = last_criteria.property
|
34
|
+
arguments.each do |operator, value|
|
35
|
+
@last_criteria = query[property_name].send(operator.to_sym, value)
|
36
|
+
query.where(@last_criteria)
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# Specifies the limit for the query.
|
42
|
+
# @param value [to_i]
|
43
|
+
# @return [self]
|
44
|
+
def limit(value)
|
45
|
+
query.limit(value.to_i)
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
# Specifies the number of entities to skip for the query.
|
50
|
+
# @param value [to_i]
|
51
|
+
# @return [self]
|
52
|
+
def skip(value)
|
53
|
+
query.skip(value.to_i)
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
# Specified the ordering for the query.
|
58
|
+
# @param property_name [to_sym]
|
59
|
+
# @return [self]
|
60
|
+
def order_by(property_name)
|
61
|
+
query.order_by(target.property_map[property_name.to_sym])
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
# Selects specific properties to return with query.
|
66
|
+
# @param property_name [to_sym]
|
67
|
+
# @return [self]
|
68
|
+
def select(property_name)
|
69
|
+
query.select(target.property_map[property_name.to_sym])
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
# Executes the query and returns each instance of the target model in
|
74
|
+
# turn.
|
75
|
+
def each(&block)
|
76
|
+
query.execute.each do |entity|
|
77
|
+
model = target.new
|
78
|
+
model.instance_variable_set(:@odata_entity, entity)
|
79
|
+
block_given? ? block.call(model) : yield(model)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
attr_reader :target, :query
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/odata/model/version.rb
CHANGED
data/lib/odata/model.rb
CHANGED
@@ -4,14 +4,13 @@ require 'active_support/concern'
|
|
4
4
|
|
5
5
|
require 'odata'
|
6
6
|
|
7
|
-
require 'odata/query/builder'
|
8
|
-
|
9
7
|
require 'odata/model/version'
|
10
8
|
require 'odata/model/active_model'
|
11
9
|
require 'odata/model/configuration'
|
12
10
|
require 'odata/model/attributes'
|
13
11
|
require 'odata/model/persistence'
|
14
12
|
require 'odata/model/query'
|
13
|
+
require 'odata/model/query_proxy'
|
15
14
|
|
16
15
|
# OData is the parent namespace for the OData::Model project.
|
17
16
|
module OData
|
data/odata-model.gemspec
CHANGED
@@ -20,11 +20,11 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
22
22
|
spec.add_development_dependency 'rake'
|
23
|
-
spec.add_development_dependency 'simplecov', '~> 0.
|
23
|
+
spec.add_development_dependency 'simplecov', '~> 0.9.0'
|
24
24
|
spec.add_development_dependency 'codeclimate-test-reporter'
|
25
25
|
spec.add_development_dependency 'rspec', '~> 3.0.0'
|
26
26
|
|
27
|
-
spec.add_dependency 'odata', '~> 0.
|
27
|
+
spec.add_dependency 'odata', '~> 0.5'
|
28
28
|
spec.add_dependency 'activesupport', '>= 3.0.0'
|
29
29
|
spec.add_dependency 'activemodel', '>= 3.0.0'
|
30
30
|
end
|
@@ -3,18 +3,35 @@ require 'spec_helper'
|
|
3
3
|
describe OData::Model do
|
4
4
|
describe 'query interface' do
|
5
5
|
it { expect(Product).to respond_to(:[]) }
|
6
|
-
it { expect(Product).to respond_to(:find) }
|
7
|
-
|
8
6
|
describe 'Product[]' do
|
9
7
|
it 'finds a model instance' do
|
10
8
|
expect(Product[0]).to be_a(Product)
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
it { expect(Product).to respond_to(:where) }
|
13
|
+
describe 'Product#where' do
|
14
|
+
it { expect(Product.where(:name)).to be_a(OData::Model::QueryProxy) }
|
15
|
+
end
|
16
|
+
|
17
|
+
it { expect(Product).to respond_to(:limit) }
|
18
|
+
describe 'Product#limit' do
|
19
|
+
it { expect(Product.limit(3)).to be_a(OData::Model::QueryProxy) }
|
20
|
+
end
|
21
|
+
|
22
|
+
it { expect(Product).to respond_to(:skip) }
|
23
|
+
describe 'Product#skip' do
|
24
|
+
it { expect(Product.skip(6)).to be_a(OData::Model::QueryProxy) }
|
25
|
+
end
|
26
|
+
|
27
|
+
it { expect(Product).to respond_to(:order_by) }
|
28
|
+
describe 'Product#order_by' do
|
29
|
+
it { expect(Product.order_by(:rating)).to be_a(OData::Model::QueryProxy) }
|
30
|
+
end
|
31
|
+
|
32
|
+
it { expect(Product).to respond_to(:select) }
|
33
|
+
describe 'Product#order_by' do
|
34
|
+
it { expect(Product.select(:name)).to be_a(OData::Model::QueryProxy) }
|
18
35
|
end
|
19
36
|
end
|
20
37
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OData::Model::QueryProxy do
|
4
|
+
let(:subject) { query_proxy }
|
5
|
+
let(:query_proxy) { OData::Model::QueryProxy.new(Product) }
|
6
|
+
let(:query_string) { subject.send(:query).to_s }
|
7
|
+
|
8
|
+
it { expect(subject).to respond_to(:where) }
|
9
|
+
describe '#where' do
|
10
|
+
let(:subject) { query_proxy.where(:name) }
|
11
|
+
|
12
|
+
it { expect(subject).to be_a(OData::Model::QueryProxy) }
|
13
|
+
|
14
|
+
it 'sets up last criteria properly' do
|
15
|
+
expect(subject.last_criteria).to be_a(OData::Query::Criteria)
|
16
|
+
expect(subject.last_criteria.property).to eq(Product.property_map[:name])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it { expect(subject).to respond_to(:is) }
|
21
|
+
describe '#is' do
|
22
|
+
%w{eq ne gt lt ge le}.each do |operator|
|
23
|
+
describe "with :#{operator} operator" do
|
24
|
+
let(:subject) { query_proxy.where(:rating).is(operator.to_sym => 4) }
|
25
|
+
|
26
|
+
it { expect(subject).to be_a(OData::Model::QueryProxy) }
|
27
|
+
|
28
|
+
it 'sets up last criteria properly' do
|
29
|
+
expect(subject.last_criteria).to be_a(OData::Query::Criteria)
|
30
|
+
expect(subject.last_criteria.property).to eq(Product.property_map[:rating])
|
31
|
+
expect(subject.last_criteria.operator).to eq(operator.to_sym)
|
32
|
+
expect(subject.last_criteria.value).to eq(4)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'properly generates query' do
|
36
|
+
expect(query_string).to eq("Products?$filter=Rating #{operator} 4")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it { expect(subject).to respond_to(:limit) }
|
43
|
+
describe '#limit' do
|
44
|
+
let(:subject) { query_proxy.limit(3) }
|
45
|
+
|
46
|
+
it { expect(subject).to be_a(OData::Model::QueryProxy) }
|
47
|
+
|
48
|
+
it 'properly generates query' do
|
49
|
+
expect(query_string).to eq('Products?$top=3')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it { expect(subject).to respond_to(:skip) }
|
54
|
+
describe '#skip' do
|
55
|
+
let(:subject) { query_proxy.skip(6) }
|
56
|
+
|
57
|
+
it { expect(subject).to be_a(OData::Model::QueryProxy) }
|
58
|
+
|
59
|
+
it 'properly generates query' do
|
60
|
+
expect(query_string).to eq('Products?$skip=6')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it { pending; expect(subject).to respond_to(:expand) }
|
65
|
+
describe '#expand' do
|
66
|
+
it { pending; fail }
|
67
|
+
end
|
68
|
+
|
69
|
+
it { expect(subject).to respond_to(:select) }
|
70
|
+
describe '#select' do
|
71
|
+
let(:subject) { query_proxy.select(:name) }
|
72
|
+
|
73
|
+
it { expect(subject).to be_a(OData::Model::QueryProxy) }
|
74
|
+
|
75
|
+
it 'properly generates query' do
|
76
|
+
expect(query_string).to eq('Products?$select=Name')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it { expect(subject).to respond_to(:order_by) }
|
81
|
+
describe '#order_by' do
|
82
|
+
let(:subject) { query_proxy.order_by(:rating) }
|
83
|
+
|
84
|
+
it { expect(subject).to be_a(OData::Model::QueryProxy) }
|
85
|
+
|
86
|
+
it 'properly generates query' do
|
87
|
+
expect(query_string).to eq('Products?$orderby=Rating')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it { pending; expect(subject).to respond_to(:and) }
|
92
|
+
describe '#and' do
|
93
|
+
it { pending; fail }
|
94
|
+
end
|
95
|
+
|
96
|
+
it { pending; expect(subject).to respond_to(:or) }
|
97
|
+
describe '#or' do
|
98
|
+
it { pending; fail }
|
99
|
+
end
|
100
|
+
|
101
|
+
it { pending; expect(subject).to respond_to(:not) }
|
102
|
+
describe '#not' do
|
103
|
+
it { pending; fail }
|
104
|
+
end
|
105
|
+
|
106
|
+
it { expect(subject).to respond_to(:each) }
|
107
|
+
describe '#each' do
|
108
|
+
it 'returns model instances in turn' do
|
109
|
+
counter = 0
|
110
|
+
subject.each do |model|
|
111
|
+
expect(model).to be_a(Product)
|
112
|
+
counter += 1
|
113
|
+
end
|
114
|
+
expect(counter).to eq(11)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -16,7 +16,7 @@ require 'odata/model'
|
|
16
16
|
# Suppressing a deprecation warning
|
17
17
|
I18n.enforce_available_locales = false
|
18
18
|
|
19
|
-
OData::Service.open('http://services.odata.org/OData/OData.svc')
|
19
|
+
OData::Service.open('http://services.odata.org/OData/OData.svc', name: 'ODataDemo')
|
20
20
|
|
21
21
|
require 'example_models/bare_model'
|
22
22
|
require 'example_models/odatademo_product'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: odata-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Thompson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: 0.9.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
54
|
+
version: 0.9.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: codeclimate-test-reporter
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0.
|
89
|
+
version: '0.5'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '0.
|
96
|
+
version: '0.5'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: activesupport
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,6 +133,7 @@ files:
|
|
133
133
|
- ".rspec"
|
134
134
|
- ".ruby-version"
|
135
135
|
- ".travis.yml"
|
136
|
+
- CHANGELOG.md
|
136
137
|
- Gemfile
|
137
138
|
- LICENSE.txt
|
138
139
|
- README.md
|
@@ -143,20 +144,16 @@ files:
|
|
143
144
|
- lib/odata/model/configuration.rb
|
144
145
|
- lib/odata/model/persistence.rb
|
145
146
|
- lib/odata/model/query.rb
|
147
|
+
- lib/odata/model/query_proxy.rb
|
146
148
|
- lib/odata/model/version.rb
|
147
|
-
- lib/odata/query/builder.rb
|
148
149
|
- odata-model.gemspec
|
149
150
|
- spec/example_models/bare_model.rb
|
150
151
|
- spec/example_models/odatademo_product.rb
|
151
152
|
- spec/model/active_model_lint_spec.rb
|
152
153
|
- spec/model/property_defaults_spec.rb
|
153
154
|
- spec/model/query_interface_spec.rb
|
155
|
+
- spec/model/query_proxy_spec.rb
|
154
156
|
- spec/model/service_integration_spec.rb
|
155
|
-
- spec/query/builder/filters_spec.rb
|
156
|
-
- spec/query/builder/order_by_spec.rb
|
157
|
-
- spec/query/builder/pagination_spec.rb
|
158
|
-
- spec/query/builder/select_spec.rb
|
159
|
-
- spec/query/builder_spec.rb
|
160
157
|
- spec/spec_helper.rb
|
161
158
|
homepage: https://github.com/ruby-odata/odata-model
|
162
159
|
licenses:
|
@@ -188,10 +185,6 @@ test_files:
|
|
188
185
|
- spec/model/active_model_lint_spec.rb
|
189
186
|
- spec/model/property_defaults_spec.rb
|
190
187
|
- spec/model/query_interface_spec.rb
|
188
|
+
- spec/model/query_proxy_spec.rb
|
191
189
|
- spec/model/service_integration_spec.rb
|
192
|
-
- spec/query/builder/filters_spec.rb
|
193
|
-
- spec/query/builder/order_by_spec.rb
|
194
|
-
- spec/query/builder/pagination_spec.rb
|
195
|
-
- spec/query/builder/select_spec.rb
|
196
|
-
- spec/query/builder_spec.rb
|
197
190
|
- spec/spec_helper.rb
|
data/lib/odata/query/builder.rb
DELETED
@@ -1,219 +0,0 @@
|
|
1
|
-
module OData
|
2
|
-
class Query
|
3
|
-
# Provides a OData::Model aware means of building up queries using chained
|
4
|
-
# methods. Also implements the Enumerable module to support working with
|
5
|
-
# the results of any query in a sane way.
|
6
|
-
class Builder
|
7
|
-
include Enumerable
|
8
|
-
|
9
|
-
SUPPORTED_OPERATIONS = [:eq, :ne, :gt, :ge, :lt, :le, :not]
|
10
|
-
|
11
|
-
# Sets up a new Query Builder.
|
12
|
-
# @param model [OData::Model] the model to build the query for
|
13
|
-
def initialize(model)
|
14
|
-
@entity_set = model.odata_entity_set
|
15
|
-
@property_map = model.property_map
|
16
|
-
end
|
17
|
-
|
18
|
-
def each
|
19
|
-
# TODO implement
|
20
|
-
end
|
21
|
-
|
22
|
-
# Set the number of entities to skip for the final query.
|
23
|
-
# @param value [to_i,nil]
|
24
|
-
# @return [self]
|
25
|
-
def skip(value)
|
26
|
-
value = nil if value == 0
|
27
|
-
query_structure[:skip] = value.try(:to_i)
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
|
-
# Set the number of entities to return in the final query.
|
32
|
-
# @param value [to_i,nil]
|
33
|
-
# @return [self]
|
34
|
-
def limit(value)
|
35
|
-
value = nil if value == 0
|
36
|
-
query_structure[:top] = value.try(:to_i)
|
37
|
-
self
|
38
|
-
end
|
39
|
-
|
40
|
-
# Set the options for ordering the final query.
|
41
|
-
# @param args [Symbol,Hash]
|
42
|
-
# @return [self]
|
43
|
-
def order_by(*args)
|
44
|
-
validate_order_by_arguments(args)
|
45
|
-
query_structure[:orderby] += process_order_by_arguments(args)
|
46
|
-
self
|
47
|
-
end
|
48
|
-
|
49
|
-
# Set the properties to select with the final query.
|
50
|
-
# @param args [Array<Symbol>]
|
51
|
-
# @return self
|
52
|
-
def select(*args)
|
53
|
-
args.each {|arg| query_structure[:select] << arg.to_sym}
|
54
|
-
self
|
55
|
-
end
|
56
|
-
|
57
|
-
# Sets up a new filter condition on the provided property mapping.
|
58
|
-
# @param value [to_s]
|
59
|
-
# @return self
|
60
|
-
def where(value)
|
61
|
-
last_filter = query_structure[:filter].last
|
62
|
-
clause = {
|
63
|
-
property: lookup_property_name(value),
|
64
|
-
opeartion: nil,
|
65
|
-
argument: nil
|
66
|
-
}
|
67
|
-
|
68
|
-
if last_filter.is_a?(Array)
|
69
|
-
last_filter << clause
|
70
|
-
else
|
71
|
-
query_structure[:filter] << [clause]
|
72
|
-
end
|
73
|
-
self
|
74
|
-
end
|
75
|
-
|
76
|
-
# Sets the operation and argument for the last filter condition started
|
77
|
-
# by #where, #and or #or.
|
78
|
-
# @param value [Hash]
|
79
|
-
# @return self
|
80
|
-
def is(value)
|
81
|
-
value = value.first
|
82
|
-
validate_is_argument(value)
|
83
|
-
last_filter = query_structure[:filter].last.last
|
84
|
-
if last_filter[:operation].nil? && last_filter[:argument].nil?
|
85
|
-
last_filter[:operation] = value[0].to_sym
|
86
|
-
last_filter[:argument] = value[1]
|
87
|
-
else
|
88
|
-
query_structure[:filter].last << {
|
89
|
-
property: last_filter[:property],
|
90
|
-
operation: value[0].to_sym,
|
91
|
-
argument: value[1]
|
92
|
-
}
|
93
|
-
end
|
94
|
-
self
|
95
|
-
end
|
96
|
-
|
97
|
-
# Adds another filter to the last supplied clause.
|
98
|
-
# @param value [to_s]
|
99
|
-
# @return self
|
100
|
-
def and(value)
|
101
|
-
query_structure[:filter].last << {
|
102
|
-
property: lookup_property_name(value),
|
103
|
-
opeartion: nil,
|
104
|
-
argument: nil
|
105
|
-
}
|
106
|
-
self
|
107
|
-
end
|
108
|
-
|
109
|
-
# Adds an alternate filter after the last supplied clause.
|
110
|
-
# @param value [to_s]
|
111
|
-
# @return self
|
112
|
-
def or(value)
|
113
|
-
query_structure[:filter] << [{
|
114
|
-
property: lookup_property_name(value),
|
115
|
-
opeartion: nil,
|
116
|
-
argument: nil
|
117
|
-
}]
|
118
|
-
self
|
119
|
-
end
|
120
|
-
|
121
|
-
# Returns the current query structure as a valid query string.
|
122
|
-
def to_s
|
123
|
-
# TODO validate the actual query structure
|
124
|
-
|
125
|
-
query_array = []
|
126
|
-
query_array << filters_to_query
|
127
|
-
query_array << orderby_to_query
|
128
|
-
query_array << select_to_query
|
129
|
-
query_array << top_to_query
|
130
|
-
query_array << skip_to_query
|
131
|
-
query_array.compact!
|
132
|
-
|
133
|
-
query_string = query_array.join('&')
|
134
|
-
"#{entity_set.name}?#{query_string}"
|
135
|
-
end
|
136
|
-
|
137
|
-
private
|
138
|
-
|
139
|
-
def query_structure
|
140
|
-
@query_structure ||= {
|
141
|
-
top: nil,
|
142
|
-
skip: nil,
|
143
|
-
orderby: [],
|
144
|
-
select: [],
|
145
|
-
filter: []
|
146
|
-
}
|
147
|
-
end
|
148
|
-
|
149
|
-
def entity_set
|
150
|
-
@entity_set
|
151
|
-
end
|
152
|
-
|
153
|
-
def skip_to_query
|
154
|
-
return nil if query_structure[:skip].nil?
|
155
|
-
"$skip=#{query_structure[:skip]}"
|
156
|
-
end
|
157
|
-
|
158
|
-
def top_to_query
|
159
|
-
return nil if query_structure[:top].nil?
|
160
|
-
"$top=#{query_structure[:top]}"
|
161
|
-
end
|
162
|
-
|
163
|
-
def orderby_to_query
|
164
|
-
return nil if query_structure[:orderby].empty?
|
165
|
-
"$orderby=#{query_structure[:orderby].join(',')}"
|
166
|
-
end
|
167
|
-
|
168
|
-
def select_to_query
|
169
|
-
return nil if query_structure[:select].empty?
|
170
|
-
"$select=#{query_structure[:select].join(',')}"
|
171
|
-
end
|
172
|
-
|
173
|
-
def filters_to_query
|
174
|
-
str = "$filter="
|
175
|
-
clauses = []
|
176
|
-
query_structure[:filter].each do |clause|
|
177
|
-
clause_filters = []
|
178
|
-
clause.each do |filter|
|
179
|
-
clause_filters << "#{filter[:property]} #{filter[:operation]} #{filter[:argument]}"
|
180
|
-
end
|
181
|
-
clauses << clause_filters.join(' and ')
|
182
|
-
end
|
183
|
-
clauses.collect! {|clause| "(#{clause})"}
|
184
|
-
str << clauses.join(' or ')
|
185
|
-
str
|
186
|
-
end
|
187
|
-
|
188
|
-
def validate_order_by_arguments(args)
|
189
|
-
args.each do |arg|
|
190
|
-
unless arg.is_a?(Hash) || arg.is_a?(Symbol)
|
191
|
-
raise ArgumentError, 'must be a Hash or Symbol'
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def validate_is_argument(value)
|
197
|
-
raise ArgumentError, 'argument must be a hash' unless value.size == 2
|
198
|
-
raise ArgumentError, "unsupported operation: #{value[0]}" unless SUPPORTED_OPERATIONS.include?(value[0].to_sym)
|
199
|
-
end
|
200
|
-
|
201
|
-
def process_order_by_arguments(args)
|
202
|
-
args.collect do |arg|
|
203
|
-
case arg
|
204
|
-
when is_a?(Symbol)
|
205
|
-
lookup_property_name(arg)
|
206
|
-
when is_a?(Hash)
|
207
|
-
arg.each do |key, value|
|
208
|
-
"#{lookup_property_name(key)} #{value}"
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
def lookup_property_name(mapping)
|
215
|
-
@property_map[mapping.to_s.to_sym]
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OData::Query::Builder do
|
4
|
-
let(:subject) { OData::Query::Builder.new(Product) }
|
5
|
-
|
6
|
-
describe 'filter method' do
|
7
|
-
describe '#where' do
|
8
|
-
it { expect(subject).to respond_to(:where) }
|
9
|
-
|
10
|
-
it { expect(subject.where(:name)).to be_a(OData::Query::Builder) }
|
11
|
-
it { expect(subject.where(:name)).to eq(subject) }
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '#is' do
|
15
|
-
let(:subject) { OData::Query::Builder.new(Product).where(:name) }
|
16
|
-
|
17
|
-
it { expect(subject).to respond_to(:is) }
|
18
|
-
|
19
|
-
it { expect(subject.is(eq: 'Bread')).to be_a(OData::Query::Builder) }
|
20
|
-
it { expect(subject.is(eq: 'Bread')).to eq(subject) }
|
21
|
-
end
|
22
|
-
|
23
|
-
describe '#and' do
|
24
|
-
let(:subject) { OData::Query::Builder.new(Product).where(:name).is(eq: 'Bread') }
|
25
|
-
|
26
|
-
it { expect(subject).to respond_to(:and) }
|
27
|
-
|
28
|
-
it { expect(subject.and(:name)).to be_a(OData::Query::Builder) }
|
29
|
-
it { expect(subject.and(:name)).to eq(subject) }
|
30
|
-
end
|
31
|
-
|
32
|
-
describe '#or' do
|
33
|
-
let(:subject) { OData::Query::Builder.new(Product).where(:name).is(eq: 'Bread') }
|
34
|
-
|
35
|
-
it { expect(subject).to respond_to(:or) }
|
36
|
-
|
37
|
-
it { expect(subject.or(:name)).to be_a(OData::Query::Builder) }
|
38
|
-
it { expect(subject.or(:name)).to eq(subject) }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OData::Query::Builder do
|
4
|
-
let(:subject) { OData::Query::Builder.new(Product) }
|
5
|
-
|
6
|
-
describe '#order_by' do
|
7
|
-
it { expect(subject).to respond_to(:order_by) }
|
8
|
-
|
9
|
-
describe 'accepts Symbols' do
|
10
|
-
it { expect(subject.order_by(:name)).to be_a(OData::Query::Builder) }
|
11
|
-
it { expect(subject.order_by(:name)).to eq(subject) }
|
12
|
-
|
13
|
-
it { expect(subject.order_by(:price, :rating)).to be_a(OData::Query::Builder) }
|
14
|
-
it { expect(subject.order_by(:price, :rating)).to eq(subject) }
|
15
|
-
end
|
16
|
-
|
17
|
-
describe 'accepts a Hash' do
|
18
|
-
it { expect(subject.order_by(name: :asc)).to be_a(OData::Query::Builder) }
|
19
|
-
it { expect(subject.order_by(name: :asc)).to eq(subject) }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OData::Query::Builder do
|
4
|
-
let(:subject) { OData::Query::Builder.new(Product) }
|
5
|
-
|
6
|
-
describe 'pagination method' do
|
7
|
-
describe '#skip' do
|
8
|
-
it { expect(subject).to respond_to(:skip) }
|
9
|
-
it { expect(subject.skip(5)).to be_a(OData::Query::Builder) }
|
10
|
-
it { expect(subject.skip(5)).to eq(subject) }
|
11
|
-
end
|
12
|
-
|
13
|
-
describe '#limit' do
|
14
|
-
it { expect(subject).to respond_to(:limit) }
|
15
|
-
it { expect(subject.limit(5)).to be_a(OData::Query::Builder) }
|
16
|
-
it { expect(subject.limit(5)).to eq(subject) }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OData::Query::Builder do
|
4
|
-
let(:subject) { OData::Query::Builder.new(Product) }
|
5
|
-
|
6
|
-
describe '#select' do
|
7
|
-
it { expect(subject).to respond_to(:select) }
|
8
|
-
|
9
|
-
it { expect(subject.select(:name, :description)).to be_a(OData::Query::Builder) }
|
10
|
-
it { expect(subject.select(:name, :description)).to eq(subject) }
|
11
|
-
end
|
12
|
-
end
|
data/spec/query/builder_spec.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe OData::Query::Builder do
|
4
|
-
let(:subject) { OData::Query::Builder.new(Product) }
|
5
|
-
|
6
|
-
describe '#to_s' do
|
7
|
-
it 'properly builds queries' do
|
8
|
-
query_string = "Products?$filter=(Name eq 'Bread')"
|
9
|
-
query = subject.where(:name).is(eq: "'Bread'")
|
10
|
-
expect(query.to_s).to eq(query_string)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'properly builds queries' do
|
14
|
-
query_string = "Products?$filter=(Name eq 'Bread') or (Name eq 'Milk')"
|
15
|
-
query = subject.where(:name).is(eq: "'Bread'").or(:name).is(eq: "'Milk'")
|
16
|
-
expect(query.to_s).to eq(query_string)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'properly builds queries' do
|
20
|
-
query_string = 'Products?$filter=(Price lt 15 and Rating gt 3)'
|
21
|
-
query = subject.where(:price).is(lt: 15).and(:rating).is(gt: 3)
|
22
|
-
expect(query.to_s).to eq(query_string)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|