module ODBA::Persistable
Constants
- Exact
- Find
- ODBA_EXCLUDE_VARS
-
Classes which include
Persistable
may overrideODBA_EXCLUDE_VARS
to prevent data from being stored in the database (e.g. passwords, file descriptors). Simply redefine:ODBA_EXCLUDE_VARS
= [‘@foo’] - ODBA_PREFETCH
- ODBA_SERIALIZABLE
-
If you want to prevent Persistables from being disconnected and stored separately (
Array
andHash
arePersistable
by default), redefine:ODBA_SERIALIZABLE
= [‘@bar’]
Attributes
Classes which include Persistable
have a class-method ‘odba_index’
Public Class Methods
Source
# File lib/odba/persistable.rb, line 32 def Persistable.append_features(mod) super mod.module_eval { class << self def odba_index(*keys) require 'odba/index_definition' origin_klass = self resolve_origin = nil resolve_target = :none resolve = {} opts = {} if(keys.size > 1) if(keys.last.is_a?(Hash)) opts = keys.pop end if(keys.last.is_a?(Class)) origin_klass = keys.pop resolve = keys.pop resolve_origin = keys.pop elsif(keys.last.is_a?(Symbol)) keys.each { |key| resolve.store(key, {'resolve' => key}) } else resolve = keys.pop end else resolve = keys.first end keys.each { |key| if RUBY_VERSION >= '1.9' key = key.to_sym else key = key.to_s end unless(instance_methods.include?(key)) attr_accessor key end } index_prefix = self.name.downcase.gsub(/::/, '_') index_suffix = Persistable.sanitize(keys.join('_and_')) index_name = sprintf("%s_%s", index_prefix, index_suffix) search_name = sprintf("search_by_%s", index_suffix) exact_name = sprintf("search_by_exact_%s", index_suffix) find_name = sprintf("find_by_%s", index_suffix) keys_name = sprintf("%s_keys", index_suffix) index_definition = IndexDefinition.new index_definition.index_name = index_name index_definition.origin_klass = origin_klass index_definition.target_klass = self index_definition.resolve_search_term = resolve index_definition.resolve_origin = resolve_origin.to_s index_definition.resolve_target = resolve_target opts.each { |key, val| index_definition.send "#{key}=", val } ODBA.cache.ensure_index_deferred(index_definition) meta_eval { define_method(search_name) { |*vals| if(vals.size > 1) args = {} vals.each_with_index { |val, idx| cond = case val when Numeric, Date '=' else 'like' end args.store(keys.at(idx), { 'value' => val, 'condition' => cond }) } ODBA.cache.retrieve_from_index(index_name, args) else ODBA.cache.retrieve_from_index(index_name, vals.first) end } define_method(exact_name) { |*vals| if(vals.size > 1) args = {} vals.each_with_index { |val, idx| args.store(keys.at(idx), val) } ODBA.cache.retrieve_from_index(index_name, args, ODBA::Persistable::Exact) else ODBA.cache.retrieve_from_index(index_name, vals.first, ODBA::Persistable::Exact) end } define_method(find_name) { |*vals| if(vals.size > 1) args = {} vals.each_with_index { |val, idx| cond = case val when Numeric, Date '=' else 'like' end args.store(keys.at(idx), { 'value' => val, 'condition' => cond }) } ODBA.cache.retrieve_from_index(index_name, args, ODBA::Persistable::Find) else ODBA.cache.retrieve_from_index(index_name, vals.first, ODBA::Persistable::Find) end.first } define_method(keys_name) { |*vals| # TODO fix this for fulltext and condition indices length, = vals ODBA.cache.index_keys(index_name, length) } } index_definition end def odba_extent all = ODBA.cache.extent(self) if(block_given?) all.each { |instance| yield instance } nil else all end end def odba_count ODBA.cache.count(self) end end } end
Source
# File lib/odba/persistable.rb, line 156 def odba_count ODBA.cache.count(self) end
Source
# File lib/odba/persistable.rb, line 147 def odba_extent all = ODBA.cache.extent(self) if(block_given?) all.each { |instance| yield instance } nil else all end end
Source
# File lib/odba/persistable.rb, line 36 def odba_index(*keys) require 'odba/index_definition' origin_klass = self resolve_origin = nil resolve_target = :none resolve = {} opts = {} if(keys.size > 1) if(keys.last.is_a?(Hash)) opts = keys.pop end if(keys.last.is_a?(Class)) origin_klass = keys.pop resolve = keys.pop resolve_origin = keys.pop elsif(keys.last.is_a?(Symbol)) keys.each { |key| resolve.store(key, {'resolve' => key}) } else resolve = keys.pop end else resolve = keys.first end keys.each { |key| if RUBY_VERSION >= '1.9' key = key.to_sym else key = key.to_s end unless(instance_methods.include?(key)) attr_accessor key end } index_prefix = self.name.downcase.gsub(/::/, '_') index_suffix = Persistable.sanitize(keys.join('_and_')) index_name = sprintf("%s_%s", index_prefix, index_suffix) search_name = sprintf("search_by_%s", index_suffix) exact_name = sprintf("search_by_exact_%s", index_suffix) find_name = sprintf("find_by_%s", index_suffix) keys_name = sprintf("%s_keys", index_suffix) index_definition = IndexDefinition.new index_definition.index_name = index_name index_definition.origin_klass = origin_klass index_definition.target_klass = self index_definition.resolve_search_term = resolve index_definition.resolve_origin = resolve_origin.to_s index_definition.resolve_target = resolve_target opts.each { |key, val| index_definition.send "#{key}=", val } ODBA.cache.ensure_index_deferred(index_definition) meta_eval { define_method(search_name) { |*vals| if(vals.size > 1) args = {} vals.each_with_index { |val, idx| cond = case val when Numeric, Date '=' else 'like' end args.store(keys.at(idx), { 'value' => val, 'condition' => cond }) } ODBA.cache.retrieve_from_index(index_name, args) else ODBA.cache.retrieve_from_index(index_name, vals.first) end } define_method(exact_name) { |*vals| if(vals.size > 1) args = {} vals.each_with_index { |val, idx| args.store(keys.at(idx), val) } ODBA.cache.retrieve_from_index(index_name, args, ODBA::Persistable::Exact) else ODBA.cache.retrieve_from_index(index_name, vals.first, ODBA::Persistable::Exact) end } define_method(find_name) { |*vals| if(vals.size > 1) args = {} vals.each_with_index { |val, idx| cond = case val when Numeric, Date '=' else 'like' end args.store(keys.at(idx), { 'value' => val, 'condition' => cond }) } ODBA.cache.retrieve_from_index(index_name, args, ODBA::Persistable::Find) else ODBA.cache.retrieve_from_index(index_name, vals.first, ODBA::Persistable::Find) end.first } define_method(keys_name) { |*vals| # TODO fix this for fulltext and condition indices length, = vals ODBA.cache.index_keys(index_name, length) } } index_definition end
Source
# File lib/odba/persistable.rb, line 163 def Persistable.sanitize(name) name.gsub(@@sanitize_ptrn, '_') end
Public Instance Methods
Source
# File lib/odba/persistable.rb, line 202 def odba_add_observer(obj) odba_observers.push(obj) obj end
Add an observer for Cache#store(self)
, Cache#delete(self)
and Cache#clean removing the object from the Cache
Source
# File lib/odba/persistable.rb, line 211 def odba_cut_connection(remove_object) odba_potentials.each { |name| var = instance_variable_get(name) if(var.eql?(remove_object)) instance_variable_set(name, nil) end } end
Removes all connections to another persistable. This method is called by the Cache
server when remove_object is deleted from the database
Source
# File lib/odba/persistable.rb, line 221 def odba_delete ODBA.cache.delete(self) end
Permanently deletes this Persistable
from the database and remove all connections to it
Source
# File lib/odba/persistable.rb, line 226 def odba_delete_observer(observer) @odba_observers.delete(observer) if(@odba_observers) end
Delete observer as an observer on this object. It will no longer receive notifications.
Source
# File lib/odba/persistable.rb, line 230 def odba_delete_observers @odba_observers = nil end
Delete all observers associated with this object.
Source
# File lib/odba/persistable.rb, line 265 def odba_id @odba_id ||= ODBA.cache.next_id end
Returns the odba unique id of this Persistable
. If no id had been assigned, this is now done. No attempt is made to store the Persistable
in the db.
Source
# File lib/odba/persistable.rb, line 272 def odba_isolated_store @odba_persistent = true ODBA.cache.store(self) end
Convenience method equivalent to ODBA.cache
.store(self)
Source
# File lib/odba/persistable.rb, line 278 def odba_isolated_stub Stub.new(self.odba_id, nil, self) end
Returns a new instance of Stub
, which can be used as a stand-in replacement for this Persistable
.
Source
# File lib/odba/persistable.rb, line 283 def odba_isolated_twin # ensure a valid odba_id self.odba_id twin = self.odba_dup twin.odba_replace_persistables twin.odba_replace_excluded! twin end
Returns a duplicate of this Persistable
, for which all connected Persistables have been replaced by a Stub
Source
# File lib/odba/persistable.rb, line 307 def odba_notify_observers(*args) odba_observers.each { |obs| obs.odba_update(*args) } end
Invoke the update method in each currently associated observer in turn, passing it the given arguments
Source
# File lib/odba/persistable.rb, line 310 def odba_observers @odba_observers ||= [] end
Source
# File lib/odba/persistable.rb, line 296 def odba_prefetch? @odba_prefetch ||= nil @odba_prefetch \ || (defined?(self::class::ODBA_PREFETCH) && self::class::ODBA_PREFETCH) end
A Persistable
instance can be prefetchable. This means that the object can be loaded at startup by calling ODBA.cache
.prefetch, and that it will never expire from the Cache
. The prefetch status can be controlled per instance by setting the instance variable @odba_prefetch, and per class by overriding the module constant ODBA_PREFETCH
Source
# File lib/odba/persistable.rb, line 376 def odba_store(name = nil) begin unless (name.nil?) old_name = @odba_name @odba_name = name end odba_store_unsaved self rescue @odba_name = old_name raise end end
Stores this Persistable
and recursively all connected unsaved persistables, until no more direcly connected unsaved persistables can be found. The optional parameter name can be used later to retrieve this Persistable
using Cache#fetch_named
Source
# File lib/odba/persistable.rb, line 427 def odba_take_snapshot @odba_snapshot_level ||= 0 snapshot_level = @odba_snapshot_level.next current_level = [self] tree_level = 0 while(!current_level.empty?) tree_level += 1 obj_count = 0 next_level = [] current_level.each { |item| if(item.odba_unsaved?(snapshot_level)) obj_count += 1 next_level += item.odba_unsaved_neighbors(snapshot_level) item.odba_snapshot(snapshot_level) end } current_level = next_level #.uniq end end
Recursively stores all connected Persistables.
Protected Instance Methods
Source
# File lib/odba/persistable.rb, line 476 def odba_replace_excluded! odba_exclude_vars.each { |name| instance_variable_set(name, nil) } end