odata-model 0.0.1 → 0.0.2

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 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