class GxG::Database::PersistedArray
Class Place-holder Definitions
Public Class Methods
new(settings = {})
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 651 def initialize(settings = {}) # mount element: {:database => <database>, :uuid => <uuid>, :credential => <uuid>, :delegate => nil/<uuid>, :parent => nil/<an-object>} # create element: {:database => <database>, :credential => <uuid>, :delegate => nil/<uuid>, :parent => nil/<an-object>} # if settings.is_a?(::Hash) unless ::GxG::valid_uuid?(settings[:credential]) raise ArgumentError, "You must supply a valid credential UUID (37 character limit) as a String or Symbol" end @quick = settings[:quick] @credential = settings[:credential].to_sym @reservation = nil @delegate = settings[:delegate] if settings[:parent].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) @parent = settings[:parent] else @parent = nil end @constraint = settings[:constraint] if settings[:database].is_a?(::GxG::Database::Database) if settings[:database].open?() the_uuid = settings[:uuid] if the_uuid.is_a?(::Symbol) the_uuid = the_uuid.to_s end # TODO: validate uuid pattern if settings[:title].is_a?(::String) the_title = settings[:title] else the_title = ("Untitled PersistedArray " << (settings[:database].connector()[:element_array].count.to_s)) end unless ::GxG::valid_uuid?(the_uuid) # without specifying a uuid, the implied intent is to create a new PersistedArray the_uuid = ::GxG::uuid_generate() while ((settings[:database].connector()[:element_array].filter({:uuid => the_uuid}).count > 0) or (settings[:database].connector()[:element_array].filter({:uuid => the_uuid}).count > 0)) the_uuid = ::GxG::uuid_generate() end # create blank array record new_dbid = settings[:database].connector()[:element_array].insert({:uuid => (the_uuid), :title => (the_title), :constraint => (@constraint.to_s)}) # @db_address = {:database => (settings[:database]), :table => :element_array, :dbid => (new_dbid)} if @parent @permission = @parent.get_permissions() # settings[:database].enforce_permission_policy({:action => :extend, :credential => @credential, :source => settings[:parent], :destination => self}) # settings[:database].extend_element_permissions(settings[:parent].db_address()[:table], settings[:parent].db_address()[:dbid], :element_array, new_dbid) else # create raw permissions for this element @permission = {:execute => false, :rename => true, :move => true, :destroy => true, :create => true, :write => true, :read => true} # settings[:database].assign_element_permission(:element_array, new_dbid, @credential, {:execute => false, :rename => true, :move => true, :destroy => true, :create => true, :write => true, :read => true}) # settings[:database].enforce_permission_policy({:action => :extend, :credential => @credential, :source => self, :destination => self}) end settings[:database].assign_element_permission(:element_array, new_dbid, @credential, @permission) end # mount according to uuid if the_uuid # mount record = settings[:database].connector()[:element_array].filter({:uuid => (the_uuid)}).first if record @uuid = the_uuid.to_sym @title = record[:title].to_s @version = record[:version].to_f @db_address = {:database => (settings[:database]), :table => :element_array, :dbid => (record[:dbid])} @element_links = [] if record[:constraint].to_s.size > 0 @constraint = record[:constraint].to_sym else @constraint = nil end unless @permission @permission = @db_address[:database].effective_element_permission(@db_address[:table], @db_address[:dbid], @credential) end # @read_reservation = @db_address[:database].reserve_element_locks(@credential, (@db_address[:database].element_manifest(@db_address[:table], @db_address[:dbid])), :read) # load_element_links # else raise Exception, "Unable to mount the PersistedArray record" end else raise Exception, "Unable to mount the PersistedArray record" end # else raise Exception, "Database not available for storage" end # else raise Exception, "Invalid Database object" end # else raise ArgumentError, "You must supply a hash of details" end # end
Public Instance Methods
<<(*args)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1303 def <<(*args) if args.size > 0 args.each do |item| self[(@element_links.size)] = item end end self end
[](indexer=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1203 def [](indexer=nil) result = nil # if exists # if is not loaded, load element (if String or ByteArray) if self.alive?() if @db_address[:database].open?() if indexer.is_a?(::Integer) if @element_links[(indexer)] if @element_links[(indexer)][:content].is_any?(::String, ::GxG::ByteArray) unless @element_links[(indexer)][:loaded] == true # ### Load Base Element contents from the database. if @element_links[(indexer)][:content].is_a?(::String) if @element_links[(indexer)][:record][:element_text_uuid].to_s.size > 0 @db_address[:database].connector()[:text_page].filter({:parent_uuid => @element_links[(indexer)][:record][:element_text_uuid].to_s}).order(:ordinal).each do |text_page| @element_links[(indexer)][:content] << text_page[:content] end else @element_links[(indexer)][:content] = @element_links[(indexer)][:record][:element_text].to_s end else @db_address[:database].connector()[:binary_page].filter({:parent_uuid => @element_links[(indexer)][:record][:element_binary_uuid].to_s}).order(:ordinal).each do |binary_page| @element_links[(indexer)][:content] << binary_page[:content] end end @element_links[(indexer)][:loaded] = true end end result = @element_links[(indexer)][:content] end else raise ArgumentError, "You must specify with an Integer, not a #{indexer.class.inspect}" end else raise Exception, "Database not available" end else raise Exception, "Attempted to access a defunct structure" end result end
[]=(indexer=nil, value=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 892 def []=(indexer=nil, value=nil) # Only works with Integer indexes. unless self.alive?() raise Exception, "Attempted to alter a defunct structure" end unless @db_address[:database].open?() raise Exception, "Database not available" end result = nil if indexer.is_a?(::Integer) # Review : rewrite ???? if value.is_any?(::GxG::Database::Database::valid_field_classes()) || value.is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray, ::Hash, ::Array) unless self.write_reserved?() self.get_reservation() end if self.write_reserved?() # Further screen value provided: # ### Check provided PersistedHashes and PersistedArrays if value.is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) unless value.db_address() raise Exception, "The structure you are attaching is Deactivated (not supported)." end if value.structure_attached?() # Review : experimental - auto-detach from prior structural relationship and reassign here. # raise Exception, "Cross linked structures not supported" value.structure_detach end value.search do |the_value, the_selector, the_container| if the_value.is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) unless the_value.db_address() raise Exception, "The structure you are attaching has a Deactivated item within it (not supported)." end end end end # ### Check provided Hashes and Arrays if value.is_any?(::Hash, ::Array) value.search do |the_value, the_selector, the_container| if the_value.is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) unless the_value.db_address() raise Exception, "The structure you are attaching has a Deactivated item within it (not supported)." end if @db_address[:database].structure_attached?(the_value.uuid.to_s) && the_container.is_any?(::Hash, ::Array) raise Exception, "The structure you are attaching has a cross-linked structure within it (cross linked structures not supported)." end end unless the_value.is_any?(::GxG::Database::Database::valid_field_classes()) || the_value.is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray, ::Hash, ::Array) raise Exception, "The structure you are attaching has an unpersistable item within it (not supported)." end end end # ### Property Exists? if @element_links[(indexer)] # set property to value operation = :set_value else if @format raise Exception, "Formatted - the structure cannot be altered" else # add property : value pair operation = :add_value end end # ### Prepare new value new_value = { :linkid => nil, :content => nil, :loaded => false, :state => 0, :record => { :parent_uuid => @uuid.to_s, :ordinal => 0, :version => 0.0, :element => "element_boolean", :element_boolean => -1, :element_integer => 0, :element_float => 0.0, :element_bigdecimal => ::BigDecimal.new("0.0"), :element_datetime => ::DateTime.now, :time_offset => 0.0, :time_prior => 0.0, :time_after => 0.0, :length => 0, :element_text => "", :element_text_uuid => "", :element_binary_uuid => "", :element_array_uuid => "", :element_hash_uuid => "" } } # if value.is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) # ### Assimilate PersistedHash or PersistedArray new_value[:content] = value new_value[:loaded] = true new_value[:state] = new_value[:content].hash # Note: version is sync'd here, but don't rely upon property version with linked structures, but use structure's version method. new_value[:record][:version] = new_value[:content].version() if value.is_a?(::GxG::Database::PersistedHash) new_value[:record][:element] = "element_hash" new_value[:record][:element_hash_uuid] = value.uuid.to_s else new_value[:record][:element] = "element_array" new_value[:record][:element_array_uuid] = value.uuid.to_s end else # ### Persist Hashes and Arrays if value.is_any?(::Hash, ::Array) new_value[:content] = @db_address[:database].iterative_persist(value,@credential) new_value[:loaded] = true new_value[:state] = new_value[:content].hash # Note: version is sync'd here, but don't rely upon property version with linked structures, but use structure's version method. new_value[:record][:version] = new_value[:content].version() if value.is_a?(::Hash) new_value[:record][:element] = "element_hash" new_value[:record][:element_hash_uuid] = new_value[:content].uuid.to_s else new_value[:record][:element] = "element_array" new_value[:record][:element_array_uuid] = new_value[:content].uuid.to_s end else # ### Persist Base Element Values new_value[:record][:element] = ::GxG::Database::Database::element_table_for_instance(value).to_s case new_value[:record][:element] when "element_boolean" case value.class when ::NilClass new_value[:record][:element_boolean] = -1 new_value[:content] = nil when ::FalseClass new_value[:record][:element_boolean] = 0 new_value[:content] = false when ::TrueClass new_value[:record][:element_boolean] = 1 new_value[:content] = true end when "element_integer" new_value[:record][:element_integer] = value new_value[:content] = value when "element_float" new_value[:record][:element_float] = value new_value[:content] = value when "element_bigdecimal" new_value[:record][:element_bigdecimal] = ::BigDecimal.new(value.to_s) new_value[:content] = new_value[:record][:element_bigdecimal] when "element_datetime" new_value[:record][:element_datetime] = value new_value[:content] = value when "element_text" if value.size > 256 # Note: be sure to keep text version & length sync'd with linked text element record if operation == :set_value new_value[:record][:version] = @element_links[(indexer)][:record][:version] new_value[:record][:element_text_uuid] = @element_links[(indexer)][:record][:element_text_uuid] end new_value[:record][:length] = value.size else new_value[:record][:element_text] = value new_value[:record][:length] = value.size end new_value[:content] = value when "element_binary" # Note: be sure to keep version & length sync'd with linked binary element record if operation == :set_value new_value[:record][:version] = @element_links[(indexer)][:record][:version] new_value[:record][:element_binary_uuid] = @element_links[(indexer)][:record][:element_binary_uuid] end new_value[:record][:length] = value.size new_value[:content] = value else raise Exception, "Unable to map an element type for value: #{value.inspect}" end end end # ### Commit Changes case operation when :set_value # Note: Set In-memory value only, don't save unless you have to. if new_value[:content].is_a?(@element_links[(indexer)][:content].class) || ([true, false, nil].include?(new_value[:content]) && [true, false, nil].include?(@element_links[(indexer)][:content])) # Replace value directly, but don't save yet unless you have to (:state refers to the last 'loaded-in-from-db' state of the data). new_value[:linkid] = @element_links[(indexer)][:linkid] if new_value[:content].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) new_value[:record][:version] = new_value[:content].version() else new_value[:record][:version] = (((@element_links[(indexer)][:record][:version].to_f + 0.0001) * 10000.0).to_i.to_f / 10000.0) end new_value[:record][:ordinal] = @element_links[(indexer)][:record][:ordinal] new_value[:loaded] = true new_value[:state] = @element_links[(indexer)][:state] # ### Did string grow or shrink crossing the threshold?? if new_value[:content].is_a?(::String) if (@element_links[(indexer)][:content].size > 256 && new_value[:content].size <= 256) # shrank - delete text object and pages as well as property record (slow) element_destroy(indexer) @element_links[(indexer)] = new_value element_write(indexer) else if (@element_links[(indexer)][:content].size <= 256 && new_value[:content].size > 256) # grew - create text object and pages (a little less slow) @element_links[(indexer)] = new_value element_write(indexer) else # N/A @element_links[(indexer)] = new_value end end else # N/A @element_links[(indexer)] = new_value end if new_value[:content].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) # Note: this ensures attachment to this object property_write(property_key) end # else # Other class value being substituted. if new_value[:content].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) new_value[:record][:version] = new_value[:content].version() else new_value[:record][:version] = (((@element_links[(indexer)][:record][:version].to_f + 0.0001) * 10000.0).to_i.to_f / 10000.0) end new_value[:record][:ordinal] = @element_links[(indexer)][:record][:ordinal] new_value[:loaded] = true # Destroy old property record on db, and associated linked objects. # Review : this is slow - look into optimizations here. if @element_links[(indexer)][:content].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray, ::GxG::ByteArray, ::String) if @element_links[(indexer)][:content].is_a?(::String) if (@element_links[(indexer)][:content].size > 256 && new_value[:content].size <= 256) || (@element_links[(indexer)][:content].size <= 256 && new_value[:content].size > 256) element_destroy(indexer) end else element_destroy(indexer) end end # @element_links[(indexer)] = new_value element_write(indexer) end # when :add_value # Note: set in-memory value and save. if new_value[:content].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) new_value[:record][:version] = new_value[:content].version() else new_value[:record][:version] = 0.0 end new_value[:record][:ordinal] = @element_links.size new_value[:loaded] = true # @element_links[(indexer)] = new_value # Review : is this wise to do this here?? element_write(indexer) end # ### Handle coordination between persisted objects: if @element_links[(indexer)][:content].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) # ### Extend Reservation to persisted objects ( Review : does this slow it down too much?? ) @element_links[(indexer)][:content].release_reservation @db_address[:database].reservation_add_element((@reservation || @delegate), (@element_links[(indexer)][:content].db_address()[:table]), @element_links[(indexer)][:content].db_address()[:dbid]) @element_links[(indexer)][:content].set_delegate((@reservation || @delegate)) # ### Extend Permissions to persisted object @db_address[:database].extend_element_permissions(@db_address[:table],@db_address[:dbid],@element_links[(indexer)][:content].db_address()[:table],@element_links[(indexer)][:content].db_address()[:dbid]) @db_address[:database].enforce_permission_policy({:action => :extend, :credential => @credential, :source => self, :destination => @element_links[(indexer)][:content]}) # @element_links[(indexer)][:content].set_parent(self) end # self.increment_version() result = @element_links[(indexer)][:content] # else raise Exception, "You do not have sufficient privileges to make this change. (write-reservation)" end else raise Exception, "The value is not persistable." end else raise Exception, "You must provide a index in the form of an Integer." end result end
alive?()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 773 def alive?() if @db_address if @db_address[:database].element_exists?(@db_address[:table],@db_address[:dbid]) true else false end else false end end
clear_constraint()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 602 def clear_constraint() if self.alive? if @constraint @constraint = nil @db_address[:database].connector()[:element_array].filter({:dbid => (@db_address[:dbid])}).update({:constraint => ""}) end end true end
constraint()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 612 def constraint() @constraint.clone end
db_address()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 785 def db_address() @db_address end
deactivate()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 789 def deactivate() if self.alive?() @element_links.each_index do |index| element = @element_links[(index)][:content] if element.is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) containers = [(element)] element.search({:include_inactive => false}) do |the_value, the_selector, the_container| if the_value.alive? the_value.deactivate end if the_container.alive? unless containers.include?(the_container) containers.unshift(the_container) end end nil end containers.each do |the_container| the_container.deactivate end end end if self.write_reserved?() self.release_reservation() end @element_links = [] @db_address = nil end true end
delete_at(indexer=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1244 def delete_at(indexer=nil) result = nil # if exists # if is not loaded, load element if self.alive?() if @db_address[:database].open?() if indexer.is_a?(::Integer) if self.write_reserved?() property_key = key.to_s.to_sym # if @element_links[(indexer)] # This will load the unloaded prior to separation. result = self[(indexer)] the_link = @element_links.delete_at(indexer) if the_link[:content].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) the_link[:content].save the_link[:content].release_reservation() @db_address[:database].reservation_remove_element((@reservation || @delegate), the_link[:content].db_address()[:table], the_link[:content].db_address()[:dbid]) else # Eliminate orphaned text and binary objects in the database. They will exist only in memory. if the_link[:content].is_any?(::String, ::GxG::ByteArray) if the_link[:content].is_a?(::String) if the_link[:content].size > 256 # eliminate text object and pages. the_temp_record = @db_address[:database].connector()[:element_text].select(:dbid).where({:uuid => the_link[:record][:element_text_uuid]}).first if the_temp_record @db_address[:database].element_destroy(@credential, :element_text, the_temp_record[:dbid]) end end end if the_link[:content].is_a?(::GxG::ByteArray) # eliminate binary object and pages. the_temp_record = @db_address[:database].connector()[:element_binary].select(:dbid).where({:uuid => the_link[:record][:element_binary_uuid]}).first if the_temp_record @db_address[:database].element_destroy(@credential, :element_binary, the_temp_record[:dbid]) end end end end @db_address[:database].connector()[:array_elements].filter({:dbid => the_link[:linkid]}).delete refresh_ordinals self.increment_version() end # else raise Exception, "You do not have sufficient privileges to make this change" end else raise ArgumentError, "You must specify with a Symbol, not a #{key.class.inspect}" end else raise Exception, "Database not available" end else raise Exception, "Attempted to access a defunct structure" end result end
destroy()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 847 def destroy() result = false if self.alive? begin unless self.write_reserved?() raise Exception, "You do not have a write-lock for this element" end unless @permission[:destroy] raise Exception, "You do not have permission to destory this element" end if @db_address[:database].open?() if @db_address[:database].element_in_use?(@db_address[:table], @db_address[:dbid]) raise Exception, "Element is still linked to a structure. Use <PersistedHash>.delete(<key>).destroy or <PersistedArray>.delete_at(<index>).destroy" else if self.write_reserved?() address = @db_address self.deactivate address[:database].element_destroy(@credential, address[:table],address[:dbid]) # Review : consider either emptying the db trash now, or adding a flag to manifest records to prevent future loading. result = true else raise Exception, "You do not have sufficient privileges to make this change" end end else raise Exception, "Database not available" end rescue Exception => the_error log_error({:error => the_error}) end end result end
each(&block)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1432 def each(&block) if block.respond_to?(:call) load_element_links if @element_links.size > 0 @element_links.each_index do |index| block.call(self[(index)]) end end self else self.to_enum(:each) end end
each_index(&block)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1446 def each_index(&block) if block.respond_to?(:call) load_element_links if @element_links.size > 0 @element_links.each_index do |index| block.call(index) end end self else self.to_enum(:each_index) end end
each_with_index(offset=0,&block)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1460 def each_with_index(offset=0,&block) if block.respond_to?(:call) load_element_links if @element_links.size > 0 @element_links.to_enum(:each).with_index(offset).each do |entry, index| block.call(self[(index)], index) end end self else self.to_enum(:each_with_index,offset) end end
element_version(index=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 526 def element_version(index=nil) result = 0.0 if index.is_a?(::Numeric) if @element_links[(index)] result = @element_links[(index)][:record][:version] end # end result end
export(options={:exclude_file_segments=>false})
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1347 def export(options={:exclude_file_segments=>false}) if self.alive? exclude_file_segments = (options[:exclude_file_segments] || false) if options[:clone] == true # Review : why are cloned objects unconstrained? sync issues?? result = {:type => :element_array, :uuid => GxG::uuid_generate.to_s.to_sym, :title => @title.clone, :version => @version.clone, :content => []} else result = {:type => :element_array, :uuid => @uuid.clone, :title => @title.clone, :version => @version.clone, :constraint => @constraint.clone, :content => []} end export_db = [{:parent => nil, :parent_selector => nil, :object => self, :record => result}] children_of = Proc.new do |the_parent=nil| list = [] export_db.each do |node| if node[:parent].object_id == the_parent.object_id list << node end end list end # Build up export_db: self.search do |the_value, the_selector, the_container| if the_value.is_a?(::GxG::Database::PersistedHash) if options[:clone] == true the_uuid = GxG::uuid_generate.to_s.to_sym else the_uuid = the_value.uuid().clone end if (exclude_file_segments == true) && (the_selector == :file_segments || the_selector == :segments || the_selector == :portions) export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => {}, :record => {:type => :element_hash, :uuid => the_uuid, :title => the_value.title().clone, :version => the_value.version().clone, :format => the_value.format().clone, :content => {}}} else export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => {:type => :element_hash, :uuid => the_uuid, :title => the_value.title().clone, :version => the_value.version().clone, :format => the_value.format().clone, :content => {}}} end end if the_value.is_a?(::GxG::Database::PersistedArray) if options[:clone] == true the_uuid = GxG::uuid_generate.to_s.to_sym else the_uuid = the_value.uuid().clone end if (exclude_file_segments == true) && (the_selector == :file_segments || the_selector == :segments || the_selector == :portions) export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => [], :record => {:type => :element_array, :uuid => the_uuid, :title => the_value.title().clone, :version => the_value.version().clone, :constraint => the_value.constraint().clone, :content => []}} else export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => {:type => :element_array, :uuid => the_uuid, :title => the_value.title().clone, :version => the_value.version().clone, :constraint => the_value.constraint().clone, :content => []}} end end if the_value.is_any?(::GxG::Database::Database::valid_field_classes()) data_type = GxG::Database::Database::element_table_for_instance(the_value) case data_type when :element_bigdecimal data = the_value.to_s when :element_datetime data = the_value.to_s when :element_binary data = the_value.to_s.encode64 when :element_text data = the_value.to_s else data = the_value end export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => {:type => data_type, :version => (the_container.version(the_selector) || 0.0), :content => data}} end end # Collect children export content: link_db = [(export_db[0])] while link_db.size > 0 do entry = link_db.shift children_of.call(entry[:object]).each do |the_child| entry[:record][:content][(the_child[:parent_selector])] = the_child[:record] if the_child[:object].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) link_db << the_child end end end else result = nil end result end
find_index(the_value)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1336 def find_index(the_value) result = nil @element_links.each_with_index do |element, indexer| if element[:content] == the_value result = indexer break end end result end
get_at_path(the_path="/")
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1633 def get_at_path(the_path="/") # /^(?:[0-9])*[0-9](?:[0-9])*$/ = nil if an alpha present there, else 0 only numeric # Attribution : http://stackoverflow.com/questions/1240674/regex-match-a-string-containing-numbers-and-letters-but-not-a-string-of-just-nu # # if ":" detected do: (str.gsub("%2f","/").to_sym) as key else (str.gsub("%2f","/")) result = nil if the_path == "/" result = self else object_stack = [(self)] path_stack = the_path.split("/") path_stack.to_enum.each do |path_element| element = nil if path_element.size > 0 if (path_element =~ /^(?:[0-9])*[0-9](?:[0-9])*$/) == 0 element = path_element.to_i else element = path_element element.gsub!("%2f","/") if element[0] == ":" element = element[(1..-1)].to_sym end end end if element result = object_stack.first[(element)] if result.is_a?(NilClass) break else object_stack.unshift(result) end else # ignore double slashes? '//' # break end end end result end
get_delegate()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 496 def get_delegate() if self.alive? if @delegate.is_any?(::String, ::Symbol) @delegate.clone end end end
get_permissions()
click to toggle source
Permission Management:
# File lib/gxg/gxg_database_persistedarray.rb, line 321 def get_permissions() @permission.clone end
get_reservation()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 424 def get_reservation() result = false # Review : Experimental design change - deprecate @delegate use, require entire structure (and sub-structures) to get solid @reservation (all of them) or this fails. # Note : keep your structures small as this opens the door for stack-depth exceptions if it is nested too deep. (say 256 or less layers deep??) if @reservation result = true else if self.alive? if @permission[:write] clean_up_list = [] # Review : efficiency - write locks only apply to PersistedHashes and PersistedArrays so do we need a full manifest?? the_reservation = @db_address[:database].reserve_element_locks(@credential, (@db_address[:database].element_manifest(@db_address[:table], @db_address[:dbid])), :write) if the_reservation @element_links.each_index do |ordinal| if @element_links[(ordinal)][:content].is_any?([::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray]) clean_up_list << @element_links[(ordinal)][:content] unless @element_links[(ordinal)][:content].get_reservation() @db_address[:database].release_element_locks(the_reservation) the_reservation = nil break end end end # end if the_reservation @reservation = the_reservation result = true else clean_up_list.each do |the_object| the_object.release_reservation end end end end end # xxx keep old code for now # if (@reservation || @delegate) # result = true # else # if self.alive? # if @permission[:write] # @reservation = @db_address[:database].reserve_element_locks(@credential, (@db_address[:database].element_manifest(@db_address[:table], @db_address[:dbid])), :write) # if @reservation # @element_links.each_index do |ordinal| # if @element_links[(ordinal)][:content].is_any?([::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray]) # @element_links[(ordinal)][:content].set_delegate((@reservation || @delegate)) # end # end # result = true # end # # # end # end # end # xxx end old code result end
include?(the_value)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1325 def include?(the_value) result = false @element_links.each do |element| if element[:content] == the_value result = true break end end result end
increment_version()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 552 def increment_version() if self.alive? if @db_address[:database].open? if self.write_reserved?() @version = (((@version + 0.0001) * 10000.0).to_i.to_f / 10000.0) end end end end
inspect()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 746 def inspect() # FORNOW: make re-entrant (yes, I know!) Fortunately, circular links are impossible with PersistedArray. # TODO: make interative instead of re-entrant. result = "(Not Loaded)" if @db_address if @db_address[:database].element_byte_size(@db_address[:table], @db_address[:dbid]) <= 10485760 # smaller than 10MB result = "[" @element_links.each_index do |element_index| if @element_links[(element_index)].is_a?(::Hash) result << @element_links[(element_index)][:content].inspect else result << "(Not Loaded)" end unless element_index == (@element_links.size - 1) result << ", " end end result << "]" else result = "(Too Damned Big)" end # end result end
iterative(options={:include_inactive => true}, &block)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1474 def iterative(options={:include_inactive => true}, &block) result = [] visit = Proc.new do |the_node=nil, accumulator=[]| node_stack = [] if the_node node_stack << ({:parent => nil, :parent_selector => nil, :object => (the_node)}) while (node_stack.size > 0) do a_node = node_stack.shift # if a_node[:object].is_a?(::GxG::Database::PersistedHash) if a_node[:object].alive? a_node[:object].each_pair do |the_key, the_value| node_stack << ({:parent => a_node[:object], :parent_selector => the_key, :object => the_value}) end else if options[:include_inactive] accumulator << a_node end end end if a_node[:object].is_a?(::GxG::Database::PersistedArray) if a_node[:object].alive? a_node[:object].each_with_index do |the_value, the_index| node_stack << ({:parent => a_node[:object], :parent_selector => the_index, :object => the_value}) end else if options[:include_inactive] accumulator << a_node end end end # if a_node.alive? || options[:include_inactive] accumulator << a_node end end end accumulator end # children_of = Proc.new do |the_db=[], the_parent=nil| list = [] the_db.each do |node| if node[:parent].object_id == the_parent.object_id list << node end end list end # begin database = visit.call(self,[]) link_db = children_of.call(database, self) if block.respond_to?(:call) while (link_db.size > 0) do entry = link_db.shift unless entry[:object].object_id == self.object_id # calls with parameters: the_value, the_key/the_index (the_selector), the_container raw_result = block.call(entry[:object], entry[:parent_selector], entry[:parent]) if raw_result result << raw_result end end if entry[:object].object_id != nil.object_id children = children_of.call(database, entry[:object]) children.each do |child| link_db << child end end end end # rescue Exception => the_error log_error({:error => the_error, :parameters => {}}) end # result end
parent()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 629 def parent() @parent end
paths_to(the_object=nil,base_path="")
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1566 def paths_to(the_object=nil,base_path="") # new idea here: search_results = [] unless base_path[0] == "/" base_path = ("/" << base_path) end if base_path.size > 1 path_stack = base_path.split("/")[1..-1].reverse else path_stack = [] end origin = self.get_at_path(base_path) container_stack = [{:selector => nil, :container => origin}] find_container = Proc.new do |the_container| result = nil container_stack.each_with_index do |entry, index| if entry[:container] == the_container result = entry break end end result end last_container = origin found = false # tester = {:a=>1, :b=>2, :c=>[0, 5], :testing=>{:d=>4.0, :e=>0.9, :f => nil}} if origin.is_any?(::Hash, ::Array, ::Struct, ::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) origin.process! do |the_value, selector, container| if last_container.object_id != container.object_id container_record = find_container.call(container) if container_record path_stack = container_record[:prefix].split("/").reverse if path_stack.size == 0 path_stack << "" end end last_container = container end if selector.is_a?(Symbol) safe_key = (":" + selector.to_s) else safe_key = selector.to_s end safe_key.gsub!("/","%2f") path_stack.unshift(safe_key) # compare the_value found = false if (the_value == the_object) found = true end if found search_results << ("/" << path_stack.reverse.join("/")) end # if the_value.is_any?(::Array, ::Hash, ::Struct, ::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) container_stack.unshift({:selector => selector, :container => the_value, :prefix => (path_stack.reverse.join("/"))}) end path_stack.shift # nil end else search_results << ("/" << path_stack.join("/")) end search_results end
pop()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1321 def pop() self.delete_at((@element_links.size - 1)) end
process!(options={:include_inactive => true}, &block)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1553 def process!(options={:include_inactive => true}, &block) self.iterative(options, &block) self end
push(*args)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1312 def push(*args) if args.size > 0 args.each do |item| self << item end end self end
refresh_links()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 643 def refresh_links() if self.alive?() unless @db_address[:database].element_in_use?(@db_address[:table], @db_address[:dbid]) @parent = nil end end end
release_reservation()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 405 def release_reservation() if self.alive?() if @reservation @db_address[:database].release_element_locks(@reservation) @reservation = nil end if @delegate @delegate = nil end # release write-locks of all sub-items @element_links.each_index do |ordinal| if @element_links[(ordinal)][:content].is_any?([::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray]) @element_links[(ordinal)][:content].release_reservation end end end true end
reservation()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 385 def reservation() if self.alive? if @reservation.is_any?(::String, ::Symbol) @reservation.clone end end end
save()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 820 def save() result = false if self.alive? begin if @db_address[:database].open?() @element_links.each_index do |index| # Note: only save property data and header if: a) data is still loaded and b) state has changed. if @element_links[(index)][:loaded] == true if @element_links[(index)][:state] != @element_links[(index)][:content].hash @element_links[(index)][:record][:version] = (((@element_links[(index)][:record][:version].to_f + 0.0001) * 10000.0).to_i.to_f / 10000.0) element_write(index) end end # end else raise Exception, "Database not available" end self.save_version result = true rescue Exception => the_error log_error({:error => the_error}) end end result end
save_version()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 562 def save_version() @db_address[:database].connector()[:element_array].filter({:dbid => @db_address[:dbid]}).update({:version => @version}) end
search(options={:include_inactive => true}, &block)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1558 def search(options={:include_inactive => true}, &block) results = [] if block.respond_to?(:call) results = self.iterative(options, &block) end results end
set_at_path(the_path="/",the_value=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1673 def set_at_path(the_path="/",the_value=nil) result = nil if the_path != "/" container = self.get_at_path(::File::dirname(the_path)) if container raw_selector = ::File::basename(the_path) selector = nil if raw_selector.size > 0 if (raw_selector =~ /^(?:[0-9])*[0-9](?:[0-9])*$/) == 0 selector = raw_selector.to_i else selector = raw_selector selector.gsub!("%2f","/") if selector[0] == ":" selector = selector[(1..-1)].to_sym end end end if selector container[(selector)] = the_value result = container[(selector)] else # ignore double slashes? '//' # break end # end end result end
set_constraint(format_uuid=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 591 def set_constraint(format_uuid=nil) if self.alive? unless @constraint if ::GxG::valid_uuid?(format_uuid) @constraint = format_uuid.to_sym @db_address[:database].connector()[:element_array].filter({:dbid => (@db_address[:dbid])}).update({:constraint => (@constraint.to_s)}) end end end end
set_delegate(the_delegate=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 504 def set_delegate(the_delegate=nil) if self.alive? if the_delegate.is_any?([::String, ::Symbol]) @delegate = the_delegate.to_sym end end end
set_element_version(element_index, the_version=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 537 def set_element_version(element_index, the_version=nil) result = false if @element_links[(element_index)] if the_version.is_a?(::Numeric) @element_links[(element_index)][:record][:version] = (((the_version.to_f) * 10000.0).to_i.to_f / 10000.0) result = true else log_warning("Attempted to set version to an invalid version value #{the_version.inspect} for index #{element_index.inspect} on Object #{@uuid.inspect}") end else log_warning("Attempted to set version with an invalid index #{element_index.inspect} on Object #{@uuid.inspect}") end result end
set_parent(object=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 633 def set_parent(object=nil) if self.alive? if object.is_any?([::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray]) unless @parent @parent = object end end end end
set_permissions(credential=nil, the_permission=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 325 def set_permissions(credential=nil, the_permission=nil) if self.alive? if credential.is_a?(::Hash) && the_permission.is_a?(::Hash) if credential[:user] if credential[:user] == "public" || credential[:user] == "Public" credential = "00000000-0000-4000-0000-000000000000" else credential = (@db_address[:database].user_fetch({:user_id => credential[:user].to_s}) || {})[:uuid] end if credential credential = credential.to_s.to_sym end else if credential[:group] credential = @db_address[:database].group_credential(credential) else credential = nil end end else if credential.is_a?(::Hash) && the_permission == nil the_permission = credential credential = @credential else unless credential credential = @credential end end end if the_permission.is_a?(::Hash) && ::GxG::valid_uuid?(credential) manifest = [] structures = [{:table => @db_address[:table], :dbid => @db_address[:dbid]}] while structures.size > 0 do entry = structures[0] @db_address[:database].element_manifest(entry[:table],entry[:dbid]).each do |record| if [:element_hash, :element_array].include?(record[:table]) unless structures.include?(record) structures << record end else # Review - only set/get/check permissions on persisted arrays/hashes # unless manifest.include?(record) # manifest << record # end end end manifest << structures.shift end manifest.each do |entry| @db_address[:database].assign_element_permission(entry[:table], entry[:dbid], credential, the_permission) end # true else log_error({:error => Exception.new("You MUST provide a valid permissions Hash."), :parameters => {:credential => credential, :permission => the_permission}}) false end end end
set_title(the_title=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 577 def set_title(the_title=nil) if self.alive? if @db_address[:database].open? if self.write_reserved?() if the_title @title = the_title.to_s[0..256] @db_address[:database].connector()[:element_array].filter({:dbid => @db_address[:dbid]}).update({:title => @title}) self.increment_version end end end end end
set_version(the_version=0.0)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 566 def set_version(the_version=0.0) if self.write_reserved?() @version = (((the_version.to_f) * 10000.0).to_i.to_f / 10000.0) self.save_version end end
size()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 881 def size() @element_links.size end
structure_attached?()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 885 def structure_attached?() @db_address[:database].structure_attached?(@uuid.to_s) end
structure_detach()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 888 def structure_detach() @db_address[:database].structure_detach(@uuid.to_s) end
sync_export(options={})
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1426 def sync_export(options={}) # Review : does this work with PersistedArray ?? self.save @db_address[:database].sync_export(@credential, [(@uuid)], options) end
title()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 573 def title() @title.clone end
ufs()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 616 def ufs() if @constraint record = @db_address[:database].format_load({:uuid => @constraint.to_s}) if record record[:ufs] else "" end else "" end end
unload(indexer=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1174 def unload(indexer=nil) result = false # if key exists # if key is loaded, unload element (if String or ByteArray) if self.alive?() if @db_address[:database].open?() if indexer.is_a?(::Integer) if @element_links[(indexer)] if @element_links[(indexer)][:content].is_any?(::String, ::GxG::ByteArray) if @element_links[(indexer)][:loaded] == true # ### Unload Base Element contents from memory, leaving reference harness intact and active. @element_links[(indexer)][:content].clear @element_links[(indexer)][:loaded] = false end end result = true end else raise ArgumentError, "You must specify with an Integer, not a #{indexer.class.inspect}" end else raise Exception, "Database not available" end else raise Exception, "Attempted to access a defunct structure" end result end
unpersist()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 1704 def unpersist() result = [] if self.alive? # export_db = [{:parent => nil, :parent_selector => nil, :object => self, :record => result}] children_of = Proc.new do |the_parent=nil| list = [] export_db.each do |node| if node[:parent].object_id == the_parent.object_id list << node end end list end # Build up export_db: self.search do |the_value, the_selector, the_container| if the_value.is_a?(::GxG::Database::PersistedHash) export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => {}} else if the_value.is_a?(::GxG::Database::PersistedArray) export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => []} else export_db << {:parent => the_container, :parent_selector => the_selector.clone, :object => the_value, :record => the_value} end end end # Collect children export content: link_db =[(export_db[0])] while link_db.size > 0 do entry = link_db.shift children_of.call(entry[:object]).each do |the_child| entry[:record][(the_child[:parent_selector])] = the_child[:record] if the_child[:object].is_any?(::GxG::Database::PersistedHash, ::GxG::Database::PersistedArray) link_db << the_child end end end # end result end
uuid()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 512 def uuid() @uuid.clone end
version(input=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 516 def version(input=nil) @version.clone end
version=(the_version=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 520 def version=(the_version=nil) if the_version.is_a?(::Numeric) @version = (((the_version.to_f) * 10000.0).to_i.to_f / 10000.0) end end
wait_for_reservation(timeout=nil)
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 483 def wait_for_reservation(timeout=nil) result = true the_timeout = Time.now.to_f + (timeout || 30.0).to_f until self.get_reservation() == true do sleep 1.0 if Time.now.to_f >= the_timeout result = false break end end result end
write_permission?()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 393 def write_permission?() @permission[:write] end
write_reserved?()
click to toggle source
# File lib/gxg/gxg_database_persistedarray.rb, line 397 def write_reserved?() if @reservation or @delegate true else false end end