odata-model 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dcef84e8ecc5149a6a18c69532677a69bb5febad
4
- data.tar.gz: ce363fbfb1866a67e3705b0260e9fc80e0ac004b
3
+ metadata.gz: 332cae2c88d7bec95fd2099befabbbecc227585a
4
+ data.tar.gz: 9c7c7fb9ad675081918ddbd85397425ec086c9a0
5
5
  SHA512:
6
- metadata.gz: 5d171f64ab550e40f4fe064e5d83afb4c595348b9239a5c3efd0b7aa35be874b31d5205478690497eac5494bcc7dac8c18db2702c31004a132393e6f0f18ba68
7
- data.tar.gz: cbc3a736fee2b716381ccaaf357dd7cb9037c3e4969f5b71f1e81d021345d80fe80af95c53b974f96b0e1f9f0d22ec6f7c6d01fe115feea32ec55325bb6f6e68
6
+ metadata.gz: a7d906d5dbf1970f0391133f3daf252e193cdfb452f00a0fda0532357f7c8fb955524579338f1648d93c1025d2664ee746dff72d67f90f03344fa30510431294
7
+ data.tar.gz: 2de6ebdf03dd5b12d4870e3c39f338d873459be5a1f48f2f9b7f90c1ea973b530fba95d8b003c89aa6a4c86db92d7d8b5aa810be7274816e12575b29fb087e41
@@ -0,0 +1,48 @@
1
+ require 'active_model'
2
+
3
+ module OData
4
+ module Model
5
+ # The OData::Model::ActiveModel module encapsulates all the functionality
6
+ # specifically needed for OData::Model to work with Rails via the
7
+ # ActiveModel conventions.
8
+ module ActiveModel
9
+ extend ActiveSupport::Concern
10
+
11
+ extend ::ActiveModel::Naming
12
+ include ::ActiveModel::Validations
13
+ include ::ActiveModel::Conversion
14
+ include ::ActiveModel::Dirty
15
+
16
+ included do
17
+ # ...
18
+ end
19
+
20
+ # Integrates ActiveModel's error handling capabilities
21
+ # @return [ActiveModel::Errors]
22
+ def errors
23
+ @errors ||= ::ActiveModel::Errors.new(self)
24
+ end
25
+
26
+ # Used for ActiveModel validations
27
+ # @api private
28
+ def read_attribute_for_validation(attr)
29
+ send(attr)
30
+ end
31
+
32
+ # Methods mixed in at the class level.
33
+ module ClassMethods
34
+ # Used for ActiveModel validations
35
+ # @api private
36
+ def human_attribute_name(attr, options = {})
37
+ attr
38
+ end
39
+
40
+ # Used for ActiveModel validations
41
+ # @api private
42
+ def lookup_ancestors
43
+ [self]
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,121 @@
1
+ module OData
2
+ module Model
3
+ # The OData::Model::Attributes module encapsulates all the functionality
4
+ # specifically needed for OData::Model to support the mapping of
5
+ # OData::Entity properties to attributes on the class that includes
6
+ # OData::Model.
7
+ module Attributes
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ # ...
12
+ end
13
+
14
+ # Returns an array of registered attributes.
15
+ # @return [Array]
16
+ # @api private
17
+ def attributes
18
+ self.class.class_variable_get(:@@attributes)
19
+ end
20
+
21
+ # Returns the hash for the attribute to property mapping.
22
+ # @return [Hash]
23
+ # @api private
24
+ def property_map
25
+ self.class.class_variable_get(:@@property_map)
26
+ end
27
+
28
+ # Methods mixed in at the class level.
29
+ module ClassMethods
30
+ # Defines a property from this model's related OData::Entity you want
31
+ # mapped to an attribute.
32
+ #
33
+ # @param literal_name [to_s] the literal Entity property name
34
+ # @param options [Hash] hash of options
35
+ # @return nil
36
+ def property(literal_name, options = {})
37
+ attribute_name = (options[:as] || literal_name.to_s.underscore).to_sym
38
+
39
+ register_attribute(attribute_name, literal_name, options)
40
+ create_accessors(attribute_name)
41
+
42
+ nil
43
+ end
44
+
45
+ # Returns an array of all registered attributes
46
+ # @return [Array]
47
+ # @api private
48
+ def attributes
49
+ if self.class_variable_defined?(:@@attributes)
50
+ class_variable_get(:@@attributes)
51
+ else
52
+ class_variable_set(:@@attributes, [])
53
+ class_variable_get(:@@attributes)
54
+ end
55
+ end
56
+
57
+ # Returns a hash keyed to the attribute name of passed options from the
58
+ # property definitions.
59
+ # @return [Hash]
60
+ # @api private
61
+ def attribute_options
62
+ if self.class_variable_defined?(:@@attribute_options)
63
+ class_variable_get(:@@attribute_options)
64
+ else
65
+ class_variable_set(:@@attribute_options, {})
66
+ class_variable_get(:@@attribute_options)
67
+ end
68
+ end
69
+
70
+ # Returns a hash keyed to the attribute name with the values being the
71
+ # literal OData property name to use when accessing entity data.
72
+ # @return [Hash]
73
+ # @api private
74
+ def property_map
75
+ if self.class_variable_defined?(:@@property_map)
76
+ class_variable_get(:@@property_map)
77
+ else
78
+ class_variable_set(:@@property_map, {})
79
+ class_variable_get(:@@property_map)
80
+ end
81
+ end
82
+
83
+ # Registers a supplied attribute with its literal property name and any
84
+ # provided options.
85
+ # @return [nil]
86
+ # @api private
87
+ def register_attribute(attribute_name, literal_name, options)
88
+ attributes << attribute_name
89
+ attribute_options[attribute_name] = options
90
+ property_map[attribute_name] = literal_name
91
+
92
+ # Ties into ActiveModel::Dirty
93
+ define_attribute_methods attribute_name
94
+
95
+ nil
96
+ end
97
+
98
+ # Create attribute accessors for the supplied attribute name.
99
+ # @return [nil]
100
+ # @api private
101
+ def create_accessors(attribute_name)
102
+ class_eval do
103
+ define_method(attribute_name) do
104
+ odata_entity[property_map[attribute_name]]
105
+ end
106
+
107
+ define_method("#{attribute_name}=") do |value|
108
+ unless entity[property_map[attribute_name]] == value
109
+ send("#{attribute_name}_will_change!")
110
+ end
111
+
112
+ odata_entity[property_map[attribute_name]] = value
113
+ end
114
+ end
115
+
116
+ nil
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,104 @@
1
+ module OData
2
+ module Model
3
+ # The OData::Model::Configuration module encapsulates all the functionality
4
+ # specifically needed for OData::Model to maintain internal configuration
5
+ # details about it's relationship to the OData gem.
6
+ module Configuration
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ # ...
11
+ end
12
+
13
+ # Returns the entity the current model is associated with, or a fresh
14
+ # entity.
15
+ # @return [OData::Entity]
16
+ # @api private
17
+ def odata_entity
18
+ @odata_entity ||= self.class.odata_service[odata_entity_set_name].new_entity
19
+ end
20
+
21
+ # Returns the name of the OData::EntitySet the current model is related
22
+ # to.
23
+ # @return [String]
24
+ # @api private
25
+ def odata_entity_set_name
26
+ self.class.odata_entity_set_name
27
+ end
28
+
29
+ # Returns the OData::EntitySet the current model is related to.
30
+ # @return [OData::EntitySet]
31
+ # @api private
32
+ def odata_entity_set
33
+ self.class.odata_entity_set
34
+ end
35
+
36
+ # Methods mixed in at the class level.
37
+ module ClassMethods
38
+ # Define the service to use for the current OData::Model. This method
39
+ # will cause the service to be looked up in the OData::ServiceRegistry
40
+ # by the supplied key, so it can accept either the service's URL or its
41
+ # namespace.
42
+ #
43
+ # @param service_key [to_s] service URL or namespace
44
+ # @return [nil]
45
+ def use_service(service_key)
46
+ odata_config[:service] = OData::ServiceRegistry[service_key.to_s]
47
+ nil
48
+ end
49
+
50
+ # Define the entity set to use for the current OData::Model. This
51
+ # method will record in the OData configuration the supplied name so
52
+ # that it can be used to communicate properly with the underlying
53
+ # OData::Service.
54
+ #
55
+ # @param set_name [to_s] name of EntitySet used by OData service
56
+ # @return [nil]
57
+ def use_entity_set(set_name)
58
+ odata_config[:entity_set_name] = set_name.to_s
59
+ nil
60
+ end
61
+
62
+ # Get the OData::Service
63
+ # @return [OData::Service]
64
+ # @api private
65
+ def odata_service
66
+ odata_config[:service]
67
+ end
68
+
69
+ # Get the OData::Service's namespace
70
+ # @return [String] OData Service's namespace
71
+ # @api private
72
+ def odata_namespace
73
+ odata_service.try(:namespace)
74
+ end
75
+
76
+ # Returns the configuration for working with the OData gem.
77
+ # @return [Hash]
78
+ # @api private
79
+ def odata_config
80
+ if class_variable_defined?(:@@odata_config)
81
+ class_variable_get(:@@odata_config)
82
+ else
83
+ class_variable_set(:@@odata_config, {})
84
+ class_variable_get(:@@odata_config)
85
+ end
86
+ end
87
+
88
+ # Returns the entity set name this model is related to.
89
+ # @return [String]
90
+ # @api private
91
+ def odata_entity_set_name
92
+ odata_config[:entity_set_name] ||= self.name.pluralize
93
+ end
94
+
95
+ # Returns the OData::EntitySet the current model is related to.
96
+ # @return [OData::EntitySet]
97
+ # @api private
98
+ def odata_entity_set
99
+ odata_config[:entity_set] ||= odata_service[odata_entity_set_name]
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,43 @@
1
+ module OData
2
+ module Model
3
+ # The OData::Model::Persistence module encapsulates all the functionality
4
+ # specifically needed for OData::Model to persist data to and from the
5
+ # OData gem.
6
+ module Persistence
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ # ...
11
+ end
12
+
13
+ # Returns whether the current instance has been persisted.
14
+ # @return [Boolean]
15
+ def persisted?
16
+ if instance_variable_defined?(:@persisted)
17
+ instance_variable_get(:@persisted)
18
+ else
19
+ instance_variable_set(:@persisted, false)
20
+ instance_variable_get(:@persisted)
21
+ end
22
+ end
23
+
24
+ # Save the current model.
25
+ def save
26
+ odata_service[odata_entity_set_name] << odata_entity
27
+ instance_variable_set(:@persisted, true)
28
+ changes_applied
29
+ end
30
+
31
+ # Reload the model from OData
32
+ def reload!
33
+ # TODO reload OData entity
34
+ reset_changes
35
+ end
36
+
37
+ # Methods mixed in at the class level.
38
+ module ClassMethods
39
+ # ...
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ module OData
2
+ module Model
3
+ module Query
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # ...
8
+ end
9
+
10
+ module ClassMethods
11
+ # Starts a chain for building up an OData query.
12
+ # @return [OData::Query::Builder]
13
+ def find
14
+ OData::Query::Builder.new(self)
15
+ end
16
+
17
+ # Enables lookup of model entities by their primary key.
18
+ # @param [to_s] primary key value to lookup
19
+ # @return [OData::Model,nil]
20
+ def [](primary_key_value)
21
+ entity = odata_entity_set[primary_key_value]
22
+ model = self.new
23
+ model.instance_variable_set(:@odata_entity, entity)
24
+ model
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  module OData
2
2
  module Model
3
- VERSION = '0.0.1'
3
+ VERSION = '0.0.2'
4
4
  end
5
5
  end
data/lib/odata/model.rb CHANGED
@@ -1,8 +1,17 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
3
+ require 'active_support/concern'
4
+
1
5
  require 'odata'
2
- require 'odata/model/version'
3
6
 
4
- require 'active_model'
5
- require 'active_support/concern'
7
+ require 'odata/query/builder'
8
+
9
+ require 'odata/model/version'
10
+ require 'odata/model/active_model'
11
+ require 'odata/model/configuration'
12
+ require 'odata/model/attributes'
13
+ require 'odata/model/persistence'
14
+ require 'odata/model/query'
6
15
 
7
16
  # OData is the parent namespace for the OData::Model project.
8
17
  module OData
@@ -12,46 +21,10 @@ module OData
12
21
  module Model
13
22
  extend ActiveSupport::Concern
14
23
 
15
- extend ActiveModel::Naming
16
- include ActiveModel::Validations
17
- include ActiveModel::Conversion
18
-
19
- included do
20
- # ...
21
- end
22
-
23
- # Integrates ActiveModel's error handling capabilities
24
- # @return [ActiveModel::Errors]
25
- def errors
26
- @errors ||= ActiveModel::Errors.new(self)
27
- end
28
-
29
- # Returns whether the current instance has been persisted.
30
- # @return [Boolean]
31
- def persisted?
32
- false
33
- end
34
-
35
- # Used for ActiveModel validations
36
- # @api private
37
- def read_attribute_for_validation(attr)
38
- send(attr)
39
- end
40
-
41
- # Methods integrated at the class level when OData::Model is included into
42
- # a given class.
43
- module ClassMethods
44
- # Used for ActiveModel validations
45
- # @api private
46
- def human_attribute_name(attr, options = {})
47
- attr
48
- end
49
-
50
- # Used for ActiveModel validations
51
- # @api private
52
- def lookup_ancestors
53
- [self]
54
- end
55
- end
24
+ include OData::Model::ActiveModel
25
+ include OData::Model::Configuration
26
+ include OData::Model::Attributes
27
+ include OData::Model::Persistence
28
+ include OData::Model::Query
56
29
  end
57
30
  end
@@ -0,0 +1,210 @@
1
+ module OData
2
+ class Query
3
+ class Builder
4
+ SUPPORTED_OPERATIONS = [:eq, :ne, :gt, :ge, :lt, :le, :not]
5
+
6
+ # Sets up a new Query Builder.
7
+ # @param entity_set [OData::EntitySet] the EntitySet to query
8
+ def initialize(model)
9
+ @entity_set = model.odata_entity_set
10
+ @property_map = model.property_map
11
+ end
12
+
13
+ # Set the number of entities to skip for the final query.
14
+ # @param value [to_i,nil]
15
+ # @return [self]
16
+ def skip(value)
17
+ value = nil if value == 0
18
+ query_structure[:skip] = value.try(:to_i)
19
+ self
20
+ end
21
+
22
+ # Set the number of entities to return in the final query.
23
+ # @param value [to_i,nil]
24
+ # @return [self]
25
+ def limit(value)
26
+ value = nil if value == 0
27
+ query_structure[:top] = value.try(:to_i)
28
+ self
29
+ end
30
+
31
+ # Set the options for ordering the final query.
32
+ # @param args [Symbol,Hash]
33
+ # @return [self]
34
+ def order_by(*args)
35
+ validate_order_by_arguments(args)
36
+ query_structure[:orderby] += process_order_by_arguments(args)
37
+ self
38
+ end
39
+
40
+ # Set the properties to select with the final query.
41
+ # @param args [Array<Symbol>]
42
+ # @return self
43
+ def select(*args)
44
+ args.each {|arg| query_structure[:select] << arg.to_sym}
45
+ self
46
+ end
47
+
48
+ # Sets up a new filter condition on the provided property mapping.
49
+ # @param value [to_s]
50
+ # @return self
51
+ def where(value)
52
+ last_filter = query_structure[:filter].last
53
+ clause = {
54
+ property: lookup_property_name(value),
55
+ opeartion: nil,
56
+ argument: nil
57
+ }
58
+
59
+ if last_filter.is_a?(Array)
60
+ last_filter << clause
61
+ else
62
+ query_structure[:filter] << [clause]
63
+ end
64
+ self
65
+ end
66
+
67
+ # Sets the operation and argument for the last filter condition started
68
+ # by #where, #and or #or.
69
+ # @param value [Hash]
70
+ # @return self
71
+ def is(value)
72
+ value = value.first
73
+ validate_is_argument(value)
74
+ last_filter = query_structure[:filter].last.last
75
+ if last_filter[:operation].nil? && last_filter[:argument].nil?
76
+ last_filter[:operation] = value[0].to_sym
77
+ last_filter[:argument] = value[1]
78
+ else
79
+ query_structure[:filter].last << {
80
+ property: last_filter[:property],
81
+ operation: value[0].to_sym,
82
+ argument: value[1]
83
+ }
84
+ end
85
+ self
86
+ end
87
+
88
+ # Adds another filter to the last supplied clause.
89
+ # @param value [to_s]
90
+ # @return self
91
+ def and(value)
92
+ query_structure[:filter].last << {
93
+ property: lookup_property_name(value),
94
+ opeartion: nil,
95
+ argument: nil
96
+ }
97
+ self
98
+ end
99
+
100
+ # Adds an alternate filter after the last supplied clause.
101
+ # @param value [to_s]
102
+ # @return self
103
+ def or(value)
104
+ query_structure[:filter] << [{
105
+ property: lookup_property_name(value),
106
+ opeartion: nil,
107
+ argument: nil
108
+ }]
109
+ self
110
+ end
111
+
112
+ # Returns the current query structure as a valid query string.
113
+ def to_s
114
+ # TODO validate the actual query structure
115
+
116
+ query_array = []
117
+ query_array << filters_to_query
118
+ query_array << orderby_to_query
119
+ query_array << select_to_query
120
+ query_array << top_to_query
121
+ query_array << skip_to_query
122
+ query_array.compact!
123
+
124
+ query_string = query_array.join('&')
125
+ "#{entity_set.name}?#{query_string}"
126
+ end
127
+
128
+ private
129
+
130
+ def query_structure
131
+ @query_structure ||= {
132
+ top: nil,
133
+ skip: nil,
134
+ orderby: [],
135
+ select: [],
136
+ filter: []
137
+ }
138
+ end
139
+
140
+ def entity_set
141
+ @entity_set
142
+ end
143
+
144
+ def skip_to_query
145
+ return nil if query_structure[:skip].nil?
146
+ "$skip=#{query_structure[:skip]}"
147
+ end
148
+
149
+ def top_to_query
150
+ return nil if query_structure[:top].nil?
151
+ "$top=#{query_structure[:top]}"
152
+ end
153
+
154
+ def orderby_to_query
155
+ return nil if query_structure[:orderby].empty?
156
+ "$orderby=#{query_structure[:orderby].join(',')}"
157
+ end
158
+
159
+ def select_to_query
160
+ return nil if query_structure[:select].empty?
161
+ "$select=#{query_structure[:select].join(',')}"
162
+ end
163
+
164
+ def filters_to_query
165
+ str = "$filter="
166
+ clauses = []
167
+ query_structure[:filter].each do |clause|
168
+ clause_filters = []
169
+ clause.each do |filter|
170
+ clause_filters << "#{filter[:property]} #{filter[:operation]} #{filter[:argument]}"
171
+ end
172
+ clauses << clause_filters.join(' and ')
173
+ end
174
+ clauses.collect! {|clause| "(#{clause})"}
175
+ str << clauses.join(' or ')
176
+ str
177
+ end
178
+
179
+ def validate_order_by_arguments(args)
180
+ args.each do |arg|
181
+ unless arg.is_a?(Hash) || arg.is_a?(Symbol)
182
+ raise ArgumentError, 'must be a Hash or Symbol'
183
+ end
184
+ end
185
+ end
186
+
187
+ def validate_is_argument(value)
188
+ raise ArgumentError, 'argument must be a hash' unless value.size == 2
189
+ raise ArgumentError, "unsupported operation: #{value[0]}" unless SUPPORTED_OPERATIONS.include?(value[0].to_sym)
190
+ end
191
+
192
+ def process_order_by_arguments(args)
193
+ args.collect do |arg|
194
+ case arg
195
+ when is_a?(Symbol)
196
+ lookup_property_name(arg)
197
+ when is_a?(Hash)
198
+ arg.each do |key, value|
199
+ "#{lookup_property_name(key)} #{value}"
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ def lookup_property_name(mapping)
206
+ @property_map[mapping.to_s.to_sym]
207
+ end
208
+ end
209
+ end
210
+ end
data/odata-model.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
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.1.0'
27
+ spec.add_dependency 'odata', '~> 0.2.0'
28
28
  spec.add_dependency 'activesupport', '>= 3.0.0'
29
29
  spec.add_dependency 'activemodel', '>= 3.0.0'
30
30
  end
@@ -0,0 +1,3 @@
1
+ class BareModel
2
+ include OData::Model
3
+ end
@@ -0,0 +1,13 @@
1
+ class Product
2
+ include OData::Model
3
+
4
+ use_service 'ODataDemo'
5
+
6
+ property 'ID'
7
+ property 'Name'
8
+ property 'Description'
9
+ property 'Rating'
10
+ property 'Price'
11
+ property 'ReleaseDate'
12
+ property 'DiscontinuedDate'
13
+ end
@@ -1,13 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
- class BareModel
4
- include OData::Model
5
- end
6
-
7
3
  describe OData::Model do
8
- let(:subject) { BareModel.new }
4
+ let(:subject) { Product.new }
9
5
 
10
- it { expect(BareModel).to respond_to(:model_name) }
6
+ it { expect(Product).to respond_to(:model_name) }
11
7
 
12
8
  it { expect(subject).to respond_to(:to_key) }
13
9
  it { expect(subject).to respond_to(:to_param) }
@@ -46,7 +42,7 @@ describe OData::Model do
46
42
  end
47
43
 
48
44
  describe '.model_name' do
49
- let(:model_name) { BareModel.model_name }
45
+ let(:model_name) { Product.model_name }
50
46
 
51
47
  it { expect(model_name).to respond_to(:to_str) }
52
48
  it { expect(model_name.human).to respond_to(:to_str) }
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe OData::Model do
4
+ describe 'property defaults' do
5
+ properties = %w{ID Name Description Rating Price ReleaseDate DiscontinuedDate}
6
+ attributes = properties.collect {|k| k.underscore.to_sym}
7
+
8
+ attributes.each do |attr_name|
9
+ it { expect(Product.new).to respond_to(attr_name) }
10
+ end
11
+
12
+ attributes.each do |attr_name|
13
+ it { expect(Product.new).to respond_to("#{attr_name}=") }
14
+ end
15
+
16
+ it { expect(Product).to respond_to(:attributes)}
17
+ it { expect(Product.attributes).to eq(attributes) }
18
+
19
+ it { expect(Product.new).to respond_to(:attributes) }
20
+ it { expect(Product.new.attributes).to eq(attributes) }
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe OData::Model do
4
+ describe 'query interface' do
5
+ it { expect(Product).to respond_to(:[]) }
6
+ it { expect(Product).to respond_to(:find) }
7
+
8
+ describe 'Product[]' do
9
+ it 'finds a model instance' do
10
+ expect(Product[0]).to be_a(Product)
11
+ end
12
+ end
13
+
14
+ describe 'Product.find' do
15
+ it 'returns an OData::Query::Builder' do
16
+ expect(Product.find).to be_a(OData::Query::Builder)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe OData::Model do
4
+ describe 'service integration' do
5
+ let(:service) { OData::ServiceRegistry['ODataDemo'] }
6
+
7
+ it { expect(Product).to respond_to(:odata_service) }
8
+ it { expect(Product.odata_service).to be_a(OData::Service) }
9
+ it { expect(Product.odata_service).to eq(service)}
10
+
11
+ it { expect(Product).to respond_to(:odata_namespace) }
12
+ it { expect(Product.odata_namespace).to eq('ODataDemo') }
13
+ end
14
+ end
@@ -0,0 +1,41 @@
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
@@ -0,0 +1,22 @@
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
@@ -0,0 +1,19 @@
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
@@ -0,0 +1,12 @@
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
@@ -0,0 +1,25 @@
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
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
1
4
  if ENV['CI']
2
5
  require 'codeclimate-test-reporter'
3
6
  CodeClimate::TestReporter.start
@@ -10,6 +13,14 @@ end
10
13
 
11
14
  require 'odata/model'
12
15
 
16
+ # Suppressing a deprecation warning
17
+ I18n.enforce_available_locales = false
18
+
19
+ OData::Service.open('http://services.odata.org/OData/OData.svc')
20
+
21
+ require 'example_models/bare_model'
22
+ require 'example_models/odatademo_product'
23
+
13
24
  RSpec::Matchers.define :be_boolean do
14
25
  match do |actual|
15
26
  expect(actual).to satisfy { |x| x == true || x == false }
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.1
4
+ version: 0.0.2
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-08 00:00:00.000000000 Z
11
+ date: 2014-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.1.0
89
+ version: 0.2.0
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.1.0
96
+ version: 0.2.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: activesupport
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -138,9 +138,25 @@ files:
138
138
  - README.md
139
139
  - Rakefile
140
140
  - lib/odata/model.rb
141
+ - lib/odata/model/active_model.rb
142
+ - lib/odata/model/attributes.rb
143
+ - lib/odata/model/configuration.rb
144
+ - lib/odata/model/persistence.rb
145
+ - lib/odata/model/query.rb
141
146
  - lib/odata/model/version.rb
147
+ - lib/odata/query/builder.rb
142
148
  - odata-model.gemspec
143
- - spec/active_model_lint_spec.rb
149
+ - spec/example_models/bare_model.rb
150
+ - spec/example_models/odatademo_product.rb
151
+ - spec/model/active_model_lint_spec.rb
152
+ - spec/model/property_defaults_spec.rb
153
+ - spec/model/query_interface_spec.rb
154
+ - 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
144
160
  - spec/spec_helper.rb
145
161
  homepage: https://github.com/ruby-odata/odata-model
146
162
  licenses:
@@ -167,5 +183,15 @@ signing_key:
167
183
  specification_version: 4
168
184
  summary: An ActiveModel mapping layer for the OData gem
169
185
  test_files:
170
- - spec/active_model_lint_spec.rb
186
+ - spec/example_models/bare_model.rb
187
+ - spec/example_models/odatademo_product.rb
188
+ - spec/model/active_model_lint_spec.rb
189
+ - spec/model/property_defaults_spec.rb
190
+ - spec/model/query_interface_spec.rb
191
+ - 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
171
197
  - spec/spec_helper.rb