Class: Poro::Contexts::MongoContext

Inherits:
Poro::Context show all
Includes:
FinderMethods
Defined in:
lib/poro/contexts/mongo_context.rb,
lib/poro/contexts/mongo_context.rb,
lib/poro/contexts/mongo_context.rb

Overview

The MongoDB Context Adapter.

Manages an object in MongoDB.

WARNING: At this time, only objects that follow nice tree hierarchies can be encoded. Cyclical loops cannot be auto-encoded, and need embedded objects to be managed with the parent pointers blacklisted.

WARNING: Embedded objects of the same kind–which are referenced via a DBRef, are re-fetched and re-saved every time the managing object is fetched or saved.

This adapter recursively encodes the object according to the following rules for each instance variable’s value:

  1. If the object can be saved as a primitive, save it that way.

  2. If the object is managed by a Mongo context, save and encode it as a DBRef.

  3. If the object is managed by another context, save and store the class and id in a hash.

  4. Otherwise, encode all instance variables and the class, in a Hash.

For Mongo represented objects, the instance variables that are encoded can be controlled via any combination of the save_attributes and save_attributes_blacklist properties. The Context will start with the save attributes (which defaults to all the instance variables), and then subtract out the attributes in the blacklist. Thus the blacklist takes priority.

Defined Under Namespace

Modules: FinderMethods

Constant Summary collapse

@@collection_map =

A map of all the collection names registered for this kind of context. This is to facilitate DBRef dereferencing.

{}

Instance Attribute Summary collapse

Attributes inherited from Poro::Context

#data_store, #klass, #primary_key

Instance Method Summary collapse

Methods included from FinderMethods

#data_store_cursor

Methods inherited from Poro::Context

configure_for_class, factory, factory=, factory?, fetch, managed_class?, #primary_key_value, #set_primary_key_value

Methods included from Poro::Context::CallbackMethods

#callbacks, #clear_callbacks, #register_callback

Methods included from Poro::Context::FindMethods

#data_store_find, #find, included

Constructor Details

#initialize(klass) ⇒ MongoContext

Takes the class for the context, and optionally the collection object up front. This can be changed at any time by setting the data store for the Context.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/poro/contexts/mongo_context.rb', line 38

def initialize(klass)
  # Require mongo.  We do it here so that it is only required when
  # we use this.  (How does this affect speed?  It seems this takes 1/30000 of a second.)
  require 'mongo'
  
  # Set-up the lists.
  @persistent_attributes_whitelist = nil
  @persistent_attributes_blacklist = nil
  
  # Some configuration variables
  @encode_symbols = false
  @attempt_id_conversion = true
  @set_encoding_method = :embedded_array
  
  
  # Initialize
  super(klass)
end

Instance Attribute Details

#attempt_id_conversionObject

Normally, one uses BSON::ObjectId instances for the IDs on a stored Mongo object. However, one can design a database to use many different values as sthe primary key.

When this is set to true, fetch tries to convert the given ID into a BSON::ObjectId before doing a fetch. If the conversion fails, it tries using the raw value given. If this is set to false, then it always passes along the raw value, skipping the conversion step.



88
89
90
# File 'lib/poro/contexts/mongo_context.rb', line 88

def attempt_id_conversion
  @attempt_id_conversion
end

#encode_symbolsObject

If true, it encodes Symbol as a hash with a class name property, and then decodes them back into Symbol. If false, it converts them to String for storage. Defaults to false.

While one would think they want to preserve the type of the saved element, the change in storage method makes it harder to write Mongo queries on the data. Thus it is normally best to save symbols as strings for storage.



77
78
79
# File 'lib/poro/contexts/mongo_context.rb', line 77

def encode_symbols
  @encode_symbols
end

#persistent_attributes_blacklistObject

Returns the value of attribute persistent_attributes_blacklist.



67
68
69
# File 'lib/poro/contexts/mongo_context.rb', line 67

def persistent_attributes_blacklist
  @persistent_attributes_blacklist
end

#persistent_attributes_whitelistObject

Returns the value of attribute persistent_attributes_whitelist.



64
65
66
# File 'lib/poro/contexts/mongo_context.rb', line 64

def persistent_attributes_whitelist
  @persistent_attributes_whitelist
end

Instance Method Details

#convert_to_data(obj, state_info = {}) ⇒ Object



125
126
127
128
129
130
131
132
# File 'lib/poro/contexts/mongo_context.rb', line 125

def convert_to_data(obj, state_info={})
  transformed_obj = callback_transform(:before_convert_to_data, obj)
  
  data = route_encode(transformed_obj, state_info)
  
  callback_event(:after_convert_to_data, data)
  return data
end

#convert_to_plain_object(data, state_info = {}) ⇒ Object



114
115
116
117
118
119
120
121
122
123
# File 'lib/poro/contexts/mongo_context.rb', line 114

def convert_to_plain_object(data, state_info={})
  transformed_data = callback_transform(:before_convert_to_plain_object, data)
  
  # If it is a root record, and it has no class name, assume this context's class name.
  transformed_data['_class_name'] = self.klass if( transformed_data && transformed_data.kind_of?(Hash) && !state_info[:embedded] )
  obj = route_decode(transformed_data, state_info)
  
  callback_event(:after_convert_to_plain_object, obj)
  return obj
end

#data_store=(collection) ⇒ Object

Set the data store to the given collection.



58
59
60
61
62
# File 'lib/poro/contexts/mongo_context.rb', line 58

def data_store=(collection)
  @@collection_map.delete(self.data_store && self.data_store.name) # Clean-up the old record in case we change names.
  @@collection_map[collection.name] = self unless collection.nil? # Create the new record.
  super(collection)
end

#fetch(id) ⇒ Object



91
92
93
94
95
96
# File 'lib/poro/contexts/mongo_context.rb', line 91

def fetch(id)
  data = data_store.find_one( clean_id(id) )
  obj = convert_to_plain_object(data)
  callback_event(:after_fetch, obj)
  return obj
end

#remove(obj) ⇒ Object



107
108
109
110
111
112
# File 'lib/poro/contexts/mongo_context.rb', line 107

def remove(obj)
  callback_event(:before_remove, obj)
  data_store.remove( {'_id' => primary_key_value(obj)} )
  callback_event(:after_remove, obj)
  return obj
end

#save(obj) ⇒ Object



98
99
100
101
102
103
104
105
# File 'lib/poro/contexts/mongo_context.rb', line 98

def save(obj)
  callback_event(:before_save, obj)
  data = convert_to_data(obj)
  data_store.save(data)
  set_primary_key_value(obj, (data['_id'] || data[:_id])) # The pk generator uses a symbol, while everything else uses a string!
  callback_event(:after_save, obj)
  return obj
end