active_redis 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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