Class: Orchestrate::Rails::Model

Inherits:
Application::Record show all
Extended by:
ActiveModel::Naming
Includes:
ActiveModel::Conversion, ActiveModel::Serialization, ActiveModel::Serializers, ActiveModel::Serializers::JSON, ActiveModel::Validations
Defined in:
lib/orchestrate_rails/model.rb

Overview

Class to define rails models for Orchestrate.io DataBases-as-a-Service. The library provides a base class that, when subclassed to define a model, sets up a mapping between the model and an Orchestrate.io collection.

Instance Attribute Summary

Attributes inherited from Application::Record

#__ref_value__, #id

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Application::Record

#orchestrate_client, #orchestrate_primary_key, #orchio_delete, orchio_delete, #orchio_delete_graph, orchio_delete_key, #orchio_get, #orchio_get_by_ref, #orchio_get_events, #orchio_get_graph, orchio_list, #orchio_purge, #orchio_put, #orchio_put_event, #orchio_put_graph, #orchio_put_if_match, #orchio_put_if_none_match, orchio_search

Constructor Details

#initialize(params = {}) ⇒ Model

Creates instance variable for each model attribute defined by the schema. Initializes any attribute values that are passed in via the params hash and then initializes the @attributes instance variable.

Any key/value pair in params whose key is not an attribute (i.e. :id or :define_collection_name) is passed on to the superclass.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/orchestrate_rails/model.rb', line 26

def initialize(params={})super(params)
  # Define accessor and query methods for each attribute.
  attrs.each do |attribute|
    self.class.send :attr_accessor, attribute
    define_attr_query attribute
  end

  # Set instance variables and initialize @attributes with any
  # attribute values that were passed in the params hash.
  @attributes = {}
  params.each do |k,v|
    if attrs.include? k.to_s
      send("#{k}=", v)
      @attributes[k] = v
    end
  end
end

Class Method Details

.allObject

Returns ordered array of all instances in the collection.



351
352
353
354
# File 'lib/orchestrate_rails/model.rb', line 351

def self.all
  res = list
  (res.success?) ? res.results : false
end

.attributesObject



293
294
295
# File 'lib/orchestrate_rails/model.rb', line 293

def self.attributes
  new.attributes
end

.attrsObject

Returns array of model attribute names.



289
290
291
# File 'lib/orchestrate_rails/model.rb', line 289

def self.attrs
  schema.attrs ocollection
end

.create(key_value_pairs) ⇒ Object

Creates a new instance; updates the collection if the primary_key is not already present in the collection.

Returns the instance upon success; false upon failure.



317
318
319
# File 'lib/orchestrate_rails/model.rb', line 317

def self.create(key_value_pairs)
  new(key_value_pairs).save_if_none_match
end

.create!(key_value_pairs) ⇒ Object

Creates a new instance; updates the collection.

Returns the instance upon success; false upon failure.



324
325
326
# File 'lib/orchestrate_rails/model.rb', line 324

def self.create!(key_value_pairs)
  new(key_value_pairs).save!
end

.destroy(id) ⇒ Object

Deletes the specified instance from the collection.

Returns boolean status.



331
332
333
# File 'lib/orchestrate_rails/model.rb', line 331

def self.destroy(id)
  new(:id => id).destroy
end

.destroy!(id) ⇒ Object

Deletes the specified instance and purges all of its immutable data from the collection.

Returns boolean status.



339
340
341
# File 'lib/orchestrate_rails/model.rb', line 339

def self.destroy!(id)
  new(:id => id).destroy!
end

.destroy_allObject

Deletes the entire collection.

Returns boolean status.



346
347
348
# File 'lib/orchestrate_rails/model.rb', line 346

def self.destroy_all
  orchio_delete ocollection
end

.exists?(id) ⇒ Boolean

Returns boolean to indicate whether the specified primary_key exists in the collection.

Returns:

  • (Boolean)


375
376
377
# File 'lib/orchestrate_rails/model.rb', line 375

def self.exists?(id)
  find(id) ? true : false
end

.find(arg) ⇒ Object

Find by the primary_key (id). Can be a specific id, or an array of ids.

Returns instance, or array of instances, accordingly.



382
383
384
385
386
387
388
# File 'lib/orchestrate_rails/model.rb', line 382

def self.find(arg)
  if arg.is_a? Integer or arg.is_a? String
    new(:id => arg).get
  elsif arg.is_a? Array
    arg.map { |id| new(:id => id).get }
  end
end

.find_by(key_value_pairs) ⇒ Object

Returns the first instance that matches the specified criteria.



396
397
398
# File 'lib/orchestrate_rails/model.rb', line 396

def self.find_by(key_value_pairs)
  where(key_value_pairs).first
end

.find_by_method(myattrs, *args, &block) ⇒ Object

Calls ::find_by for properly constructed ‘find_by_attribute(s)’ calls.

Example: User.find_by_name_and_address(name, address) is executed as:

User.find_by(:name => name, :address => address)



406
407
408
409
410
# File 'lib/orchestrate_rails/model.rb', line 406

def self.find_by_method(myattrs, *args, &block)
  attrs_with_args = [myattrs.split('_and_'), args].transpose
  attrs_with_args.each { |awa| return unless attrs.include? awa.first }
  find_by Hash[attrs_with_args]
end

.firstObject

Returns the first (ordered) instance in the collection.



357
358
359
360
# File 'lib/orchestrate_rails/model.rb', line 357

def self.first
  res = list(1)
  (res.success?) ? res.results.first : false
end

.lastObject

Returns the last (ordered) instance in the collection.



363
364
365
# File 'lib/orchestrate_rails/model.rb', line 363

def self.last
  all.last
end

.list(limit = :all, start_key = nil, after_key = nil) ⇒ Object

Returns Orchestrate::Application::Result.

The start index may be optionally specified by using either start_key (inclusive) or after_key (exclusive). The default is the first primary key in the collection.



471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'lib/orchestrate_rails/model.rb', line 471

def self.list(limit=:all, start_key=nil, after_key=nil)
  if limit == :all
    total_count = 0
    max = 100
    result = orchio_list ocollection, "?limit=#{max}"
    count = result.count
    docs = result.results
    while result.next
      result = orchio_list ocollection, "?#{result.next.split('?').last}"
      docs += result.results
      count += result.count
    end
    result = Orchestrate::Application::Result.new(
      results:  docs,
      count:    count,
      status:   result.status,
      response: result.response
    )
  else
    option_str = "?limit=#{limit}"
    option_str += "&startKey=#{start_key}" if start_key and after_key.nil?
    option_str += "&afterKey=#{after_key}" if after_key and start_key.nil?
    result = orchio_list ocollection, option_str
  end
  result.results.map! { |odoc| odoc.to_rails }
  result
end

.method_missing(name, *args, &block) ⇒ Object

Calls ::find_by_method for ‘find_by_attribute(s)’.



413
414
415
416
417
418
419
# File 'lib/orchestrate_rails/model.rb', line 413

def self.method_missing(name, *args, &block)
  if name.to_s =~ /^find_by_(.+)$/
    find_by_method($1, *args, &block) || super
  else
    super
  end
end

.ocollectionObject

:stopdoc:



500
501
502
# File 'lib/orchestrate_rails/model.rb', line 500

def self.ocollection
  schema.get_collection_from_class(self.name).name
end

.propertiesObject

Returns array of property names.

Property names are the original key names in json documents stored in orchestrate collections - before they are converted to the snake_case style used for model attribute names. Attribute names are mapped to property names using ::qmap. Property names can be mapped to attribute names with ::Symbol#to_orchio_rails_attr or ::String#to_orchio_rails_attr.



306
307
308
# File 'lib/orchestrate_rails/model.rb', line 306

def self.properties
  schema.properties(ocollection).select { |prop| prop !~ /id/i }
end

.qmapObject

Returns the table that maps attribute names to property names.

This mapping also works when the input is a property name.



284
285
286
# File 'lib/orchestrate_rails/model.rb', line 284

def self.qmap
  schema.qmap ocollection
end

.respond_to?(name) ⇒ Boolean

Handles find_by_attribute methods.

Returns:

  • (Boolean)


422
423
424
# File 'lib/orchestrate_rails/model.rb', line 422

def self.respond_to?(name)
  (attributes.include?(name) and name.to_s =~ /^find_by_.*$/) or super
end

.search(query_str, limit = :all, offset = 0) ⇒ Object

Returns SearchResult. Orchestrate.io search implements Lucene Query Parser Syntax.



436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/orchestrate_rails/model.rb', line 436

def self.search(query_str, limit=:all, offset=0)
  query_str = orchio_query_str(query_str) unless query_str == '*'
  if limit == :all
    total_count = offset + 1
    max = 100
    qdocs = []
    while offset < total_count
      qresult = orchio_search(
        ocollection, "#{query_str}&limit=#{max}&offset=#{offset}"
      )
      offset += qresult.count
      total_count = qresult.total_count
      qdocs += qresult.results
    end
    qresult = SearchResult.new(
      results:     qdocs,
      count:       offset,
      total_count: total_count,
      status:      qresult.status,
      response:    qresult.response
    )
  else
    qresult = orchio_search(
      ocollection, "#{query_str}&limit=#{limit}&offset=#{offset}"
    )
  end
  qresult.results.map! { |odoc| odoc.to_rails }
  qresult
end

.search_results(query_str) ⇒ Object

Returns array of model instances that match the query string.



429
430
431
432
# File 'lib/orchestrate_rails/model.rb', line 429

def self.search_results(query_str)
  res = search(query_str)
  (res.success?) ? res.results : false
end

.takeObject

Returns the first (random) instance in the collection.



368
369
370
371
# File 'lib/orchestrate_rails/model.rb', line 368

def self.take
  res = search('*', 1)
  (res.success?) ? res.results.first : false
end

.where(key_value_pairs) ⇒ Object

Returns all instances that match the specified criteria.



391
392
393
# File 'lib/orchestrate_rails/model.rb', line 391

def self.where(key_value_pairs)
  search_results(key_value_pairs.map{ |k,v| "#{k}:#{v}" }.join(' AND '))
end

Instance Method Details

#all_eventsObject

:stopdoc:



192
193
194
# File 'lib/orchestrate_rails/model.rb', line 192

def all_events
  event_types.map { |etype| events(etype) }
end

#all_graphsObject

:stopdoc:



223
224
225
# File 'lib/orchestrate_rails/model.rb', line 223

def all_graphs
  graphs.map { |kind| graph kind }
end

#attributesObject

Returns hash of key/value pairs.



63
64
65
# File 'lib/orchestrate_rails/model.rb', line 63

def attributes
  @attributes = Hash[attrs.map { |a| [a.to_sym, send("#{a}")] }]
end

#attrsObject

Returns array of model attribute names.



58
59
60
# File 'lib/orchestrate_rails/model.rb', line 58

def attrs
  self.class.attrs
end

#create_event(event_type, timestamp = nil, event_rec) ⇒ Object

Creates event instance; calls #save_event to update the collection.

Returns the event instance upon success; false upon failure.



215
216
217
# File 'lib/orchestrate_rails/model.rb', line 215

def create_event(event_type, timestamp=nil, event_rec)
  save_event event_type, timestamp, Event.new(event_rec)
end

#delete_graph(kind, to_collection, to_key) ⇒ Object

Removes the specified relation from the graph.

Returns boolean status.



244
245
246
# File 'lib/orchestrate_rails/model.rb', line 244

def delete_graph(kind, to_collection, to_key)
  retval orchio_delete_graph kind, to_collection, to_key
end

#destroyObject

Deletes the current primary_key from the collection. Calls #orchio_delete

Returns boolean status.



176
177
178
# File 'lib/orchestrate_rails/model.rb', line 176

def destroy
  orchio_delete
end

#destroy!Object

Deletes the current primary_key and purges all of its immutable data from the collection.

Returns boolean status.



184
185
186
# File 'lib/orchestrate_rails/model.rb', line 184

def destroy!
  orchio_purge
end

#events(event_type, timestamp = {}) ⇒ Object

Returns array of event instances specified by event_type and timestamp range,

where the timestamp range is specified as { :start => start, :end => end }



200
201
202
203
# File 'lib/orchestrate_rails/model.rb', line 200

def events(event_type, timestamp={})
  res = orchio_get_events(event_type, timestamp)
  (res.success?) ? res.results.map { |odoc| odoc.to_event } : false
end

#getObject

Returns the key/value data for the current instance.



102
103
104
105
# File 'lib/orchestrate_rails/model.rb', line 102

def get
  res = orchio_get
  (res.success?) ? res.result.update_rails(self) : false
end

#get_by_ref(ref) ⇒ Object

Returns the key/value data for the current instance, found by ref value.



109
110
111
112
# File 'lib/orchestrate_rails/model.rb', line 109

def get_by_ref(ref)
  res = orchio_get_by_ref ref
  (res.success?) ? res.result.update_rails(self) : false
end

#graph(kind) ⇒ Object

Returns array of instances associated with the specified kind of relation.



229
230
231
232
# File 'lib/orchestrate_rails/model.rb', line 229

def graph(kind)
  res = orchio_get_graph(kind)
  (res.success?) ? res.results.map { |odoc| odoc.to_rails } : false
end

#orchestrate_collection_nameObject

Returns the collection name for the current instance.



77
78
79
# File 'lib/orchestrate_rails/model.rb', line 77

def orchestrate_collection_name
  ocollection
end

#orchestrate_ref_valueObject

Returns the ref value for the current instance. The ref value is an immutable value assigned to each version of primary_key data in an orchestrate.io collection.



84
85
86
# File 'lib/orchestrate_rails/model.rb', line 84

def orchestrate_ref_value
  __ref_value__
end

#propertiesObject

:stopdoc:



68
69
70
# File 'lib/orchestrate_rails/model.rb', line 68

def properties
  self.class.properties
end

#qmapObject



273
274
275
# File 'lib/orchestrate_rails/model.rb', line 273

def qmap
  self.class.qmap
end

#read_attribute_for_serialization(attribute) ⇒ Object

Called by ActiveModel::Serialization



50
51
52
# File 'lib/orchestrate_rails/model.rb', line 50

def read_attribute_for_serialization(attribute)
  instance_variable_get("@#{attribute}")
end

#read_attribute_for_validation(attribute) ⇒ Object

Called by ActiveModel::Validation



45
46
47
# File 'lib/orchestrate_rails/model.rb', line 45

def read_attribute_for_validation(attribute)
  instance_variable_get("@#{attribute}")
end

#saveObject

Calls #save_if_match.



135
136
137
# File 'lib/orchestrate_rails/model.rb', line 135

def save
  save_if_match
end

#save!Object

Updates the collection with current instance data.

Returns the instance upon success; false upon failure.



142
143
144
145
# File 'lib/orchestrate_rails/model.rb', line 142

def save!
  status = orchio_put(to_json_direct) if valid?
  retval status
end

#save_event(event_type, timestamp = nil, event) ⇒ Object

Updates the collection with the specified event instance.

Returns the event instance upon success; false upon failure.



208
209
210
# File 'lib/orchestrate_rails/model.rb', line 208

def save_event(event_type, timestamp=nil, event)
  retval orchio_put_event(event_type, timestamp, event.to_json), event
end

#save_graph(kind, to_collection, to_key) ⇒ Object

Updates the collection with the specified graph relation.

Returns boolean status.



237
238
239
# File 'lib/orchestrate_rails/model.rb', line 237

def save_graph(kind, to_collection, to_key)
  retval orchio_put_graph(kind, to_collection, to_key)
end

#save_if_matchObject

Updates the collection with current instance data, if the ref value matches the ref value associated with the same primary_key in the collection.

Returns the instance upon success; false upon failure.



129
130
131
132
# File 'lib/orchestrate_rails/model.rb', line 129

def save_if_match
  status = orchio_put_if_match(to_json_direct, __ref_value__) if valid?
  retval status
end

#save_if_none_matchObject

Updates the collection with current instance data, if the primary_key (id) does not exist in the collection.

Returns the instance upon success; false upon failure.



118
119
120
121
# File 'lib/orchestrate_rails/model.rb', line 118

def save_if_none_match
  status = orchio_put_if_none_match(to_json_direct) if valid?
  retval status
end

#to_properties(json_str) ⇒ Object

:stopdoc:



267
268
269
270
271
# File 'lib/orchestrate_rails/model.rb', line 267

def to_properties(json_str)
  keys = json_str.scan(/\"(\w+)\":/).map { |result| result.first }
  keys.each { |key| json_str.gsub!(/\"#{key}\":/, "\"#{qmap[key]}\":") }
  json_str
end

#update_attribute(key, value) ⇒ Object

Updates the attribute and calls #save_if_match.



148
149
150
151
# File 'lib/orchestrate_rails/model.rb', line 148

def update_attribute(key, value)
  instance_variable_set "@#{key}", value
  save_if_match
end

#update_attribute!(key, value) ⇒ Object

:stopdoc: Updates the attribute and calls #save!. Use with caution!!!



161
162
163
164
# File 'lib/orchestrate_rails/model.rb', line 161

def update_attribute!(key, value)
  instance_variable_set "@#{key}", value
  save!
end

#update_attributes(key_value_pairs) ⇒ Object

Updates the attributes and calls #save_if_match.



154
155
156
157
# File 'lib/orchestrate_rails/model.rb', line 154

def update_attributes(key_value_pairs)
  key_value_pairs.each { |k,v| instance_variable_set "@#{k}", v }
  save_if_match
end

#update_attributes!(key_value_pairs) ⇒ Object

Updates the attributes and calls #save!. Use with caution!!!



167
168
169
170
# File 'lib/orchestrate_rails/model.rb', line 167

def update_attributes!(key_value_pairs)
  key_value_pairs.each { |k,v| instance_variable_set "@#{k}", v }
  save!
end