bodhi-slam 0.3.4 → 0.4.0

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: 2ea629d70a0b01fca9df643eb9477d625e3c5d47
4
- data.tar.gz: f4057f1569b8d14baa709c439976af61a5b9b6fa
3
+ metadata.gz: 6df30b96a6aec463e6caa1ccbd279e47d27a57a2
4
+ data.tar.gz: 6852921c1be4570e84dab5869713af2f2f95bd81
5
5
  SHA512:
6
- metadata.gz: 1d89be865cf3730e3567da45b32b0ee2611524d66d08866ab1a885b48db02d1bb7405d0544e7511e9771a6662099be3d025023c340b6cf5212f337267460030c
7
- data.tar.gz: 12b9b414770e1ba9677b0bb58436afd6958e2eec9fcf02a87e8398b6dd91a009867e8019a12e327d58ea48be71bd2bee5ceccf9b5727776530a664751b740b96
6
+ metadata.gz: 7a04d8bf2df4d929e2d533283610f9d93eef65479383250d93c91e4cd22a27ae2b1ed14fdbe3c476b1576561acd85b84bd19e0d9479c18c7a88a2e66ff892d6c
7
+ data.tar.gz: 1df3159b31651ba636903099ac5f7ac5c1dd85bca80866c7de94be3ba1be5ac52c7e34e387ecd1a1cd591a770f44f8b714d7356e6eeee081edc30395720e79eb
@@ -4,6 +4,7 @@ require "json"
4
4
  require "time"
5
5
  require "SecureRandom"
6
6
  require 'regexp-examples'
7
+ require 'active_model'
7
8
 
8
9
  require 'bodhi-slam/validations'
9
10
  require 'bodhi-slam/errors'
@@ -16,6 +17,7 @@ require 'bodhi-slam/resource'
16
17
  require 'bodhi-slam/types'
17
18
  require 'bodhi-slam/users'
18
19
  require 'bodhi-slam/profiles'
20
+ require 'bodhi-slam/queries'
19
21
 
20
22
  class BodhiSlam
21
23
  # Defines a context to interact with the Bodhi API
@@ -0,0 +1,209 @@
1
+ module Bodhi
2
+ class Query
3
+ attr_reader :klass, :url, :context, :criteria, :fields, :paging, :sorting
4
+
5
+ def initialize(klass)
6
+ @klass = Object.const_get(klass.to_s)
7
+ @criteria = []
8
+ @fields = []
9
+ @paging = {}
10
+ @sorting = {}
11
+ end
12
+
13
+ def clear!
14
+ @context = nil
15
+ @criteria.clear
16
+ @fields.clear
17
+ @paging.clear
18
+ @sorting.clear
19
+ end
20
+
21
+ def url
22
+ unless context.nil?
23
+ query = "/#{context.namespace}/resources/#{klass}?"
24
+ else
25
+ query = "/resources/#{klass}?"
26
+ end
27
+ params = []
28
+
29
+ unless criteria.empty?
30
+ if criteria.size > 1
31
+ where_string = "{$and:[#{criteria.join(',')}]}"
32
+ else
33
+ where_string = criteria.join
34
+ end
35
+
36
+ params << "where=#{where_string}"
37
+ end
38
+
39
+ unless fields.empty?
40
+ params << "fields=#{fields.join(',')}"
41
+ end
42
+
43
+ unless paging.empty?
44
+ paging_params = []
45
+
46
+ if paging[:page]
47
+ paging_params << "page:#{paging[:page]}"
48
+ end
49
+
50
+ if paging[:limit]
51
+ paging_params << "limit:#{paging[:limit]}"
52
+ end
53
+
54
+ params << "paging=#{paging_params.join(',')}"
55
+ end
56
+
57
+ unless sorting.empty?
58
+ sort_params = []
59
+
60
+ if sorting[:field]
61
+ sort_params << sorting[:field]
62
+ end
63
+
64
+ if sorting[:order]
65
+ sort_params << sorting[:order]
66
+ end
67
+
68
+ params << "sort=#{sort_params.join(':')}"
69
+ end
70
+
71
+ query << params.join('&')
72
+ query.gsub(/\s+/, "")
73
+ end
74
+
75
+ def all
76
+ if context.nil?
77
+ raise ArgumentError.new("a Bodhi::Context is required to query the API")
78
+ end
79
+
80
+ if context.invalid?
81
+ raise Bodhi::ContextErrors.new(context.errors.messages), context.errors.to_a.to_s
82
+ end
83
+
84
+ result = context.connection.get do |request|
85
+ request.url self.url
86
+ request.headers[context.credentials_header] = context.credentials
87
+ end
88
+
89
+ if result.status != 200
90
+ raise Bodhi::ApiErrors.new(body: result.body, status: result.status), "status: #{result.status}, body: #{result.body}"
91
+ end
92
+
93
+ resources = JSON.parse(result.body)
94
+ resources.map{ |attributes| klass.factory.build(context, attributes) }
95
+ end
96
+
97
+ def first
98
+ if context.nil?
99
+ raise ArgumentError.new("a Bodhi::Context is required to query the API")
100
+ end
101
+
102
+ if context.invalid?
103
+ raise Bodhi::ContextErrors.new(context.errors.messages), context.errors.to_a.to_s
104
+ end
105
+
106
+ result = context.connection.get do |request|
107
+ request.url self.url
108
+ request.headers[context.credentials_header] = context.credentials
109
+ end
110
+
111
+ if result.status != 200
112
+ raise Bodhi::ApiErrors.new(body: result.body, status: result.status), "status: #{result.status}, body: #{result.body}"
113
+ end
114
+
115
+ resources = JSON.parse(result.body)
116
+ resources.map{ |attributes| klass.factory.build(context, attributes) }.first
117
+ end
118
+
119
+ def last
120
+ if context.nil?
121
+ raise ArgumentError.new("a Bodhi::Context is required to query the API")
122
+ end
123
+
124
+ if context.invalid?
125
+ raise Bodhi::ContextErrors.new(context.errors.messages), context.errors.to_a.to_s
126
+ end
127
+
128
+ result = context.connection.get do |request|
129
+ request.url self.url
130
+ request.headers[context.credentials_header] = context.credentials
131
+ end
132
+
133
+ if result.status != 200
134
+ raise Bodhi::ApiErrors.new(body: result.body, status: result.status), "status: #{result.status}, body: #{result.body}"
135
+ end
136
+
137
+ resources = JSON.parse(result.body)
138
+ resources.map{ |attributes| klass.factory.build(context, attributes) }.last
139
+ end
140
+
141
+ def from(context)
142
+ unless context.is_a? Bodhi::Context
143
+ raise ArgumentError.new("Expected Bodhi::Context but received #{context.class}")
144
+ end
145
+
146
+ @context = context
147
+ self
148
+ end
149
+
150
+ def where(query)
151
+ unless query.is_a? String
152
+ raise ArgumentError.new("Expected String but received #{query.class}")
153
+ end
154
+
155
+ @criteria << query
156
+ @criteria.uniq!
157
+ self
158
+ end
159
+ alias :and :where
160
+
161
+ def select(field_names)
162
+ unless field_names.is_a? String
163
+ raise ArgumentError.new("Expected String but received #{field_names.class}")
164
+ end
165
+
166
+ fields_array = field_names.split(',')
167
+ @fields << fields_array
168
+ @fields.flatten!
169
+ @fields.uniq!
170
+ self
171
+ end
172
+
173
+ def limit(number)
174
+ unless number.is_a? Integer
175
+ raise ArgumentError.new("Expected Integer but received #{number.class}")
176
+ end
177
+
178
+ unless number <= 100
179
+ raise ArgumentError.new("Expected limit to be less than or equal to 100 but received #{number}")
180
+ end
181
+
182
+ @paging[:limit] = number
183
+ self
184
+ end
185
+
186
+ def page(number)
187
+ unless number.is_a? Integer
188
+ raise ArgumentError.new("Expected Integer but received #{number.class}")
189
+ end
190
+
191
+ @paging[:page] = number
192
+ self
193
+ end
194
+
195
+ def sort(field, order=nil)
196
+ unless field.is_a? String
197
+ raise ArgumentError.new("Expected String but received #{field.class}")
198
+ end
199
+
200
+ unless order.nil?
201
+ @sorting[:order] = order
202
+ end
203
+
204
+ @sorting[:field] = field
205
+ self
206
+ end
207
+
208
+ end
209
+ end
@@ -1,5 +1,6 @@
1
1
  module Bodhi
2
2
  module Resource
3
+
3
4
  SYSTEM_ATTRIBUTES = [:sys_created_at, :sys_version, :sys_modified_at, :sys_modified_by,
4
5
  :sys_namespace, :sys_created_by, :sys_type_version, :sys_id, :sys_embeddedType]
5
6
  SUPPORT_ATTRIBUTES = [:bodhi_context, :errors]
@@ -62,8 +63,9 @@ module Bodhi
62
63
  raise Bodhi::ApiErrors.new(body: result.body, status: result.status), "status: #{result.status}, body: #{result.body}"
63
64
  end
64
65
 
65
- resource_attributes = JSON.parse(result.body)
66
- factory.build(context, resource_attributes)
66
+ record = Object.const_get(name).new(JSON.parse(result.body))
67
+ record.bodhi_context = context
68
+ record
67
69
  end
68
70
 
69
71
  # Returns all records of the given resource from the Bodhi Cloud.
@@ -92,7 +94,7 @@ module Bodhi
92
94
  records << JSON.parse(result.body)
93
95
  end while records.size == 100
94
96
 
95
- records.flatten.collect{ |record| factory.build(record) }
97
+ records.flatten.collect{ |record| Object.const_get(name).new(record) }
96
98
  end
97
99
 
98
100
  # Aggregates the given resource based on the supplied +pipeline+
@@ -120,30 +122,15 @@ module Bodhi
120
122
  JSON.parse(result.body)
121
123
  end
122
124
 
123
- # Returns all records for a resource which match the given +query+
125
+ # Returns a Bodhi::Query object for quering the given Resource
124
126
  #
125
127
  # context = Bodhi::Context.new
126
- # Resource.where(context, "{property: 'value'}")
127
- def where(context, query)
128
- if context.invalid?
129
- raise Bodhi::ContextErrors.new(context.errors.messages), context.errors.to_a.to_s
130
- end
131
-
132
- unless query.is_a? String
133
- raise ArgumentError.new("Expected 'query' to be a String. 'query' #=> #{query.class}")
134
- end
135
-
136
- result = context.connection.get do |request|
137
- request.url "/#{context.namespace}/resources/#{name}?where=#{query}"
138
- request.headers[context.credentials_header] = context.credentials
139
- end
140
-
141
- if result.status != 200
142
- raise Bodhi::ApiErrors.new(body: result.body, status: result.status), "status: #{result.status}, body: #{result.body}"
143
- end
144
-
145
- resources = JSON.parse(result.body)
146
- resources.map{ |attributes| factory.build(context, attributes) }
128
+ # Resource.where("{property: 'value'}").from(context).all
129
+ # Resource.where("{conditions}").and("{more conditions}").limit(10).from(context).all
130
+ def where(query)
131
+ query_obj = Bodhi::Query.new(name)
132
+ query_obj.where(query)
133
+ query_obj
147
134
  end
148
135
 
149
136
  # Deletes all records from a resource in the given +context+
@@ -167,6 +154,9 @@ module Bodhi
167
154
  end
168
155
 
169
156
  module InstanceMethods
157
+ def id; @sys_id; end
158
+ def persisted?; !@sys_id.nil?; end
159
+
170
160
  # Returns a Hash of the Objects form attributes
171
161
  #
172
162
  # s = SomeResource.build({foo:"test", bar:12345})
@@ -181,7 +171,22 @@ module Bodhi
181
171
  end
182
172
  attributes
183
173
  end
184
-
174
+
175
+ # Updates the resource with the given attributes Hash
176
+ #
177
+ # s = SomeResource.factory.build(foo:"test", bar:12345)
178
+ # s.attributes # => { foo: "test", bar: 12345 }
179
+ # s.update_attributes(foo:"12345", bar:10)
180
+ # s.attributes # => { foo: "12345", bar: 10 }
181
+ def update_attributes(params)
182
+ self.instance_variables.each do |variable|
183
+ attribute_name = variable.to_s.delete('@').to_sym
184
+ unless SYSTEM_ATTRIBUTES.include?(attribute_name) || SUPPORT_ATTRIBUTES.include?(attribute_name)
185
+ send("#{attribute_name}=", params[attribute_name])
186
+ end
187
+ end
188
+ end
189
+
185
190
  # Returns all the Objects attributes as JSON.
186
191
  # It converts any nested Objects to JSON if they respond to +to_json+
187
192
  #
@@ -192,6 +197,34 @@ module Bodhi
192
197
  attributes.to_json
193
198
  end
194
199
 
200
+ # Saves the resource to the Bodhi Cloud. Returns true if record was saved
201
+ #
202
+ # obj = Resource.new
203
+ # obj.save # => true
204
+ # obj.persisted? # => true
205
+ def save
206
+ if self.invalid?
207
+ return false
208
+ end
209
+
210
+ result = bodhi_context.connection.post do |request|
211
+ request.url "/#{bodhi_context.namespace}/resources/#{self.class}"
212
+ request.headers['Content-Type'] = 'application/json'
213
+ request.headers[bodhi_context.credentials_header] = bodhi_context.credentials
214
+ request.body = attributes.to_json
215
+ end
216
+
217
+ if result.status != 201
218
+ raise Bodhi::ApiErrors.new(body: result.body, status: result.status), "status: #{result.status}, body: #{result.body}"
219
+ end
220
+
221
+ if result.headers['location']
222
+ @sys_id = result.headers['location'].match(/(?<id>[a-zA-Z0-9]{24})/)[:id]
223
+ end
224
+
225
+ true
226
+ end
227
+
195
228
  # Saves the resource to the Bodhi Cloud. Raises ArgumentError if record could not be saved.
196
229
  #
197
230
  # obj = Resouce.new
@@ -224,6 +257,29 @@ module Bodhi
224
257
  raise Bodhi::ApiErrors.new(body: result.body, status: result.status), "status: #{result.status}, body: #{result.body}"
225
258
  end
226
259
  end
260
+ alias :destroy :delete!
261
+
262
+ def update!(params)
263
+ update_attributes(params)
264
+
265
+ if invalid?
266
+ return false
267
+ end
268
+
269
+ result = bodhi_context.connection.put do |request|
270
+ request.url "/#{bodhi_context.namespace}/resources/#{self.class}/#{sys_id}"
271
+ request.headers['Content-Type'] = 'application/json'
272
+ request.headers[bodhi_context.credentials_header] = bodhi_context.credentials
273
+ request.body = params.to_json
274
+ end
275
+
276
+ if result.status != 204
277
+ raise Bodhi::ApiErrors.new(body: result.body, status: result.status), "status: #{result.status}, body: #{result.body}"
278
+ end
279
+
280
+ true
281
+ end
282
+ alias :update :update!
227
283
 
228
284
  def patch!(params)
229
285
  result = bodhi_context.connection.patch do |request|
@@ -241,7 +297,7 @@ module Bodhi
241
297
 
242
298
  def self.included(base)
243
299
  base.extend(ClassMethods)
244
- base.include(InstanceMethods, Bodhi::Validations)
300
+ base.include(InstanceMethods, Bodhi::Validations, ActiveModel::Model)
245
301
  base.instance_variable_set(:@factory, Bodhi::Factory.new(base))
246
302
  end
247
303
  end
@@ -176,7 +176,7 @@ module Bodhi
176
176
  })
177
177
 
178
178
  type.properties.each_pair do |attr_name, attr_properties|
179
- attr_properties.delete_if{ |key, value| ["system", "trim", "unique", "default", "isCurrentUser"].include?(key) }
179
+ attr_properties.delete_if{ |key, value| ["system", "trim", "unique", "default", "isCurrentUser", "toLower"].include?(key) }
180
180
  klass.validates(attr_name.to_sym, attr_properties)
181
181
  klass.factory.add_generator(attr_name.to_sym, attr_properties)
182
182
  end
@@ -4,7 +4,11 @@ module Bodhi
4
4
  def initialize(value); end
5
5
 
6
6
  def validate(record, attribute, value)
7
- record.errors.add(attribute, "must be an array") unless value.is_a? Array
7
+ if value.nil?
8
+ #do nothing
9
+ else
10
+ record.errors.add(attribute, "must be an array") unless value.is_a? Array
11
+ end
8
12
  end
9
13
 
10
14
  def to_options
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bodhi-slam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - willdavis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-23 00:00:00.000000000 Z
11
+ date: 2015-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-http-persistent
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activemodel
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.2'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -138,6 +152,7 @@ files:
138
152
  - lib/bodhi-slam/errors/context.rb
139
153
  - lib/bodhi-slam/factory.rb
140
154
  - lib/bodhi-slam/profiles.rb
155
+ - lib/bodhi-slam/queries.rb
141
156
  - lib/bodhi-slam/resource.rb
142
157
  - lib/bodhi-slam/types.rb
143
158
  - lib/bodhi-slam/users.rb