#:enddoc: module RailsConnector class Workspace < CmsBaseModel self.key_prefix = "rev" property :generation property :base_revision_id property :title property :content_cache_id property :attributes property :obj_classes # TODO remove when renaming workspace to revision in code def base_workspace_id base_revision_id end # Selects the workspace with the given id as current workspace def self.current=(workspace) @current = workspace end def self.current @current || Workspace.default end def self.find_by_label(label_name) label = WorkspaceLabel.find(label_name) find(label.workspace_id) end def self.default Workspace.find_by_label("published") end def find_obj_data_by(index, keys) find_obj_data_from_cache_or_database_by(index, keys) end def chain @chain ||= Chain.build_for(self, content_cache) end def invalidate_chain @chain = nil end # returns the base workspace or nil for an initial workspace def base_workspace @base_workspace ||= base_workspace_id ? Workspace.find(base_workspace_id) : nil end # returns the content cache to be used with this workspace or nil if not available def content_cache if content_cache_id if @content_cache && content_cache_id == @content_cache.id @content_cache else @content_cache = ContentCache.find_by_id(content_cache_id) end end end def inspect "<#{self.class} id=\"#{id}\" title=\"#{title}\">" end private COMPOUND_KEY_INDICES = [:ppath].freeze def find_obj_data_from_database_by(index, keys) return [] if keys.blank? instrumenter = ActiveSupport::Notifications.instrumenter instrumenter.instrument( "cms_load.rails_connector", :name => "Obj Load", :index => index, :keys => keys ) do keys.map do |key| results = chain.query(index, key, COMPOUND_KEY_INDICES.include?(index)) results.values.map { |row| extract_obj_data(row) } end end end def find_obj_data_from_cache_or_database_by(index, keys) # load results from cache keys_from_database = [] results_from_cache = keys.map do |key| Cache.load([:obj, index, key]).tap do |objs| keys_from_database << key unless objs end end # load cache misses from database and store them in cache results_from_database = find_obj_data_from_database_by(index, keys_from_database) keys_from_database.each_with_index do |key, key_number| store_obj_data_list_in_cache(index, key, results_from_database[key_number]) end # combine the results results_from_cache.map do |objs_from_cache| objs_from_cache || results_from_database.shift end end UNIQUE_INDICES = [:id, :path, :permalink].freeze OBJ_PROPERTY_VALUE_TO_RANGE_VALUE_CONVERSIONS = { :path => PathConversion.method(:path_from_list) }.freeze def store_obj_data_list_in_cache(index, key, obj_data_list) obj_data_list.each do |obj_data| values = obj_data["values"] UNIQUE_INDICES.each do |unique_index| index_value = values["_#{unique_index}"] if (converter = OBJ_PROPERTY_VALUE_TO_RANGE_VALUE_CONVERSIONS[unique_index]) index_value = converter.call(index_value) end store_item_in_cache(unique_index, index_value, [obj_data]) end end unless UNIQUE_INDICES.include?(index) store_item_in_cache(index, key, obj_data_list) end end def store_item_in_cache(index, key, item) Cache.store([:obj, index, key], item) end def extract_obj_data(data) { "values" => data["values"].merge( "_id" => data["obj_id"], "_obj_type" => data["obj_type"], "_obj_class" => data["obj_class"]["name"] ), "attributes" => data["attributes"] } end end end