active_redis 0.0.5 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +6 -14
  2. data/README.md +9 -5
  3. data/Rakefile +7 -0
  4. data/active_redis.gemspec +3 -0
  5. data/lib/active_redis.rb +9 -0
  6. data/lib/active_redis/associations.rb +25 -24
  7. data/lib/active_redis/associations/association.rb +36 -0
  8. data/lib/active_redis/associations/belongs_to_association.rb +32 -0
  9. data/lib/active_redis/associations/has_many_association.rb +26 -0
  10. data/lib/active_redis/associations/has_one_association.rb +24 -0
  11. data/lib/active_redis/attributes.rb +5 -4
  12. data/lib/active_redis/attributes/integer_attribute.rb +2 -2
  13. data/lib/active_redis/attributes/string_attribute.rb +2 -2
  14. data/lib/active_redis/attributes/time_attribute.rb +2 -2
  15. data/lib/active_redis/base.rb +4 -4
  16. data/lib/active_redis/config.rb +13 -10
  17. data/lib/active_redis/connection_ext/finders_layer.rb +12 -3
  18. data/lib/active_redis/constants.rb +2 -0
  19. data/lib/active_redis/errors.rb +6 -0
  20. data/lib/active_redis/helpers/lua_scripts.rb +7 -0
  21. data/lib/active_redis/inspector.rb +1 -1
  22. data/lib/active_redis/logs/basic_log.rb +11 -0
  23. data/lib/active_redis/logs/console_log.rb +14 -0
  24. data/lib/active_redis/logs/query_logger.rb +29 -0
  25. data/lib/active_redis/lua_scripts/main.lua +127 -50
  26. data/lib/active_redis/naming.rb +2 -0
  27. data/lib/active_redis/persistence.rb +12 -1
  28. data/lib/active_redis/query_chainer.rb +61 -0
  29. data/lib/active_redis/query_executor.rb +24 -0
  30. data/lib/active_redis/query_iterator.rb +27 -0
  31. data/lib/active_redis/railtie.rb +4 -2
  32. data/lib/active_redis/relation.rb +18 -0
  33. data/lib/active_redis/version.rb +1 -1
  34. data/specs/associations_spec.rb +94 -0
  35. data/specs/attributes_spec.rb +221 -0
  36. data/specs/calculations_spec.rb +28 -0
  37. data/specs/config_spec.rb +27 -0
  38. data/specs/inspector_spec.rb +45 -0
  39. data/specs/naming_spec.rb +56 -0
  40. data/specs/test_helper.rb +7 -0
  41. metadata +77 -18
  42. data/lib/active_redis/finders.rb +0 -22
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MDI3NjI4MjQwYjg4NmI4YTQzMjk1Y2RkYTdmMzk1ZDA3MWM4YjM0OA==
5
- data.tar.gz: !binary |-
6
- MDdjN2ViZGVlODZhNDdkMGQ1OWRmNWQ3NzE5ZGY1MGQ2NzkzMGFiOA==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- MTliYzEyZDQxOTgxY2MyZWVhZjlmOTg5MTZkMjk3OWMwZjVhMmU4MzQyMDJj
10
- Y2U0YzA3MTEyYTk5ZWU2OWQwYWM1ZWFhMTU1ZTIzNzY0ZDBkNDFkMjIyMWU5
11
- NGM5NzEzOGFmZjA2MDU1MDIzNzNkYWVjNmRkNjg1M2VmNGM0NjQ=
12
- data.tar.gz: !binary |-
13
- Y2ZlMzRiYzAzNjJkMmRmY2RkZjFkNGFlMmEzMWFkNWMxYWE3NGVhZTVlNWVh
14
- ZDY5Yjk4ZWFlZTU4MmUyZmI2ZDUxOGQyNjkxM2IyNTY3OWJlMWQzZmNhZDJk
15
- YThiMmE4ZDMyMGI5YjY3Yjk0MmI5NzliYWI3NTc0ODlkZGVmYmU=
2
+ SHA1:
3
+ metadata.gz: 045f4c85e0aeb767fd6391f797427c932771c9b7
4
+ data.tar.gz: 9e250673aa1a847c1bdd33a1f85550ea9cedc8e1
5
+ SHA512:
6
+ metadata.gz: 3f54e5432066d8cd19c9844e84dc37b68d4a15bc02c2b13dc7ee618a9934c0edae3aa23685f835a45fdf69dd50b01ed64e20f6bbb41916da8f417a400c26961b
7
+ data.tar.gz: 91f1c901ff380025adc212ff0adb214d7f2c6577cffbd0017f3cf4f99752d4c4ded90efd9a74112cbad9350315f66421fd9a6b502b65b0df5faed39bbd7c3598
data/README.md CHANGED
@@ -83,7 +83,7 @@ p Article.count # => 0
83
83
 
84
84
  #### belongs_to association
85
85
 
86
- ### Finders and Calculations
86
+ ### Finders
87
87
 
88
88
  You may find 'row' by it's id
89
89
 
@@ -101,10 +101,6 @@ end
101
101
  Article.create(views: 1000, link: "http://someblog.com/1", title: "Title article")
102
102
  Article.create(views: 3000, link: "http://someblog.com/2", title: "Title article")
103
103
 
104
- Article.sum(:views) # => 4000
105
- Article.min(:views) # => 1000
106
- Article.max(:views) # => 3000
107
- Article.pluck(:id) # => ["1", "2"]
108
104
  ```
109
105
 
110
106
  From version 0.0.2 you are able to search item by multiple attributes using method __where__
@@ -136,6 +132,14 @@ class User < ActiveRedis::Base
136
132
  end
137
133
  ```
138
134
 
135
+ ## NEW IN VERSION 0.0.7
136
+
137
+ Method chaining. Now you may calling __where__, __order__, __limit__ something like this:
138
+
139
+ ```ruby
140
+ Article.where(title: "Article title").where(views: 1000).order(title: :asc).limit(per_page: 20, page: 3)
141
+ ```
142
+
139
143
  ## Contributing
140
144
 
141
145
  1. Fork it
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rake/notes/rake_task'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs.push "lib"
7
+ t.test_files = FileList['specs/*_spec.rb']
8
+ t.verbose = true
9
+ end
data/active_redis.gemspec CHANGED
@@ -20,8 +20,11 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "redis"
22
22
  spec.add_dependency "activesupport"
23
+ spec.add_dependency "colorize"
23
24
 
24
25
  spec.add_development_dependency "bundler", "~> 1.3"
25
26
  spec.add_development_dependency "rake"
26
27
  spec.add_development_dependency "rake-notes"
28
+ spec.add_development_dependency "mocha"
29
+ spec.add_development_dependency "turn"
27
30
  end
data/lib/active_redis.rb CHANGED
@@ -21,4 +21,13 @@ module ActiveRedis
21
21
  def self.connection=(value)
22
22
  @connection = value
23
23
  end
24
+
25
+ def self.log
26
+ raise ActiveRedis::NoLogError, "Connection not provided!" unless @log
27
+ @log
28
+ end
29
+
30
+ def self.log=(value)
31
+ @log = value
32
+ end
24
33
  end
@@ -1,40 +1,41 @@
1
+ Dir[File.dirname(__FILE__) + '/associations/*.rb'].each {|file| require file }
2
+ require 'active_redis/constants'
3
+ require 'active_redis/errors'
4
+
1
5
  module ActiveRedis
2
6
  module Associations
3
7
 
4
8
  def self.included(base)
5
9
  base.extend ClassMethods
10
+ class << base; attr_accessor :associations; end
11
+ base.send :alias_method_chain, :save, :associations
12
+ end
13
+
14
+ def save_with_associations
15
+ self.class.associations.each { |key, a| a.save(self) }
16
+ save_without_associations
6
17
  end
7
18
 
8
19
  module ClassMethods
9
20
 
10
- def has_one(name)
11
- define_method name.to_s do
12
- name.to_s.capitalize.constantize.where("#{self.class.foreign_key_name}" => self.id).first
13
- end
14
- define_method "#{name.to_s}=" do |value|
15
- value.send "#{self.class.foreign_key_name}=", self.id
16
- end
21
+ ActiveRedis::Constants::ASSOCIATIONS.each do |assoc|
22
+ class_eval <<-CODE
23
+ def #{assoc.to_s}(name, options = {})
24
+ register_association name, :#{assoc.to_s}, options
25
+ end
26
+ CODE
17
27
  end
18
28
 
19
- def has_many(name)
20
- define_method name.to_s do
21
- name.to_s.singularize.capitalize.constantize.where("#{self.class.foreign_key_name}" => self.id)
22
- end
23
- define_method "#{name.to_s}=" do |value|
24
- value.each do |object|
25
- object.send "#{self.class.foreign_key_name}=", self.id
26
- end
27
- end
29
+ def association(name)
30
+ raise UnregisteredAssociationError, "Unknown association :#{name}!" unless self.associations.has_key? name.to_sym
31
+ self.associations[name.to_sym]
28
32
  end
29
33
 
30
- def belongs_to(name)
31
- define_attributes_accessors "#{name.to_s}_id" => :integer
32
- define_method name.to_s do
33
- name.to_s.capitalize.constantize.find(self.send("#{name.to_s}_id"))
34
- end
35
- define_method "#{name.to_s}=" do |value|
36
- self.send "#{name.to_s}_id=", value.id
37
- end
34
+ private
35
+
36
+ def register_association(name, type, options)
37
+ self.associations ||= {}
38
+ self.associations[name.to_sym] = "ActiveRedis::Associations::#{type.to_s.classify}Association".constantize.new(name, self, options)
38
39
  end
39
40
 
40
41
  end
@@ -0,0 +1,36 @@
1
+ module ActiveRedis
2
+ module Associations
3
+
4
+ class Association
5
+
6
+ def initialize(name, target, options = {})
7
+ @name, @target = name, target
8
+ define_read_association
9
+ define_write_association
10
+ end
11
+
12
+ def reload(object)
13
+ object.send :instance_variable_set, "@assoc_#{@name}", nil
14
+ end
15
+
16
+ private
17
+
18
+ def define_read_association
19
+ @target.class_eval <<-CODE
20
+ def #{@name}
21
+ @assoc_#{@name} ||= self.class.association(:#{@name}).read(self)
22
+ end
23
+ CODE
24
+ end
25
+
26
+ def define_write_association
27
+ @target.class_eval <<-CODE
28
+ def #{@name}=(value)
29
+ @assoc_#{@name} = value
30
+ end
31
+ CODE
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ module ActiveRedis
2
+ module Associations
3
+
4
+ class BelongsToAssociation < Association
5
+
6
+ DEFAULT_OPTIONS = {touch: false}
7
+
8
+ def initialize(name, target, options = {})
9
+ super
10
+ @options ||= DEFAULT_OPTIONS.merge(options)
11
+ target.define_attributes_accessors("#{@name.to_s}_id" => :integer)
12
+ end
13
+
14
+ def read(object)
15
+ @name.to_s.capitalize.constantize.where(id: object.send("#{@name.to_s}_id")).top
16
+ end
17
+
18
+ def write(object, value)
19
+ object.send "#{@name.to_s}_id=", value.id
20
+ end
21
+
22
+ def save(object)
23
+ value = object.send :instance_variable_get, "@assoc_#{@name}"
24
+ return unless value
25
+ write(object, value)
26
+ value.touch if @options[:touch]
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ module ActiveRedis
2
+ module Associations
3
+
4
+ class HasManyAssociation < Association
5
+
6
+ def read(object)
7
+ @name.to_s.singularize.capitalize.constantize.where("#{@target.foreign_key_name}" => object.id)
8
+ end
9
+
10
+ def write(object, value)
11
+ value.each do |assoc_object|
12
+ assoc_object.send "#{@target.foreign_key_name}=", object.id
13
+ end
14
+ end
15
+
16
+ def save(object)
17
+ value = object.send :instance_variable_get, "@assoc_#{@name}"
18
+ return unless value
19
+ write object, value
20
+ value.each { |v| v.save }
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ module ActiveRedis
2
+ module Associations
3
+
4
+ class HasOneAssociation < Association
5
+
6
+ def read(object)
7
+ @name.to_s.capitalize.constantize.where("#{@target.foreign_key_name}" => object.id).top
8
+ end
9
+
10
+ def write(object, value)
11
+ value.send "#{@target.foreign_key_name}=", object.id
12
+ end
13
+
14
+ def save(object)
15
+ value = object.send :instance_variable_get, "@assoc_#{@name}"
16
+ return unless value
17
+ write object, value
18
+ value.save
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+ end
@@ -23,7 +23,7 @@ module ActiveRedis
23
23
 
24
24
  module ClassMethods
25
25
 
26
- def attributes(attrs)
26
+ def attributes(attrs = {})
27
27
  raise ActiveRedis::InvalidArgumentError, "Value must be a Hash!" unless attrs.is_a?(Hash)
28
28
  attrs = attrs.merge(ActiveRedis::Constants::DEFAULT_ATTRIBUTES)
29
29
  class << self; attr_accessor :defined_attributes; end
@@ -46,15 +46,16 @@ module ActiveRedis
46
46
  private
47
47
 
48
48
  def register_attribute(attribute, type)
49
- return if self.defined_attributes.has_key? attribute.to_sym
49
+ return false if self.defined_attributes.has_key? attribute.to_sym
50
50
  self.defined_attributes[attribute.to_sym] = {
51
51
  class: "ActiveRedis::Attributes::#{type.to_s.capitalize}Attribute".constantize,
52
52
  type: type
53
53
  }
54
+ true
54
55
  end
55
56
 
56
57
  def attribute_class(attribute)
57
- attr_class = self.defined_attributes[attribute.to_sym][:class]
58
+ self.defined_attributes[attribute.to_sym][:class]
58
59
  end
59
60
 
60
61
  def read_attribute(attribute)
@@ -67,7 +68,7 @@ module ActiveRedis
67
68
  def write_attribute(attribute)
68
69
  define_method "#{attribute}=" do |value|
69
70
  klass = self.class.send :attribute_class, attribute
70
- klass.dump(instance_variable_set("@#{attribute}", value))
71
+ instance_variable_set("@#{attribute}", klass.dump(value))
71
72
  end
72
73
  end
73
74
 
@@ -3,11 +3,11 @@ module ActiveRedis
3
3
  class IntegerAttribute < Attribute
4
4
 
5
5
  def self.load(value)
6
- value.to_i
6
+ value.nil? || value.empty? ? nil : value.to_i
7
7
  end
8
8
 
9
9
  def self.dump(value)
10
- value.to_s
10
+ value ? value.to_s : nil
11
11
  end
12
12
 
13
13
  end
@@ -3,11 +3,11 @@ module ActiveRedis
3
3
  class StringAttribute < Attribute
4
4
 
5
5
  def self.load(value)
6
- value.to_s
6
+ value.nil? || value.empty? ? nil : value.to_s
7
7
  end
8
8
 
9
9
  def self.dump(value)
10
- value.to_s
10
+ value ? value.to_s : nil
11
11
  end
12
12
 
13
13
  end
@@ -3,11 +3,11 @@ module ActiveRedis
3
3
  class TimeAttribute < Attribute
4
4
 
5
5
  def self.load(value)
6
- Time.at(value.to_i)
6
+ value.nil? || value.empty? ? nil : Time.at(value.to_i)
7
7
  end
8
8
 
9
9
  def self.dump(value)
10
- value.to_i.to_s
10
+ value ? value.to_i.to_s : nil
11
11
  end
12
12
 
13
13
  end
@@ -3,20 +3,20 @@ require 'active_redis/associations'
3
3
  require 'active_redis/persistence'
4
4
  require 'active_redis/naming'
5
5
  require 'active_redis/calculations'
6
- require 'active_redis/finders'
7
6
  require 'active_redis/inspector'
7
+ require 'active_redis/relation'
8
8
 
9
9
  # TODO: Add Expiring module
10
10
 
11
11
  module ActiveRedis
12
12
  class Base
13
13
  extend Naming
14
- extend Calculations
15
- extend Finders
14
+ # extend Calculations
15
+ extend Relation
16
16
 
17
17
  include Attributes
18
- include Associations
19
18
  include Persistence
19
+ include Associations
20
20
  include Inspector
21
21
 
22
22
  end
@@ -1,14 +1,17 @@
1
1
  class ActiveRedis::Config
2
- # Specify connection string to Redis. To check all available options please see redis-rb library.
3
- #
4
- # Some samples:
5
- # ActiveRedis.config.connection_options = {host: 10.10.1.1, port: 6380}
6
- # or
7
- # ActiveRedis.config.connection_options = {path: '/tmp/redis.sock'}
8
- attr_accessor :connection_options
2
+ # Specify connection string to Redis. To check all available options please see redis-rb library.
3
+ #
4
+ # Some samples:
5
+ # ActiveRedis.config.connection_options = {host: 10.10.1.1, port: 6380}
6
+ # or
7
+ # ActiveRedis.config.connection_options = {path: '/tmp/redis.sock'}
8
+ attr_accessor :connection_options
9
9
 
10
- # Specify adapter for connection to DB
11
- # By default it's ActiveRedis::Adapters::BasicAdapter
12
- attr_accessor :adapter
10
+ # Specify adapter for connection to DB
11
+ # By default it's ActiveRedis::Adapters::BasicAdapter
12
+ attr_accessor :adapter
13
13
 
14
+ # Specify log
15
+ # By default it's ActiveRedis::Logs::ConsoleLog
16
+ attr_accessor :log
14
17
  end
@@ -1,20 +1,29 @@
1
+ require 'active_redis/logs/query_logger'
2
+
1
3
  module ActiveRedis::ConnectionExt
2
4
  module FindersLayer
3
5
 
6
+ def self.included(base)
7
+ base.send :extend, ActiveRedis::Logs::QueryLogger
8
+ base.loggable :run_query_analyzer
9
+ end
10
+
4
11
  def fetch_row(model, id)
5
- adapter.hgetall model.table_name(id)
12
+ fetch_where(model, id: id).first
6
13
  end
7
14
 
8
15
  def fetch_keys(model)
16
+ ActiveRedis.log.write "Calling ActiveRedis::ConnectionExt::FindersLayer::fetch_keys(#{model.name})"
9
17
  adapter.keys model.key_name
10
18
  end
11
19
 
12
20
  def fetch_where(model, params)
21
+ ActiveRedis.log.write "Calling ActiveRedis::ConnectionExt::FindersLayer::fetch_where(#{model.name}, #{params})"
13
22
  run_eval :where, [model.key_name], params.flatten
14
23
  end
15
24
 
16
- def fetch_all(model)
17
- fetch_where model, {}
25
+ def run_query_analyzer(model, params = ["", "", ""])
26
+ run_eval :query_analyzer, [model.key_name, Time.now.to_i], params
18
27
  end
19
28
 
20
29
  end