Class: TinkitNodeFactory
- Inherits:
-
Object
- Object
- TinkitNodeFactory
- Defined in:
- lib/tinkit_node_factory.rb
Overview
The factory for building Tinkit Classes. Each Tinkit class is roughly equivalent to other ORM classes (Rails, Couchrest, etc).
It has class methods for operating across the entire collection, and each instance of that class is an individual node. So:
SomeTinkitClass.all #=> returns all records maintained by SomeTinkitClass as Tinkit nodes
some_tinkit_node = SomeTinkitClass.all.first
yet_another_tinkit_node = SomeTinkitClass.find_node_where(:my_data, :contains, "foo").first
another_tinkit_node = SomeTinkitClass.get(node_primary_key_value)
Note on record/node terminology. Records and Nodes are essentially a collection of data that corresponds to an instance of
the Tinkit class. The difference is that I try to use the term "record" when referring to the persisted layer data object, and
node when referring to the Tinkit wrapped data object.
Constant Summary collapse
Class Method Summary collapse
-
.env_formatter(model_name, node_class_id, user_id, path, host = nil) ⇒ Object
Some sugar to help contruct a node environment.
-
.make(node_env) ⇒ Object
Builds the class from the provided environment the environment takes the following form :node_class_id - The Name of the class to create :persist_model - Information to model the user data in the persistence layer :env - Information to set up the persistence layer.
Class Method Details
.env_formatter(model_name, node_class_id, user_id, path, host = nil) ⇒ Object
Some sugar to help contruct a node environment. It will put properly format supplied data. Note that the model name must already be defined as a model in the glue_env! TODO: Add to specs
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/tinkit_node_factory.rb', line 26 def self.env_formatter(model_name, node_class_id, user_id, path, host = nil) #binding data (note this occurs in two different places in the env) key_fields = {:required_keys => [:id], :primary_key => :id } #data model field_op_set =nil #op_set_mod => <Using default definitions> data_model = {:field_op_set => field_op_set, :key_fields => key_fields, :views => nil} #persistence layer model pmodel_env = { :host => host, :path => path, :user_id => user_id} persist_model = {:name => model_name, :env => pmodel_env} #final env model env = { :node_class_id => node_class_id, :data_model => data_model, :persist_model => persist_model } end |
.make(node_env) ⇒ Object
Builds the class from the provided environment the environment takes the following form
:node_class_id - The Name of the class to create
:persist_model - Information to model the user data in the persistence layer
:env - Information to set up the persistence layer
:persist_model fields
:name - The name of the persistence layer to use.
This name must match one of the persistent layers "glue" environments
Out of the box, tinkit currently supports
:filesystem - basic filesystem interface (linux only right now)
:couchrest - interface to CouchDB, requires a CouchDB instance (will work with CouchOne as well)
:mysql - interface to a MySQL instance (I've only tested local mysql instances)
:sdb_s3 - interface to Amazon Web Services databases, requires AWS account (SDB for node data, S3 for files)
other persistent layers can be supported and added by creating the appropriate plugin in the glue_envs directory
:key_fields - Identifies the primary key and any required keys. There can only be a single primary key, but multiple required keys
:primary_key - The data that identifies the node. This key must be unique for each node within the tinkit node class
:required_keys - List of keys required, should contain primary key.
:env fields
:user_id - This id is propagated to the persistence layer to segregate content into different contexts if necessary. A classic
example would be to give multiple users there own segregated persistence layer, before segregating by tinkit class.
Important note: persistent layer context segregation is not enforced in the tinkit runtime environment. This means that if I
used the same node_class_id for two different user_ids in the same runtime instance of tinkit, name collisions
would occur. In other words, if user_ids :batman and :robin both had class ids of :BatCloset, then the contents
and location of :BatCloset will be unpredictable (roughly similar to multi-thread behavior in a unsafe thread environment)
Having :batman with :BatmanCloset, and :robin with :RobinCloset would work fine, and if a shared closet was needed, you
could create a class called :SharedCloset (user_id doesn't matter) and progamattically update it as dictated by application needs.
tl;dr: Don't duck punch yourself.
:path - Persistence layer location. The particulars vary by persistence layer, but in general it says "this is where the persistence layer is gonna live"
filesystem - The path to the directory for all tinkit persisted data (created if it doesn't exist)
couchrest - The URL of the couchrest database to use (error if there is no CouchDB at that location)
mysql - A name prepended to mysql tables to keep tables unique (created if it doesn't exist)
sdb_s3 - Simple DB domain (created if it doesn't exist)
Example:
env = {:node_class_id => "HelloWorldClass",
:persist_model => {
:name => "filesystem",
:key_fields => {
:required_keys => [:id],
:primary_key => :id,
},
:env => {
:user_id => "me",
:path => "/tmp/tinkit_hello_world_test/"
}
}
}
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/tinkit_node_factory.rb', line 105 def self.make(node_env) TinkitLog.log_raise "No Node Environment provided" unless node_env TinkitLog.log_raise "Empty Node Environment provided" if node_env.empty? TinkitLog.log_raise "Malformed Node Environment" unless node_env.respond_to?(:keys) TinkitLog.log_raise "Malformed Node Environment" unless node_env.keys.include? :persist_model #TODO: Make setting the environment thread safe #__user_doc_class_name = node_env[:node_class_id] user_doc_class_name = "Tinkit::#{node_env[:node_class_id]}" #Security TODO: remove spaces and other pototential injection issues #---- Dynamic Class Definitions ---- dyn_user_class_def = "class #{user_doc_class_name} < TinkitBaseNode class << self; attr_accessor :user_attachClass, end end" #Create the Tinkit Class TinkitNodeFactory.class_eval(dyn_user_class_def) docClass = Tinkit.const_get(node_env[:node_class_id]) #TODO: Streamline the paramaters (maybe one env paramater?) class_environment = node_env[:persist_model] neo_env = node_env[:data_model] || {} neo = NodeElementOperations.new(neo_env) docClass.data_struc = neo #TODO: Why is this parameter passed magically, vs the others passed normally? data_model_bindings = {:key_fields => neo.key_fields, #:data_ops_set => neo.field_op_set_sym, :views => neo.views} docClass.set_environment(class_environment, data_model_bindings) docClass end |