lib/redis-model-extension.rb in redis-model-extension-0.3.8 vs lib/redis-model-extension.rb in redis-model-extension-0.4.0

- old
+ new

@@ -1,341 +1,73 @@ # -*- encoding : utf-8 -*- require 'pp' require 'yaml' +require 'json' require 'redis' +require 'active_model' require 'active_support' require 'active_support/inflector' require 'active_support/inflector/inflections' require 'active_support/core_ext/hash/keys' +require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/class/inheritable_attributes' require 'string_to_bool' require 'database' -module RedisModel - - attr_accessor :args, :error, :old_args, :conf - +module RedisModelExtension + extend ActiveSupport::Concern + #include all needed modules directly into main class def self.included(base) - base.send :extend, ClassMethods - base.send :include, InstanceMethods - end - - module ClassMethods - - def initialize_redis_model_methods conf - @conf = {:reject_nil_values => true}.merge(conf) - #take all fields and make methods for them - conf[:fields].each do |attr, action| - define_method "#{attr}" do - if self.args[attr] || self.args[attr] == false #== false is a fi for boolean variable - self.args[attr].to_s.send(action) - else - nil - end - end - - define_method "#{attr}=" do |item| - self.args[attr] = item - end - - define_method "#{attr}?" do - !self.args[attr].nil? - end - end - end - - def conf - @conf - end - - #Generates redis key for storing object - def generate_key(args = {}) - out = "#{self.name.to_s.underscore.to_sym}:key" - @conf[:redis_key].each do |key| - if args.has_key?(key) - out += ":#{args[key]}" - else - out += ":*" - end - end - out - end - - #Generates redis key for storing indexes for aliases - def generate_alias_key(alias_name, args = {}) - out = "#{self.name.to_s.underscore.to_sym}:alias:#{alias_name}" - @conf[:redis_aliases][alias_name.to_sym].each do |key| - if args.has_key?(key) - out += ":#{args[key]}" - else - out += ":*" - end - end - out - end - - #Validates if key by arguments is valid - def valid_key?(args = {}) - full_key = true - @conf[:redis_key].each do |key| - full_key = false if !args.has_key?(key) || args[key].nil? - end - full_key - end + base.class_eval do + extend ClassInitialize + extend ClassOldInitialize + extend ClassConfig + extend ClassGetFind + extend ClassRedisKey + extend ClassCreate + extend ClassValidations + extend ClassAutoincrementId - #Validates if key by alias name and arguments is valid - def valid_alias_key?(alias_name, args = {}) - full_key = true - @conf[:redis_aliases][alias_name.to_sym].each do |key| - full_key = false if !args.has_key?(key) || args[key].nil? - end - full_key + include Initialize + include ActiveModelIntegration + include Attributes + include AutoincrementId + include RedisKey + include StoreKeys + include Config + include SaveDestroy + include Validations + include ValueTransform end + end - #Check if key by arguments exists in db - def exists?(args = {}) - RedisModelExtension::Database.redis.exists(self.name.constantize.generate_key(args)) - end + module ActiveModelIntegration + def self.included(base) + base.class_eval do + include ActiveModel::AttributeMethods + include ActiveModel::Validations + include ActiveModel::Naming + include ActiveModel::Conversion - #Check if key by alias name and arguments exists in db - def alias_exists?(alias_name, args = {}) - RedisModelExtension::Database.redis.exists(self.name.constantize.generate_alias_key(alias_name, args)) - end - - #Wrapper around find to get all instances - def all - self.find({}) - end - - #Find method for searching in redis - def find(args = {}) - args.symbolize_keys! - out = [] - klass = self.name.constantize - - #is key specified directly? -> no needs of looking for other keys! -> faster - if klass.valid_key?(args) - if klass.exists?(args) - data_args = RedisModelExtension::Database.redis.hgetall(klass.generate_key(args)) - out << klass.new(args.merge(data_args).merge({:old_args => data_args})) - end - else - RedisModelExtension::Database.redis.keys(klass.generate_key(args)).each do |key| - data_args = RedisModelExtension::Database.redis.hgetall(key) - out << klass.new(args.merge(data_args).merge({:old_args => data_args})) - end + extend ActiveModel::Callbacks + define_model_callbacks :save, :destroy, :create end - out end - - #Find method for searching in redis - def find_by_alias(alias_name, args = {}) - args.symbolize_keys! - out = [] - klass = self.name.constantize - - #is key specified directly? -> no needs of looking for other keys! -> faster - if klass.valid_alias_key?(alias_name, args) - out << klass.get_by_alias(alias_name, args) if klass.alias_exists?(alias_name, args) - else - RedisModelExtension::Database.redis.keys(klass.generate_alias_key(alias_name, args)).each do |key| - out << klass.get_by_alias_key(key) - end - end - out - end - - #fastest method to get object from redis by getting it by arguments - def get(args = {}) - args.symbolize_keys! - klass = self.name.constantize - if klass.valid_key?(args) && klass.exists?(args) - data_args = RedisModelExtension::Database.redis.hgetall(klass.generate_key(args)) - klass.new(args.merge(data_args).merge({:old_args => data_args})) - else - nil - end - end - - #if you know redis key and would like to get object - def get_by_redis_key(redis_key) - if redis_key.is_a?(String) && RedisModelExtension::Database.redis.exists(redis_key) - unless redis_key.include?("*") - data_args = RedisModelExtension::Database.redis.hgetall(redis_key) - klass = self.name.constantize - klass.new(data_args.merge({:old_args => data_args})) - else - raise ArgumentError, "RedisKey for method get_by_redis_key can not contains '*'" - end - else - nil - end - end - - #fastest method to get object from redis by getting it by alias and arguments - def get_by_alias(alias_name, args = {}) - args.symbolize_keys! - klass = self.name.constantize - if klass.valid_alias_key?(alias_name, args) && klass.alias_exists?(alias_name, args) - key = RedisModelExtension::Database.redis.get(klass.generate_alias_key(alias_name, args)) - if RedisModelExtension::Database.redis.exists(key) - data_args = RedisModelExtension::Database.redis.hgetall(key) - klass.new(args.merge(data_args).merge({:old_args => data_args})) - else - nil - end - else - nil - end - end - - #fastest method to get object from redis by getting it by alias and arguments - def get_by_alias_key(alias_key) - klass = self.name.constantize - if RedisModelExtension::Database.redis.exists(alias_key) - key = RedisModelExtension::Database.redis.get(alias_key) - if RedisModelExtension::Database.redis.exists(key) - klass.new(args.merge(RedisModelExtension::Database.redis.hgetall(key)).merge({:old_args => key})) - else - nil - end - else - nil - end - end - end - - module InstanceMethods - - def initialize(args={}) - args.symbolize_keys! - #if old_args is specified, don't usi it in args hash - if args[:old_args] && args[:old_args].size > 0 - self.old_args = args.delete(:old_args).symbolize_keys - end - self.args = clear_args(args) - return self - end - - #Fixing some problems with saving nil into redis and clearing input arguments - def clear_args(args) - args.symbolize_keys! - out_args = {} - args.each do |key, value| - if self.class.conf[:fields].keys.include?(key) #don't use arguments wich aren't specified in :fields - if value.nil? || value.to_s.size == 0 #change nil and zero length string into nil - out_args[key] = nil - else - out_args[key] = value - end - end - end - out_args - end - - #validates required attributes - def valid? - @error ||= [] - self.class.conf[:required].each do |key| - if !self.args.has_key?(key) || self.args[key].nil? - @error.push("Required #{key}") - end - end - @error.size == 0 - end +end - #return error from validation - def error - @error ||= [] - end - - #return error from validation - def errors - @error ||= [] - end - - #take all arguments and send them out - def to_arg - self.args.inject({}) do |output, item| - output[item.first] = item.last.send(self.class.conf[:fields][item.first.to_sym]) - output - end - end - - #if this record exists in database - def exists? - RedisModelExtension::Database.redis.exists(self.class.generate_key(self.args)) - end - - #remove record form database - def destroy! - if exists? - #destroy main object - RedisModelExtension::Database.redis.del(redis_key) - destroy_aliases! - end - end - - #remove all aliases - def destroy_aliases! - #do it only if it is existing object! - if self.old_args - self.class.conf[:redis_aliases].each do |alias_name, fields| - if self.class.valid_alias_key?(alias_name, self.old_args) && self.class.alias_exists?(alias_name, self.old_args) - RedisModelExtension::Database.redis.del(self.class.generate_alias_key(alias_name, self.old_args)) - end - end - end - end - - #Method for creating aliases - def create_aliases - main_key = redis_key - self.class.conf[:redis_aliases].each do |alias_name, fields| - RedisModelExtension::Database.redis.set(self.class.generate_alias_key(alias_name, self.args), main_key) if self.class.valid_alias_key?(alias_name, self.args) - end - end - - #get redis key for instance - def redis_key - self.class.generate_key(self.args) - end - - #get redis key for instance alias - def redis_alias_key(alias_name) - self.class.generate_alias_key(alias_name, self.args) - end - - #update multiple attrubutes at once - def update args - args.each do |key, value| - method = "#{key}=".to_sym - if self.respond_to? method - self.send(method, value) - end - end - end - - #save method - def save - if valid? - #generate key (possibly new) - generated_key = redis_key - RedisModelExtension::Database.redis.rename(self.class.generate_key(self.old_args), generated_key) if self.old_args && generated_key != self.class.generate_key(self.old_args) && RedisModelExtension::Database.redis.exists(self.class.generate_key(self.old_args)) - args = self.class.conf[:reject_nil_values] ? self.args.reject{|k,v| v.nil?} : self.args - RedisModelExtension::Database.redis.hmset(generated_key, *args.inject([]){ |arr,kv| arr + [kv[0], kv[1].to_s]}) - - #destroy aliases - destroy_aliases! - create_aliases - #after save make new_key -> old_key - self.old_args = self.args.clone - return self - else - raise ArgumentError, @error.join(", ") - end - end - end -end \ No newline at end of file +#require all additional modules +require 'redis-model-extension/config' +require 'redis-model-extension/initialize' +require 'redis-model-extension/old_initialize' +require 'redis-model-extension/value_transform' +require 'redis-model-extension/redis_key' +require 'redis-model-extension/get_find' +require 'redis-model-extension/validation' +require 'redis-model-extension/attributes' +require 'redis-model-extension/save_destroy' +require 'redis-model-extension/store_keys' +require 'redis-model-extension/autoincrement_id' +#bad naming in past, will be removed +require 'redis-model'