ca_ching 0.1.0 → 0.1.1
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.
- data/.rvmrc +48 -0
- data/Gemfile +3 -3
- data/README.md +13 -4
- data/ca_ching.gemspec +2 -2
- data/dump.rdb +0 -0
- data/lib/ca_ching/index.rb +3 -5
- data/lib/ca_ching/read_through.rb +40 -41
- data/lib/ca_ching/version.rb +1 -1
- data/lib/ca_ching/write_through.rb +22 -8
- data/spec/ca_ching/query/abstract_spec.rb +2 -2
- data/spec/ca_ching/write_through_spec.rb +29 -3
- metadata +38 -16
data/.rvmrc
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
+
# development environment upon cd'ing into the directory
|
5
|
+
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
|
7
|
+
# Only full ruby name is supported here, for short names use:
|
8
|
+
# echo "rvm use 1.9.3" > .rvmrc
|
9
|
+
environment_id="ruby-1.9.3-p194@ca_ching"
|
10
|
+
|
11
|
+
# Uncomment the following lines if you want to verify rvm version per project
|
12
|
+
# rvmrc_rvm_version="1.14.5 (stable)" # 1.10.1 seams as a safe start
|
13
|
+
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
|
14
|
+
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
|
15
|
+
# return 1
|
16
|
+
# }
|
17
|
+
|
18
|
+
# First we attempt to load the desired environment directly from the environment
|
19
|
+
# file. This is very fast and efficient compared to running through the entire
|
20
|
+
# CLI and selector. If you want feedback on which environment was used then
|
21
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
22
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
|
23
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
24
|
+
then
|
25
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
26
|
+
[[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
|
27
|
+
\. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
|
28
|
+
else
|
29
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
30
|
+
rvm --create "$environment_id" || {
|
31
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
32
|
+
return 1
|
33
|
+
}
|
34
|
+
fi
|
35
|
+
|
36
|
+
# If you use bundler, this might be useful to you:
|
37
|
+
# if [[ -s Gemfile ]] && {
|
38
|
+
# ! builtin command -v bundle >/dev/null ||
|
39
|
+
# builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null
|
40
|
+
# }
|
41
|
+
# then
|
42
|
+
# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
|
43
|
+
# gem install bundler
|
44
|
+
# fi
|
45
|
+
# if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
|
46
|
+
# then
|
47
|
+
# bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete'
|
48
|
+
# fi
|
data/Gemfile
CHANGED
@@ -3,14 +3,14 @@ source "http://rubygems.org"
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
# Development gems
|
6
|
-
gem '
|
6
|
+
gem 'debugger'
|
7
7
|
gem 'rake'
|
8
8
|
|
9
|
-
gem 'sqlite3'
|
9
|
+
gem 'sqlite3', '1.3.5'
|
10
10
|
|
11
11
|
# Testing
|
12
12
|
gem 'rspec'
|
13
13
|
gem 'machinist'
|
14
14
|
gem 'faker'
|
15
15
|
gem 'guard-rspec'
|
16
|
-
gem '
|
16
|
+
gem 'growl'
|
data/README.md
CHANGED
@@ -6,7 +6,10 @@ That means that when you read from the database, your results are stored in the
|
|
6
6
|
the database, whatever is written to the database is also written to the cache (write-through). If the results are already
|
7
7
|
in the cache, great, they're read straight from there on a read, and updated on a write.
|
8
8
|
|
9
|
-
|
9
|
+
This is definitely still alpha-level software. It's just something I thought should exist; I'm not using it in production
|
10
|
+
anywhere. It could blow up in totally unexpected, but nevertheless exciting, ways. If it does fall over, [let me know](http://github.com/ahlatimer/ca_ching/issues).
|
11
|
+
|
12
|
+
Take a look at `SPEC.md` for what's planned for v1.
|
10
13
|
|
11
14
|
## Getting started
|
12
15
|
|
@@ -50,9 +53,9 @@ miss and pull the data into the cache.
|
|
50
53
|
|
51
54
|
## Queries supported
|
52
55
|
|
53
|
-
Generally anything
|
56
|
+
Generally anything involving equality is supported by CaChing. Currently, only single fields can be found (e.g., `Person.where(:name => 'Andrew')` will be cached,
|
54
57
|
`Person.where(:name => 'Andrew', :age => 22)` is not). There is some plumbing for adding support for the latter, and support will be
|
55
|
-
introduced as soon as possible.
|
58
|
+
introduced as soon as possible. I also have plans to add limited support for comparators (i.e., <, <=, >, >=).
|
56
59
|
|
57
60
|
Anything including joins, includes, `OR`, and inequality (!=) are not supported, nor do I have any plans for adding support.
|
58
61
|
|
@@ -75,7 +78,7 @@ These queries are not:
|
|
75
78
|
|
76
79
|
### Order
|
77
80
|
|
78
|
-
Order is not currently supported, although there will be some order
|
81
|
+
Order is not currently supported, although there will be some order functionality in the next version.
|
79
82
|
|
80
83
|
### Composite keys and queries against multiple fields
|
81
84
|
|
@@ -89,6 +92,12 @@ composite key *is* specified, CaChing will keep the resulting set.
|
|
89
92
|
While there is support for this in the Redis adapter, there isn't any support in the ActiveRecord ties as I haven't
|
90
93
|
decided how, exactly, I'd like to add this.
|
91
94
|
|
95
|
+
### Thar be dragons
|
96
|
+
|
97
|
+
While I've tried to outline the issues here (and write failing specs for them), realize that this is
|
98
|
+
still very much alpha software. There are probably a number of unknown unknowns that I just haven't
|
99
|
+
uncovered yet. If you find them, please be sure to [let me know](http://github.com/ahlatimer/ca_ching/issues)!
|
100
|
+
|
92
101
|
## Ruby/Rails versions supported
|
93
102
|
|
94
103
|
Ruby 1.9.2 and Rails 3.1+ are officially supported. I try to stick to Ruby 1.8.7 syntax, so it may be supported,
|
data/ca_ching.gemspec
CHANGED
@@ -20,6 +20,6 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
s.add_dependency 'hiredis'
|
22
22
|
s.add_dependency 'redis', '2.2.2'
|
23
|
-
s.add_dependency 'activesupport', '>= 3.
|
24
|
-
s.add_dependency 'activerecord', '>= 3.
|
23
|
+
s.add_dependency 'activesupport', '>= 3.2.0'
|
24
|
+
s.add_dependency 'activerecord', '>= 3.2.0'
|
25
25
|
end
|
data/dump.rdb
ADDED
Binary file
|
data/lib/ca_ching/index.rb
CHANGED
@@ -9,50 +9,49 @@ module CaChing
|
|
9
9
|
module ClassMethods
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@_query = CaChing::Query::Select.new(self)
|
18
|
-
|
19
|
-
return to_a_without_cache if CaChing.cache.nil? || CaChing.disabled? || !cacheable?
|
20
|
-
|
21
|
-
result = CaChing.cache.find(@_query)
|
22
|
-
@from_cache = true
|
23
|
-
|
24
|
-
if result.nil?
|
25
|
-
result = to_a_without_cache
|
26
|
-
CaChing.cache.insert(result, :for => @_query)
|
27
|
-
@from_cache = false
|
28
|
-
end
|
29
|
-
|
30
|
-
result.from_cache = self.from_cache?
|
31
|
-
result.each { |item| item.from_cache = self.from_cache? }
|
32
|
-
|
33
|
-
return result
|
34
|
-
end
|
12
|
+
# All queries, be they find(id), dynamic finders (find_by_foo, find_all_by_foo, etc.),
|
13
|
+
# where(:foo => :bar), order('foo DESC'), etc. go through to_a before being returned.
|
14
|
+
# Hook into that point to check the cache.
|
15
|
+
def to_a_with_cache
|
16
|
+
@_query = CaChing::Query::Select.new(self)
|
35
17
|
|
36
|
-
|
37
|
-
@from_cache ||= false
|
38
|
-
end
|
18
|
+
return to_a_without_cache if CaChing.cache.nil? || CaChing.disabled? || !cacheable?
|
39
19
|
|
40
|
-
|
41
|
-
|
42
|
-
:group_values,
|
43
|
-
:having_values,
|
44
|
-
:includes_values,
|
45
|
-
:joined_includes_values,
|
46
|
-
:joins_values,
|
47
|
-
:lock_value,
|
48
|
-
:select_values]
|
49
|
-
!where_values.empty? && find_on_indexed_fields? && unsupported_methods.inject(true) { |flag, method| self.send(method).send(method.to_s =~ /values/ ? :empty? : :nil?) && flag }
|
50
|
-
end
|
20
|
+
result = CaChing.cache.find(@_query)
|
21
|
+
@from_cache = true
|
51
22
|
|
52
|
-
|
53
|
-
|
54
|
-
|
23
|
+
if result.nil?
|
24
|
+
result = to_a_without_cache
|
25
|
+
CaChing.cache.insert(result, :for => @_query)
|
26
|
+
@from_cache = false
|
55
27
|
end
|
28
|
+
|
29
|
+
result.from_cache = self.from_cache?
|
30
|
+
result.each { |item| item.from_cache = self.from_cache? }
|
31
|
+
|
32
|
+
return result
|
33
|
+
end
|
34
|
+
|
35
|
+
def from_cache?
|
36
|
+
@from_cache ||= false
|
37
|
+
end
|
38
|
+
|
39
|
+
def cacheable?
|
40
|
+
unsupported_methods = [:from_value,
|
41
|
+
:group_values,
|
42
|
+
:having_values,
|
43
|
+
:includes_values,
|
44
|
+
:joined_includes_values,
|
45
|
+
:joins_values,
|
46
|
+
:lock_value,
|
47
|
+
:select_values,
|
48
|
+
:order_values]
|
49
|
+
!where_values.empty? && find_on_indexed_fields? && unsupported_methods.inject(true) { |flag, method| self.send(method).send(method.to_s =~ /values/ ? :empty? : :nil?) && flag }
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def find_on_indexed_fields?
|
54
|
+
(@_query.where.keys - indexed_fields.keys).empty?
|
56
55
|
end
|
57
56
|
|
58
57
|
included do |base|
|
@@ -61,4 +60,4 @@ module CaChing
|
|
61
60
|
end
|
62
61
|
end
|
63
62
|
end
|
64
|
-
end
|
63
|
+
end
|
data/lib/ca_ching/version.rb
CHANGED
@@ -5,19 +5,33 @@ module CaChing
|
|
5
5
|
module ClassMethods
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
def save_with_cache(*)
|
9
|
+
return save_without_cache if CaChing.cache.nil? || CaChing.disabled?
|
10
|
+
|
11
|
+
CaChing.cache.update(self)
|
12
|
+
save_without_cache
|
13
|
+
end
|
14
|
+
|
15
|
+
def save_with_cache!
|
16
|
+
return save_without_cache! if CaChing.cache.nil? || CaChing.disabled?
|
17
|
+
|
18
|
+
CaChing.cache.update(self)
|
19
|
+
save_without_cache!
|
15
20
|
end
|
16
21
|
|
22
|
+
def destroy_with_cache(*)
|
23
|
+
return destroy_without_cache if CaChing.cache.nil? || CaChing.disabled?
|
24
|
+
|
25
|
+
CaChing.cache.destroy(self)
|
26
|
+
destroy_without_cache
|
27
|
+
end
|
28
|
+
|
17
29
|
included do |base|
|
18
30
|
base.class_eval do
|
19
31
|
alias_method_chain :save, :cache
|
32
|
+
alias_method_chain :save!, :cache
|
33
|
+
alias_method_chain :destroy, :cache
|
20
34
|
end
|
21
35
|
end
|
22
36
|
end
|
23
|
-
end
|
37
|
+
end
|
@@ -99,7 +99,7 @@ module CaChing
|
|
99
99
|
it 'handles multiple clauses' do
|
100
100
|
ar = Person.where(:name => 'Andrew', :age => 22)
|
101
101
|
query = Abstract.new(ar)
|
102
|
-
query.where.should == { :name => ['=', 'Andrew'], :age => ['=', 22] }
|
102
|
+
query.where.should == { :name => ['=', 'Andrew'], :age => ['=', '22'] }
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
@@ -192,4 +192,4 @@ module CaChing
|
|
192
192
|
end
|
193
193
|
end
|
194
194
|
end
|
195
|
-
end
|
195
|
+
end
|
@@ -11,15 +11,41 @@ module CaChing
|
|
11
11
|
@cache.clear!
|
12
12
|
end
|
13
13
|
|
14
|
-
it 'updates the cache for a cached object' do
|
14
|
+
it 'updates the cache for a cached object with AR#save' do
|
15
15
|
ar = Person.where(:id => 1)
|
16
16
|
query = CaChing::Query::Abstract.new(ar)
|
17
17
|
@cache.insert(ar.to_a_without_cache, :for => query)
|
18
18
|
|
19
|
-
|
19
|
+
name = @person.name.reverse
|
20
|
+
|
21
|
+
@person.name = name
|
20
22
|
@person.save
|
21
23
|
|
22
|
-
@cache.find(CaChing::Query::Abstract.new(ar)).first.name.should ==
|
24
|
+
@cache.find(CaChing::Query::Abstract.new(ar)).first.name.should == name
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'updates the cache for a cached object with AR#save!' do
|
28
|
+
ar = Person.where(:id => 1)
|
29
|
+
query = CaChing::Query::Abstract.new(ar)
|
30
|
+
@cache.insert(ar.to_a_without_cache, :for => query)
|
31
|
+
|
32
|
+
name = @person.name.reverse
|
33
|
+
|
34
|
+
@person.name = name
|
35
|
+
@person.save!
|
36
|
+
|
37
|
+
@cache.find(CaChing::Query::Abstract.new(ar)).first.name.should == name
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'updates the cache for a cached object with AR#update_attributes' do
|
41
|
+
ar = Person.where(:id => 1)
|
42
|
+
query = CaChing::Query::Abstract.new(ar)
|
43
|
+
@cache.insert(ar.to_a_without_cache, :for => query)
|
44
|
+
|
45
|
+
name = @person.name.reverse
|
46
|
+
@person.update_attributes(:name => name)
|
47
|
+
|
48
|
+
@cache.find(CaChing::Query::Abstract.new(ar)).first.name.should == name
|
23
49
|
end
|
24
50
|
end
|
25
51
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ca_ching
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-03-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: hiredis
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,40 +21,60 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: redis
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
|
-
- - =
|
35
|
+
- - '='
|
31
36
|
- !ruby/object:Gem::Version
|
32
37
|
version: 2.2.2
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.2.2
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: activesupport
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
42
52
|
- !ruby/object:Gem::Version
|
43
|
-
version: 3.
|
53
|
+
version: 3.2.0
|
44
54
|
type: :runtime
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.2.0
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: activerecord
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
53
68
|
- !ruby/object:Gem::Version
|
54
|
-
version: 3.
|
69
|
+
version: 3.2.0
|
55
70
|
type: :runtime
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 3.2.0
|
58
78
|
description: Write-through ActiveRecord model caching that's right on the money
|
59
79
|
email:
|
60
80
|
- andrew@elpasoera.com
|
@@ -63,6 +83,7 @@ extensions: []
|
|
63
83
|
extra_rdoc_files: []
|
64
84
|
files:
|
65
85
|
- .gitignore
|
86
|
+
- .rvmrc
|
66
87
|
- Gemfile
|
67
88
|
- Guardfile
|
68
89
|
- LICENSE.txt
|
@@ -70,6 +91,7 @@ files:
|
|
70
91
|
- Rakefile
|
71
92
|
- SPEC.md
|
72
93
|
- ca_ching.gemspec
|
94
|
+
- dump.rdb
|
73
95
|
- lib/ca_ching.rb
|
74
96
|
- lib/ca_ching/adapters/active_record.rb
|
75
97
|
- lib/ca_ching/adapters/redis.rb
|
@@ -114,7 +136,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
136
|
version: '0'
|
115
137
|
segments:
|
116
138
|
- 0
|
117
|
-
hash:
|
139
|
+
hash: 3771213621582903175
|
118
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
141
|
none: false
|
120
142
|
requirements:
|
@@ -123,10 +145,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
145
|
version: '0'
|
124
146
|
segments:
|
125
147
|
- 0
|
126
|
-
hash:
|
148
|
+
hash: 3771213621582903175
|
127
149
|
requirements: []
|
128
150
|
rubyforge_project: ca_ching
|
129
|
-
rubygems_version: 1.8.
|
151
|
+
rubygems_version: 1.8.24
|
130
152
|
signing_key:
|
131
153
|
specification_version: 3
|
132
154
|
summary: Write-through ActiveRecord model caching that's right on the money
|