class DoesKeyValue::Index

Public Class Methods

delete_index(object, key_name) click to toggle source

Delete an index record for a given object/key combination:

# File lib/doeskeyvalue/index.rb, line 84
def self.delete_index(object, key_name)
  object_type = object.class.to_s
  object_id = object.id

  deleted_count = table_agnostic_exec(object.class) do
    DoesKeyValue::Index.delete_all(
      obj_type: object_type, obj_id: object_id, key_name: key_name
    )
  end
end
find_objects(klass, key_name, value) click to toggle source

Search the database for objects matching the given query for the given key:

# File lib/doeskeyvalue/index.rb, line 19
def self.find_objects(klass, key_name, value)
  object_type = klass.to_s
  key_type = klass.key_options(key_name)[:type]

  condition_set = {obj_type: object_type, key_name: key_name, key_type: key_type, "value_#{key_type}"=>value}
  DoesKeyValue.log("Condition Set for index find: #{condition_set.inspect}")
  table_agnostic_exec(klass) do
    index_rows = DoesKeyValue::Index.where(condition_set)
    object_ids = index_rows.blank? ? [] : index_rows.collect {|i| i.obj_id }
    klass.where(:id=>object_ids)
  end
end
read_index(object, key_name) click to toggle source

Read the appropriate index values for the given object/key combination:

# File lib/doeskeyvalue/index.rb, line 34
def self.read_index(object, key_name)
  object_type = object.class.to_s
  object_id = object.id
  key_type = object.class.key_options(key_name)[:type]

  # Prepare the query conditions:
  condition_set = {obj_type: object_type, obj_id: object_id, key_name: key_name}

  # Access the appropriate value column of the returned index:
  table_agnostic_exec(object.class) do 
    DoesKeyValue::Index.where(condition_set).first().try(:send, "value_#{key_type}")
  end
end
update_index(object, key_name, value) click to toggle source

Update the appropriate index with new/changed information for the given object/key/value combination:

# File lib/doeskeyvalue/index.rb, line 51
def self.update_index(object, key_name, value)
  # Log our index column values:
  object_type = object.class.to_s
  object_id = object.id
  key_type = object.class.key_options(key_name)[:type]

  # Prepare update conditions and manipulators:
  update_set = {key_type: key_type}
  condition_set = {obj_type: object_type, obj_id: object_id, key_name: key_name}
  create_set = {obj_type: object_type, obj_id: object_id, key_name: key_name, key_type: key_type}

  # Insert the new value of the correct type:
  update_set["value_#{key_type}"] = value
  create_set["value_#{key_type}"] = value

  DoesKeyValue.log("Updating Index for class:#{object_type} key:#{key_name}:")
  DoesKeyValue.log("update_set: #{update_set.inspect}")
  DoesKeyValue.log("condition_set: #{condition_set.inspect}")
  DoesKeyValue.log("create_set: #{create_set.inspect}")

  # Update an index in a table-agnostic way to support table-based key-value storage in
  # database tables other than the universal table:
  table_agnostic_exec(object.class) do
    updated_count = DoesKeyValue::Index.update_all( update_set, condition_set )
    if !value.nil? && updated_count == 0
      DoesKeyValue::Index.create( create_set )
    end
  end

end

Private Class Methods

table_agnostic_exec(klass) { || ... } click to toggle source

Perform a block action inside of table-altered query:

# File lib/doeskeyvalue/index.rb, line 106
def self.table_agnostic_exec(klass)
  begin
    original_table_name = DoesKeyValue::Index.table_name
    if DoesKeyValue::Index.table_storage_for_class?(klass)
      class_storage_options = DoesKeyValue::State.instance.options_for_class(klass)
      if class_storage_options[:table]
        DoesKeyValue::Index.table_name = class_storage_options[:table]
        DoesKeyValue.log("Storage table for index changed to '#{DoesKeyValue::Index.table_name}'")
      end
    end

    exec_result = yield

    if DoesKeyValue::Index.table_storage_for_class?(klass)
      DoesKeyValue::Index.table_name = original_table_name
      DoesKeyValue.log("Storage table for index changed back to original '#{DoesKeyValue::Index.table_name}")
    end

    return exec_result

  rescue ActiveRecord::StatementInvalid => e
    DoesKeyValue.log("Database query statement invalid: #{e.message}")
    if (e.message =~ /doesn't exist/)
      DoesKeyValue.log("It appears the index table `#{DoesKeyValue::Index.table_name}` expected has not been generated.")
      DoesKeyValue.log("To generate the necessary table run: rails generate doeskeyvalue #{DoesKeyValue::Index.table_name}")
    end
    raise e

  ensure
    # Ensure that the table name is always restored
    DoesKeyValue::Index.table_name = original_table_name
    DoesKeyValue.log("After table-agnostic execution, table name restored to '#{DoesKeyValue::Index.table_name}'")
  end
end
table_storage_for_class?(klass) click to toggle source

Return true only if the storage method for the given class is table:

# File lib/doeskeyvalue/index.rb, line 100
def self.table_storage_for_class?(klass)
  storage_options = DoesKeyValue::State.instance.options_for_class(klass)
  storage_options[:table].nil? ? false : true
end