Skip to content

Commit

Permalink
feature(unique_values_lists): added methods to read and delete data
Browse files Browse the repository at this point in the history
  • Loading branch information
Napolskih committed Oct 18, 2013
1 parent 67c5200 commit b29eab7
Show file tree
Hide file tree
Showing 10 changed files with 974 additions and 167 deletions.
16 changes: 8 additions & 8 deletions lib/redis_counters/base_counter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ class BaseCounter
KEY_DELIMITER = ':'.freeze
VALUE_DELIMITER = ':'.freeze

class_attribute :key_delimiter
class_attribute :value_delimiter

self.key_delimiter = KEY_DELIMITER
self.value_delimiter = VALUE_DELIMITER

attr_reader :redis
attr_reader :options
attr_reader :params
Expand Down Expand Up @@ -60,6 +54,12 @@ def process(params = {}, &block)
process_value(&block)
end

def name
options[:counter_name]
end

alias_method :id, :name

protected

def init
Expand All @@ -71,11 +71,11 @@ def counter_name
end

def key_delimiter
@key_delimiter ||= options.fetch(:key_delimiter, self.class.key_delimiter)
@key_delimiter ||= options.fetch(:key_delimiter, KEY_DELIMITER)
end

def value_delimiter
@value_delimiter ||= options.fetch(:value_delimiter, self.class.value_delimiter)
@value_delimiter ||= options.fetch(:value_delimiter, VALUE_DELIMITER)
end

def_delegator :redis, :multi, :transaction
Expand Down
59 changes: 40 additions & 19 deletions lib/redis_counters/hash_counter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ class HashCounter < BaseCounter
def partitions(parts = {})
partitions_raw(parts).map do |part|
# parse and exclude counter_name
part = part.split(key_delimiter).from(1)
part = part.split(key_delimiter, -1).from(1)
# construct hash
HashWithIndifferentAccess[partition_keys.zip(part)]
Hash[partition_keys.zip(part)].with_indifferent_access
end
end

Expand All @@ -38,12 +38,8 @@ def partitions(parts = {})
# Returns Array Of Hash.
#
def data(parts = {})
# получаем все подпартиции
parts = partitions(parts)
# подгатавливаем в необходимом виде
parts = prepared_parts(parts)

parts.flat_map do |partition|
prepared_parts(parts).flat_map do |partition|
rows = partition_data(partition)
block_given? ? yield(rows) : rows
end
Expand Down Expand Up @@ -88,7 +84,7 @@ def delete_partitions!(parts)
# Returns Nothing.
#
def delete_partition_direct!(partition, write_session = redis)
partition = prepared_parts(partition, true)
partition = prepared_parts(partition, :only_leaf => true)
key = key(partition)
write_session.del(key)
end
Expand Down Expand Up @@ -131,43 +127,68 @@ def partition_keys
@partition_keys ||= Array.wrap(options.fetch(:partition_keys, []))
end

# Public: Возвращает массив партиций (подпартиций) в виде ключей.
#
# Если партиция не указана, возвращает все партиции.
# Protected: Возвращает массив листовых партиций в виде ключей.
#
# parts - Array of Hash - список партиций (опционально).
# По умолчанию, выбираются все данные.
#
# Returns Array of Hash.
#
def partitions_raw(parts = {})
prepared_parts(parts).flat_map do |partition|
prepared_parts(parts).inject(Array.new) do |result, partition|
strict_pattern = key(partition)
fuzzy_pattern = key(partition << '*')
redis.keys(strict_pattern) | redis.keys(fuzzy_pattern)
result |= redis.keys(strict_pattern) if strict_pattern.present?
result |= redis.keys(fuzzy_pattern) if fuzzy_pattern.present?
result
end
.uniq
end

def prepared_parts(parts, only_leaf = false)
# Protected: Возвращает массив партиций, где каждая партиция,
# представляет собой массив параметров, однозначно её идентифицирующих.
#
# parts - Array of Hash - список партиций.
# options - Hash - хеш опций:
# :only_leaf - Boolean - выбирать только листовые партиции (по умолачнию - false).
# Если флаг установлен в true и передана не листовая партиция, то
# будет сгенерировано исключение KeyError.
#
# Метод генерирует исключение ArgumentError, если переданы параметры не верно идентифицирующие партицию.
# Например: ключи партиционирования счетчика {:param1, :param2, :param3}, а переданы {:param1, :param3}.
#
# Returns Array of Array.
#
def prepared_parts(parts, options = {})
default_options = {:only_leaf => false}
options.reverse_merge!(default_options)

parts = Array.wrap(parts).map(&:with_indifferent_access)
parts.map do |partition|
partition_keys.inject(Array.new) do |result, key|
param = (only_leaf ? partition.fetch(key) : partition[key])
next result if param.nil?
param = (options[:only_leaf] ? partition.fetch(key) : partition[key])
next result unless partition.has_key?(key)
next result << param if result.size >= partition_keys.index(key)

raise ArgumentError, 'An incorrectly specified partition %s' % [partition]
end
end
end

# Protected: Возвращает данные партиции в виде массива хешей.
#
# Каждый элемент массива, представлен в виде хеша, содержащего все параметры группировки и
# значение счетчика в ключе :value.
#
# partition - Array - листовая партиция - массив параметров однозначно идентифицирующий партицию.
#
# Returns Array of WithIndifferentAccess.
#
def partition_data(partition)
keys = group_keys.dup << :value
redis.hgetall(key(partition)).inject(Array.new) do |result, (key, value)|
values = key.split(value_delimiter) << value.to_i
values = key.split(value_delimiter, -1) << value.to_i
values = values.from(1) unless group_keys.present?
result << HashWithIndifferentAccess[keys.zip(values)]
result << Hash[keys.zip(values)].with_indifferent_access
end
end
end
Expand Down
13 changes: 7 additions & 6 deletions lib/redis_counters/unique_hash_counter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,14 @@ class UniqueHashCounter < HashCounter

UNIQUE_LIST_POSTFIX_DELIMITER = '_'.freeze

class_attribute :unique_list_postfix_delimiter

self.unique_list_postfix_delimiter = UNIQUE_LIST_POSTFIX_DELIMITER
attr_reader :unique_values_list

protected

def process_value
unique_values_list.add(params) { super }
end

attr_reader :unique_values_list

def init
super
@unique_values_list = unique_values_list_class.new(
Expand All @@ -43,7 +39,12 @@ def unique_values_list_class
end

def unique_list_postfix_delimiter
@unique_list_postfix_delimiter ||= options.fetch(:unique_list_postfix_delimiter, self.class.unique_list_postfix_delimiter)
@unique_list_postfix_delimiter ||= options.fetch(:unique_list_postfix_delimiter, UNIQUE_LIST_POSTFIX_DELIMITER)
end

def partitions_raw(parts = {})
# удаляем из списка партиций, ключи в которых хранятся списки уникальных значений
super.delete_if { |partition| partition.start_with?(unique_values_list_name) }
end
end

Expand Down
Loading

0 comments on commit b29eab7

Please sign in to comment.