Class: CouchrestEnv::GlueEnv
- Inherits:
-
Object
- Object
- CouchrestEnv::GlueEnv
- Includes:
- CouchRest::Mixins::Views::ClassMethods, CouchrestViews
- Defined in:
- lib/glue_envs/couchrest_glue_env.rb
Overview
EnvName = :couchrest_env #name for couchrest environments
Constant Summary collapse
- VersionKey =
used to identify metadata for models (should be consistent across models) ModelKey = :_id
:_rev
- PersistLayerKey =
NamespaceKey = :bufs_namespace
:_id
- CouchMetadataKeys =
required by CouchDb to be unique in DB
[:_pos, :_deleted_conflicts, :couchrest, :all_this_class]
- QueryAllStr =
"by_all_bufs".to_sym
- AttachClassBaseName =
"MoabAttachmentHandler"
- DesignDocBaseName =
used to be module name
"CouchRestEnv"
- @@log =
Set Logger
TinkitLog.set(self.name, :warn)
Constants included from CouchrestViews
Instance Attribute Summary collapse
-
#_files_mgr_class ⇒ Object
Returns the value of attribute _files_mgr_class.
-
#attachClass ⇒ Object
Returns the value of attribute attachClass.
-
#attachment_base_id ⇒ Object
Returns the value of attribute attachment_base_id.
-
#db ⇒ Object
Returns the value of attribute db.
-
#design_doc ⇒ Object
Returns the value of attribute design_doc.
-
#metadata_keys ⇒ Object
Returns the value of attribute metadata_keys.
-
#moab_data ⇒ Object
Returns the value of attribute moab_data.
-
#model_key ⇒ Object
Returns the value of attribute model_key.
-
#model_save_params ⇒ Object
Returns the value of attribute model_save_params.
-
#namespace_key ⇒ Object
Returns the value of attribute namespace_key.
-
#node_key ⇒ Object
Returns the value of attribute node_key.
-
#persist_layer_key ⇒ Object
Returns the value of attribute persist_layer_key.
-
#query_all ⇒ Object
TODO move to ViewsMgr and change the confusing accessor/method clash.
-
#required_instance_keys ⇒ Object
Returns the value of attribute required_instance_keys.
-
#required_save_keys ⇒ Object
Returns the value of attribute required_save_keys.
-
#user_datastore_location ⇒ Object
Returns the value of attribute user_datastore_location.
-
#user_id ⇒ Object
Returns the value of attribute user_id.
-
#version_key ⇒ Object
Returns the value of attribute version_key.
-
#views ⇒ Object
Returns the value of attribute views.
Instance Method Summary collapse
-
#db_destroy(model_metadata) ⇒ Object
TODO: update glue models so that it’s id and rev that are explicitly needed which begs the question whether rev is supported or not.
-
#destroy_bulk(user_records_to_delete) ⇒ Object
TODO: Investigate if Couchrest bulk actions or design views will assist here fixed to delete orphaned attachments, but this negates much of the advantage of using this method in the first place or perhaps using a close to the metal design view based on the class name?? (this may be better).
-
#destroy_node(model_metadata) ⇒ Object
Not tested in factory tests (but is in couchrest tests).
- #find_contains(key, this_value) ⇒ Object
- #find_contains_type_helper(stored_data, this_value) ⇒ Object
- #find_equals(key, this_value) ⇒ Object
-
#find_nodes_where(key, relation, this_value) ⇒ Object
current relations supported: - :equals (data in the key field matches this_value) - :contains (this_value is contained in the key field data (same as equals for non-enumerable types ).
-
#generate_model_key(namespace, node_key_value) ⇒ Object
I hope this can be replaced by the generate_pk_data, but need to make sure FIXME: Actually it has to be.
- #generate_pk_data(record_id) ⇒ Object
- #get(id) ⇒ Object
-
#initialize(persist_env, data_model_bindings) ⇒ GlueEnv
constructor
A new instance of GlueEnv.
-
#raw_all ⇒ Object
some models have additional processing required, but not this one.
- #save(user_data) ⇒ Object
- #set_attach_class(db_root_location, attach_class_name) ⇒ Object
-
#set_couch_design(db, user_id) ⇒ Object
, view_name).
-
#set_db_location(couch_db_host, db_name_path) ⇒ Object
TODO Need to fix some naming issues before bringing this method over into the glue environment def set_attach_class(db_root_location, attach_class_name) dyn_attach_class_def = “class #attach_class_name < CouchrestAttachment use_database CouchRest.database!("http://#db_root_location/").
-
#set_namespace(db_name_path, db_user_id) ⇒ Object
TODO: MAJOR Refactoring may have broken compatibility with already persisted data, need to figure out tool to migrate persisted data when changes occur TODO: MAJOR Namespace should not be bound to the underlying model it should be bound to user data only.
- #set_user_datastore_location(db, db_user_id) ⇒ Object
Methods included from CouchrestViews
#call_view, #set_view_value_match, #view_map
Constructor Details
#initialize(persist_env, data_model_bindings) ⇒ GlueEnv
Returns a new instance of GlueEnv.
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 194 def initialize(persist_env, data_model_bindings) couchrest_env = persist_env[:env] couch_db_host = couchrest_env[:host] db_name_path = couchrest_env[:path] @user_id = couchrest_env[:user_id] @model_name = persist_env[:name] #data_model_bindings from NodeElementOperations key_fields = data_model_bindings[:key_fields] initial_views_data = data_model_bindings[:views] || [] #FIXME: Major BUG!! when setting multiple environments in that this may cross-contaminate across users #if those users share the same db. Testing up to date has been users on different dbs, so not an issue to date #also, one solution might be to force users to their own db? (what about sharing though?) #The problem is that there is one "query_all" per database, and it gets set to the last user class #that sets it. [Is this still a bug? 12/16/10] #@user_id = db_user_id #user_attach_class_name = "UserAttach#{db_user_id}" #the rescue is so that testing works #begin # attachClass = UserNode.const_get(user_attach_class_name) #rescue NameError # puts "Warning:: Multiuser support for attachments not enabled. Using generic Attachment Class" # attachClass = CouchrestAttachment #end couch_db_location = set_db_location(couch_db_host, db_name_path) @db = CouchRest.database!(couch_db_location) @model_save_params = {:db => @db} @persist_layer_key = PersistLayerKey #@collection_namespace = CouchrestEnv.set_collection_namespace(db_name_path, @user_id) #@user_datastore_location = CouchRestEnv.set_user_datastore_location(@db, @user_id) @user_datastore_location = set_namespace(db_name_path, @user_id) @design_doc = set_couch_design(@db, @user_id)#, @collection_namespace) @node_key = key_fields[:primary_key] # @define_query_all = QueryAllStr #CouchRestEnv.query_for_all_collection_records @required_instance_keys = key_fields[:required_keys] #DataStructureModels::RequiredInstanceKeys @required_save_keys = key_fields[:required_keys] #DataStructureModels::Tinkit::RequiredSaveKeys @model_key = @node_key #ModelKey #CouchRestEnv::ModelKey @version_key = VersionKey #CouchRestEnv::VersionKey @namespace_key = @model_name #NamespaceKey #CouchRestEnv::NamespaceKey #TODO: Need to investigate whether to keep model_key = node_key in metadata @metadata_keys = [@persist_layer_key, @version_key, @namespace_key] + CouchMetadataKeys #CouchRestEnv.set_db_metadata_keys #(@collection_namespace) @views = CouchRestViews @views.set_view_all(@db, @design_doc, @model_name, @user_datastore_location) @views.set_my_cat_view(@db, @design_doc, @user_datastore_location) #set new view initial_views_data.each do |view_name, view_data| set_view_value_match(@db, @design_doc, @namespace_key, @user_datastore_location, view_data[:field]) end #@views.set_new_views(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) attach_class_name = "#{AttachClassBaseName}#{@user_id}" @attachClass = set_attach_class(@db.root, attach_class_name) @moab_data = {:db => @db, :design_doc => @design_doc, :attachClass => @attachClass} #TODO: Have to do the above, but want to do the below #@attachClass = set_attach_class(@db.root, attach_class_name) @_files_mgr_class = CouchrestInterface::FilesMgr end |
Instance Attribute Details
#_files_mgr_class ⇒ Object
Returns the value of attribute _files_mgr_class.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def _files_mgr_class @_files_mgr_class end |
#attachClass ⇒ Object
Returns the value of attribute attachClass.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def attachClass @attachClass end |
#attachment_base_id ⇒ Object
Returns the value of attribute attachment_base_id.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def @attachment_base_id end |
#db ⇒ Object
Returns the value of attribute db.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def db @db end |
#design_doc ⇒ Object
Returns the value of attribute design_doc.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def design_doc @design_doc end |
#metadata_keys ⇒ Object
Returns the value of attribute metadata_keys.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def @metadata_keys end |
#moab_data ⇒ Object
Returns the value of attribute moab_data.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def moab_data @moab_data end |
#model_key ⇒ Object
Returns the value of attribute model_key.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def model_key @model_key end |
#model_save_params ⇒ Object
Returns the value of attribute model_save_params.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def model_save_params @model_save_params end |
#namespace_key ⇒ Object
Returns the value of attribute namespace_key.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def namespace_key @namespace_key end |
#node_key ⇒ Object
Returns the value of attribute node_key.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def node_key @node_key end |
#persist_layer_key ⇒ Object
Returns the value of attribute persist_layer_key.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def persist_layer_key @persist_layer_key end |
#query_all ⇒ Object
TODO move to ViewsMgr and change the confusing accessor/method clash
327 328 329 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 327 def query_all @query_all end |
#required_instance_keys ⇒ Object
Returns the value of attribute required_instance_keys.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def required_instance_keys @required_instance_keys end |
#required_save_keys ⇒ Object
Returns the value of attribute required_save_keys.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def required_save_keys @required_save_keys end |
#user_datastore_location ⇒ Object
Returns the value of attribute user_datastore_location.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def user_datastore_location @user_datastore_location end |
#user_id ⇒ Object
Returns the value of attribute user_id.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def user_id @user_id end |
#version_key ⇒ Object
Returns the value of attribute version_key.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def version_key @version_key end |
#views ⇒ Object
Returns the value of attribute views.
173 174 175 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 173 def views @views end |
Instance Method Details
#db_destroy(model_metadata) ⇒ Object
TODO: update glue models so that it’s id and rev that are explicitly needed which begs the question whether rev is supported or not
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 462 def db_destroy() id_to_delete = [@persist_layer_key] || generate_pk_data([@node_key]) @@log.info { "Destroy in DB, Key: #{id_to_delete.inspect} in #{.inspect}" } if @@log.info? rev_to_delete = [@version_key] || @db.get(id_to_delete)['_rev'] doc_to_delete = {'_id' => id_to_delete, '_rev' => rev_to_delete } @@log.debug { "Attempting to Delete: #{doc_to_delete.inspect}" } if @@log.debug? begin @db.delete_doc(doc_to_delete) rescue ArgumentError => e puts "Rescued Error: #{e} while trying to destroy #{[@model_key]} node" #Code here was deleting the latest version, but rather than wait for an error, it was proactively checked #so this block may not be needed any more #node = node.class.get(model_metadata[@model_key]) #(model_metadata['_id']) #db_destroy(model_metadata) end end |
#destroy_bulk(user_records_to_delete) ⇒ Object
TODO: Investigate if Couchrest bulk actions or design views will assist here fixed to delete orphaned attachments, but this negates much of the advantage of using this method in the first place or perhaps using a close to the metal design view based on the class name?? (this may be better)
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 511 def destroy_bulk(user_records_to_delete) #TODO: Investigate why mutiple ids may be returned for the same record #Answer Database Corruption user_records_to_delete.uniq! #puts "List of all records: #{user_records_to_delete.map{|r| r['_id']}.inspect}" user_records_to_delete.each do |user_rec| begin db_key = user_rec[@persist_layer_key] || generate_pk_data(user_rec[@model_key]) att_doc_id = attachClass.uniq_att_doc_id(db_key) r = @db.get(db_key ) @db.delete_doc(r) begin att_doc = @db.get(att_doc_id) rescue att_doc = nil end @db.delete_doc(att_doc) if att_doc rescue RestClient::RequestFailed @@log.warn{ "Warning:: Failed to delete document?" } if @@log.warn? end end nil #TODO ok to return nil if all docs destroyed? also, not verifying end |
#destroy_node(model_metadata) ⇒ Object
Not tested in factory tests (but is in couchrest tests)
450 451 452 453 454 455 456 457 458 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 450 def destroy_node() #att_doc = node.my_GlueEnv.attachClass.get(node.attachment_doc_id) if node.respond_to?(:attachment_doc_id) attachClass = @moab_data[:attachClass] att_doc_id = attachClass.uniq_att_doc_id([@persist_layer_key]) att_doc = attachClass.get(att_doc_id) if att_doc_id #raise "Destroying Attachment #{att_doc.inspect} derived from #{@model_metadata.inspect} " att_doc.destroy if att_doc db_destroy() end |
#find_contains(key, this_value) ⇒ Object
363 364 365 366 367 368 369 370 371 372 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 363 def find_contains(key, this_value) #TODO: Make a view for this rather than doing it in ruby results =[] query_all.each do |record| test_val = record[key] results << record if find_contains_type_helper(test_val, this_value) end @@log.debug {"Found contains results: #{results.inspect}"} if @@log.debug? results end |
#find_contains_type_helper(stored_data, this_value) ⇒ Object
374 375 376 377 378 379 380 381 382 383 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 374 def find_contains_type_helper(stored_data, this_value) resp = nil #stored_data = jparse(stored_dataj) if stored_data.respond_to?(:"include?") resp = (stored_data.include?(this_value)) else resp = (stored_data == this_value) end return resp end |
#find_equals(key, this_value) ⇒ Object
353 354 355 356 357 358 359 360 361 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 353 def find_equals(key, this_value) results =[] query_all.each do |record| test_val = record[key] results << record if test_val == this_value end @@log.debug {"Found equals results: #{results.inspect}"} if @@log.debug? results end |
#find_nodes_where(key, relation, this_value) ⇒ Object
current relations supported:
-
:equals (data in the key field matches this_value)
-
:contains (this_value is contained in the key field data (same as equals for non-enumerable types )
339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 339 def find_nodes_where(key, relation, this_value) res = case relation when :equals find_equals(key, this_value) when :contains find_contains(key, this_value) else raise "Couldn't determine relationship between stored data and lookup data" end #case @@log.info {"Found #{res.size} nodes where #{key} #{relation} #{this_value}"} if @@log.info? return res end |
#generate_model_key(namespace, node_key_value) ⇒ Object
I hope this can be replaced by the generate_pk_data, but need to make sure FIXME: Actually it has to be
489 490 491 492 493 494 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 489 def generate_model_key(namespace, node_key_value) #TODO: Make sure namespace is portable across model migrations (must be diff database) #"#{namespace}::#{node_key}" # <== original if the below ends up breaking stuff #"#{node_key}" generate_pk_data(node_key_value) end |
#generate_pk_data(record_id) ⇒ Object
496 497 498 499 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 496 def generate_pk_data(record_id) #url_friendly_class_name = self.class.name.gsub('::','-') "#{user_id}:#{self.class.name}:#{record_id}" end |
#get(id) ⇒ Object
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 423 def get(id) #id can be the model id or the persist layer id pk_data = if id.include? self.class.name id else generate_pk_data(id) end #maybe put in some validations to ensure its from the proper collection namespace? #pk_data = id #generate_pk_data(id) #Major TODO: Deconflict module CouchrestView and CouchRestViews namespace_key = CouchRestViews::ClassNamespaceKey #options, use native couchdb _id or buidl a view for the model key #currently opting for using _id, but this requires rebuilding the primary key data #which is not an ideal solution rtn = begin node = @db.get(pk_data) node = HashKeys.str_to_sym(node) node.delete(PersistLayerKey) node.delete(namespace_key) node rescue RestClient::ResourceNotFound => e nil end rtn end |
#raw_all ⇒ Object
some models have additional processing required, but not this one
502 503 504 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 502 def raw_all query_all end |
#save(user_data) ⇒ Object
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 386 def save(user_data) #I thinkthis was why I originally created the namespace concept but reconciliation is now required pk_data = generate_pk_data(user_data[@model_key]) record_namespace = "#{@user_datastore_location}_#{@model_name}" #Major TODO: Deconflict module CouchrestView and CouchRestViews namespace_key = CouchRestViews::ClassNamespaceKey = {PersistLayerKey => pk_data, namespace_key => record_namespace} new_data = user_data.dup.merge() db = @model_save_params[:db] raise "No database found to save data" unless db raise "No CouchDB Key (#{PersistLayerKey}) found in data: #{new_data.inspect}" unless new_data[PersistLayerKey] raise "No [#{@model_key}] key found in model data: #{new_data.inspect}" unless new_data[@model_key] model_data = HashKeys.sym_to_str(new_data) #db.save_doc(model_data) begin #TODO: Genericize this res = db.save_doc(model_data) rescue RestClient::RequestFailed => e #TODO Update specs to test for this if e.http_code == 409 doc_str = "Document Conflict in the Database." @@log.warn { doc_str } if @@log.warn? existing_doc = db.get(model_data['_id']) rev = existing_doc['_rev'] data_with_rev = model_data.merge({'_rev' => rev}) res = db.save_doc(data_with_rev) else raise "Request Failed -- Response: #{res.inspect} Error:#{e}"\ "\nAdditonal Data: model params: #{model_save_params.inspect}"\ "\n model data: #{model_data.inspect}"\ "\n all data: #{new_data.inspect}" end end end |
#set_attach_class(db_root_location, attach_class_name) ⇒ Object
314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 314 def set_attach_class(db_root_location, attach_class_name) dyn_attach_class_def = "class #{attach_class_name} < CouchrestAttachment use_database CouchRest.database!(\"#{db_root_location}/\") def self.namespace CouchRest.database!(\"http://#{db_root_location}/\") end end" self.class.class_eval(dyn_attach_class_def) self.class.const_get(attach_class_name) end |
#set_couch_design(db, user_id) ⇒ Object
, view_name)
299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 299 def set_couch_design(db, user_id) #, view_name) design_doc = CouchRest::Design.new design_doc.name = "#{DesignDocBaseName}_#{user_id}_Design" #example of a map function that can be passed as a parameter if desired (currently not needed) #map_function = "function(doc) {\n if(doc['#{@@collection_namespace}']) {\n emit(doc['_id'], 1);\n }\n}" #design_doc.view_by collection_namespace.to_sym #, {:map => map_function } design_doc.database = db begin design_doc = db.get(design_doc['_id']) rescue RestClient::ResourceNotFound design_doc.save end design_doc end |
#set_db_location(couch_db_host, db_name_path) ⇒ Object
TODO Need to fix some naming issues before bringing this method over into the glue environment def set_attach_class(db_root_location, attach_class_name)
dyn_attach_class_def = "class #{attach_class_name} < CouchrestAttachment
use_database CouchRest.database!(\"http://#{db_root_location}/\")
def self.namespace
CouchRest.database!(\"http://#{db_root_location}/\")
end
end"
self.class.class_eval(dyn_attach_class_def)
self.class.const_get(attach_class_name)
end
278 279 280 281 282 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 278 def set_db_location(couch_db_host, db_name_path) couch_db_host.chop if couch_db_host =~ /\/$/ #removes any trailing slash db_name_path = "/#{db_name_path}" unless db_name_path =~ /^\// #check for le couch_db_location = "#{couch_db_host}#{db_name_path}" end |
#set_namespace(db_name_path, db_user_id) ⇒ Object
TODO: MAJOR Refactoring may have broken compatibility with already persisted data, need to figure out tool to migrate persisted data when changes occur TODO: MAJOR Namespace should not be bound to the underlying model it should be bound to user data only
287 288 289 290 291 292 293 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 287 def set_namespace(db_name_path, db_user_id) lose_leading_slash = db_name_path.split("/") lose_leading_slash.shift db_name = lose_leading_slash.join("") #namespace = "#{db_name}_#{db_user_id}" namespace = "#{db_user_id}" end |
#set_user_datastore_location(db, db_user_id) ⇒ Object
295 296 297 |
# File 'lib/glue_envs/couchrest_glue_env.rb', line 295 def set_user_datastore_location(db, db_user_id) "#{db.to_s}::#{db_user_id}" end |