sequel-cacheable 0.0.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,53 @@
1
+ # rcov generated
2
+ coverage
3
+ coverage.data
4
+
5
+ # rdoc generated
6
+ rdoc
7
+
8
+ # yard generated
9
+ doc
10
+ .yardoc
11
+
12
+ # bundler
13
+ .bundle
14
+
15
+ # jeweler generated
16
+ pkg
17
+
18
+ Gemfile.lock
19
+ dump.rdb
20
+ tmp
21
+
22
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
23
+ #
24
+ # * Create a file at ~/.gitignore
25
+ # * Include files you want ignored
26
+ # * Run: git config --global core.excludesfile ~/.gitignore
27
+ #
28
+ # After doing this, these files will be ignored in all your git projects,
29
+ # saving you from having to 'pollute' every project you touch with them
30
+ #
31
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
32
+ #
33
+ # For MacOS:
34
+ #
35
+ #.DS_Store
36
+
37
+ # For TextMate
38
+ #*.tmproj
39
+ #tmtags
40
+
41
+ # For emacs:
42
+ #*~
43
+ #\#*
44
+ #.\#*
45
+
46
+ # For vim:
47
+ #*.swp
48
+
49
+ # For redcar:
50
+ #.redcar
51
+
52
+ # For rubinius:
53
+ #*.rbc
data/.pryrc ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.require(:default, :development)
4
+
5
+ $: << "#{Dir.pwd}/lib"
6
+ require 'sequel-cacheable'
7
+
8
+ DB = Sequel.sqlite
9
+ DB.create_table(:mock) do
10
+ primary_key :id, :auto_increment => true
11
+ String :name
12
+ end
13
+
14
+ require 'memcache/null_server'
15
+ class Mock < Sequel::Model(:mock)
16
+ plugin :cacheable, Redis.new(server: 'localhost:6379'), :query_cache => true
17
+ end
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p327
data/.travis.yml CHANGED
@@ -1,5 +1,8 @@
1
+ services:
2
+ - memcached
3
+ - redis-server
1
4
  bundler_args: --without development
2
- script: bundle exec rake spec
5
+ script: bundle exec rspec
3
6
  language: ruby
4
7
  rvm:
5
8
  - 1.8.7
data/Gemfile CHANGED
@@ -1,30 +1,28 @@
1
- source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
1
+ source :rubygems
5
2
 
6
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
3
+ gem 'bundler'
4
+ gem 'rake'
8
5
 
9
- gem 'sequel', '~> 3.34'
10
- gem 'msgpack', '~> 0.4.6'
11
- gem 'hashr', '~> 0.0.19'
6
+ gemspec
12
7
 
13
8
  group :development, :test do
14
- gem "bundler", ">= 1.0.0"
9
+ gem 'rspec', "~> 2.12.0"
10
+ gem 'yard', "~> 0.8.3"
11
+ gem 'rdoc', "~> 3.12"
12
+ gem 'simplecov', "~> 0.7.1", :require => false
15
13
 
16
- gem "rspec", "~> 2"
17
- gem "yard", "~> 0.7"
18
- gem "rdoc", "~> 3.12"
19
- gem "jeweler", "~> 1.8.3"
20
- gem 'simplecov', "~> 0.6.1", :require => false
14
+ gem 'guard', '~> 1.6.1'
15
+ gem 'guard-rspec', '~> 2.3.3'
16
+ gem 'terminal-notifier'
17
+ gem 'listen', '~> 0.7.0'
21
18
 
22
- gem "guard", '~> 1.0.0'
23
- gem "guard-rspec", '~> 0.7'
24
- gem "growl"
25
-
26
- gem "sqlite3"
27
- gem "memcache"
28
- gem "redis"
29
- gem "queencheck"
19
+ gem 'sqlite3'
20
+ gem 'dalli'
21
+ gem 'memcache'
22
+ gem 'hiredis'
23
+ gem 'redis', :require => ['redis', 'redis/connection/hiredis']
24
+ gem 'pry'
25
+ gem 'pry-doc'
26
+ gem 'forgery'
27
+ gem 'tapp'
30
28
  end
data/Procfile ADDED
@@ -0,0 +1,2 @@
1
+ memcached: memcached
2
+ redis: redis-server
data/README.rdoc CHANGED
@@ -23,15 +23,16 @@ Caching!
23
23
  tested cache_client:
24
24
 
25
25
  * Redis[https://rubygems.org/gems/redis]
26
+ * Hiredis[https://rubygems.org/gems/hiredis]
26
27
  * Memcached[https://rubygems.org/gems/memcache]
28
+ * Dalli[https://rubygems.org/gems/dalli]
27
29
 
28
30
  options:
29
31
 
30
32
  {
31
33
  :ttl => 3600, # time to live. default 3600
32
- :ignore_exception => false, # through exception. default false
33
34
  :pack_lib => MessagePack, # cache packing library. This Object should be have pack / unpack method.
34
- :query_cache => false # enable query cache. default true if cache client implemented keys method
35
+ :query_cache => false # enable query cache. default false
35
36
  }
36
37
 
37
38
  == Cache Timing
@@ -48,7 +49,7 @@ options:
48
49
  * clear all query caches of model
49
50
 
50
51
  == Contributing to sequel-cacheable
51
-
52
+
52
53
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
53
54
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
54
55
  * Fork the project.
data/Rakefile CHANGED
@@ -1,37 +1,2 @@
1
1
  # encoding: utf-8
2
-
3
- require 'rubygems'
4
- require 'bundler'
5
- begin
6
- Bundler.setup(:default, :development)
7
- rescue Bundler::BundlerError => e
8
- $stderr.puts e.message
9
- $stderr.puts "Run `bundle install` to install missing gems"
10
- exit e.status_code
11
- end
12
- require 'rake'
13
-
14
- require 'jeweler'
15
- Jeweler::Tasks.new do |gem|
16
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
- gem.name = "sequel-cacheable"
18
- gem.homepage = "http://github.com/rosylilly/sequel-cacheable"
19
- gem.license = "MIT"
20
- gem.summary = %Q{This plug-in caching mechanism to implement the Model of the Sequel}
21
- gem.description = %Q{This plug-in caching mechanism to implement the Model of the Sequel}
22
- gem.email = "rosylilly@aduca.org"
23
- gem.authors = ["Sho Kusano <rosylilly>"]
24
- # dependencies defined in Gemfile
25
- end
26
- Jeweler::RubygemsDotOrgTasks.new
27
-
28
- require 'rspec/core'
29
- require 'rspec/core/rake_task'
30
- RSpec::Core::RakeTask.new(:spec) do |spec|
31
- spec.pattern = FileList['spec/**/*_spec.rb']
32
- end
33
-
34
- task :default => :spec
35
-
36
- require 'yard'
37
- YARD::Rake::YardocTask.new
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,74 @@
1
+ # coding: utf-8
2
+
3
+ module Sequel::Plugins
4
+ module Cacheable
5
+ module ClassMethods
6
+ attr_reader :cache_driver, :cache_options, :caches
7
+
8
+ def inherited(subclass)
9
+ super
10
+ end
11
+
12
+ def primary_key_lookup(id)
13
+ cache_fetch(id.to_s) do
14
+ super
15
+ end
16
+ end
17
+
18
+ def restore_by_cache(hash)
19
+ return nil if hash.nil?
20
+
21
+ return hash.map{|hs| restore_by_cache(hs) } if hash.is_a?(Array)
22
+
23
+ return hash if hash.kind_of?(Sequel::Model)
24
+
25
+ hash.keys.each do | key |
26
+ value = hash.delete(key)
27
+ key = key.to_sym rescue key
28
+ case db_schema[key][:type]
29
+ when :date
30
+ value = Date.new(*value)
31
+ when :time
32
+ value = Sequel::SQLTime.at(value[0], value[1])
33
+ when :datetime
34
+ value = Time.at(value[0], value[1])
35
+ when :decimal
36
+ value = BigDecimal.new(value)
37
+ when :integer
38
+ value = value.to_i
39
+ end
40
+ hash[key] = value
41
+ end
42
+
43
+ return new(hash, true)
44
+ end
45
+
46
+ def cache_key(key)
47
+ "#{self.name}:#{key}"
48
+ end
49
+
50
+ def cache_set(key, value, ttl = @cache_options[:ttl])
51
+ @caches[key.match(/\AQuery:/) ? :query : :instance] << key
52
+ cache_driver.set(cache_key(key), value, ttl)
53
+ end
54
+
55
+ def cache_get(key)
56
+ restore_by_cache(cache_driver.get(cache_key(key)))
57
+ end
58
+
59
+ def cache_fetch(key, ttl = @cache_options[:ttl], &block)
60
+ @caches[key.match(/\AQuery:/) ? :query : :instance] << key
61
+ cache_driver.fetch(cache_key(key), ttl, &block)
62
+ end
63
+
64
+ def cache_del(key)
65
+ @caches[key.match(/\AQuery:/) ? :query : :instance].delete(key)
66
+ cache_driver.del(cache_key(key))
67
+ end
68
+
69
+ def cache_clear(type)
70
+ @caches[type].dup.each {|key| cache_del(key) }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,53 @@
1
+ # coding: utf-8
2
+
3
+ module Sequel::Plugins
4
+ module Cacheable
5
+ module DatasetMethods
6
+ def all(*args, &block)
7
+ if(
8
+ model &&
9
+ model.respond_to?(:cache_fetch) &&
10
+ model.cache_options[:query_cache] &&
11
+ @row_proc.kind_of?(Class) &&
12
+ @row_proc.included_modules.include?(Sequel::Model::InstanceMethods)
13
+ )
14
+ @row_proc.cache_fetch(cache_key) do
15
+ super(*args, &block)
16
+ end
17
+ else
18
+ super(*args, &block)
19
+ end
20
+ end
21
+
22
+ def first(*args)
23
+ if(
24
+ model &&
25
+ model.respond_to?(:cache_fetch) &&
26
+ model.cache_options[:query_cache] &&
27
+ @row_proc.kind_of?(Class) &&
28
+ @row_proc.included_modules.include?(Sequel::Model::InstanceMethods)
29
+ )
30
+ @row_proc.cache_fetch("#{cache_key}:first") do
31
+ super(*args)
32
+ end
33
+ else
34
+ super(*args)
35
+ end
36
+ end
37
+
38
+ def with_pk(pk)
39
+ if pk.is_a(Integer)
40
+ model.cache_fetch(pk.to_s) do
41
+ super(pk)
42
+ end
43
+ else
44
+ super(pk)
45
+ end
46
+ end
47
+
48
+ def cache_key
49
+ "Query:#{select_sql.gsub(/ +/, '_')}"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,19 @@
1
+ module Sequel::Plugins
2
+ module Cacheable
3
+ class DalliDriver < Driver
4
+ def del(key)
5
+ @store.delete(key)
6
+
7
+ return nil
8
+ end
9
+
10
+ def expire(key, time)
11
+ if time > 0
12
+ @store.touch(key, time)
13
+ else
14
+ @store.delete(key)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Sequel::Plugins
2
+ module Cacheable
3
+ class MemcacheDriver < Driver
4
+ def del(key)
5
+ @store.delete(key)
6
+
7
+ return nil
8
+ end
9
+
10
+ def expire(key, time)
11
+ @store.set(key, @store.get(key), time)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module Sequel::Plugins
2
+ module Cacheable
3
+ class RedisDriver < Driver
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,56 @@
1
+ module Sequel::Plugins
2
+ module Cacheable
3
+ DRIVERS = %w(memcache dalli redis).freeze
4
+
5
+ class Driver
6
+ def self.factory(*args)
7
+ case args[0].class.name
8
+ when 'Memcache'
9
+ MemcacheDriver.new(*args)
10
+ when 'Dalli::Client'
11
+ DalliDriver.new(*args)
12
+ when 'Redis'
13
+ RedisDriver.new(*args)
14
+ else
15
+ Driver.new(*args)
16
+ end
17
+ end
18
+
19
+ def initialize(store, pack_lib = MessagePackPacker)
20
+ @store = store
21
+ @packer = pack_lib
22
+ end
23
+
24
+ def get(key)
25
+ val = @store.get(key)
26
+
27
+ return val.nil? || val.empty? ? nil : @packer.unpack(val)
28
+ end
29
+
30
+ def set(key, val, expire = nil)
31
+ @store.set(key, @packer.pack(val))
32
+ expire(key, expire) unless expire.nil?
33
+
34
+ return val
35
+ end
36
+
37
+ def del(key)
38
+ @store.del(key)
39
+
40
+ return nil
41
+ end
42
+
43
+ def expire(key, time)
44
+ @store.expire(key, time)
45
+ end
46
+
47
+ def fetch(key, *args, &block)
48
+ get(key) || set(key, block.call(*args))
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ Sequel::Plugins::Cacheable::DRIVERS.each do |driver|
55
+ require "sequel-cacheable/driver/#{driver}"
56
+ end
@@ -0,0 +1,66 @@
1
+ # coding: utf-8
2
+
3
+ module Sequel::Plugins
4
+ module Cacheable
5
+ module InstanceMethods
6
+ def after_initialize
7
+ super
8
+ cache! unless id.nil?
9
+ end
10
+
11
+ def after_save
12
+ super
13
+ recache!
14
+ end
15
+
16
+ def delete(*args)
17
+ uncache!
18
+ super
19
+ end
20
+
21
+ def destory(*args)
22
+ uncache!
23
+ super(*args)
24
+ end
25
+
26
+ def cache!
27
+ model.cache_set(cache_key, self)
28
+ end
29
+
30
+ def uncache!
31
+ model.cache_del(cache_key)
32
+ model.cache_clear(:query)
33
+ end
34
+
35
+ def recache!
36
+ uncache!
37
+ cache!
38
+ end
39
+
40
+ def cache_key
41
+ "#{self.id.to_s}"
42
+ end
43
+
44
+ def to_msgpack(*args)
45
+ msgpack_hash.to_msgpack
46
+ end
47
+
48
+ def msgpack_hash
49
+ hash = {}
50
+ @values.each_pair do | key, value |
51
+ case value
52
+ when Date
53
+ value = [value.year, value.mon, value.mday, value.start]
54
+ when Sequel::SQLTime, Time
55
+ value = [value.to_i, value.usec]
56
+ when BigDecimal, Bignum
57
+ value = value.to_s
58
+ end
59
+ hash[key] = value
60
+ end
61
+ hash
62
+ end
63
+ private :msgpack_hash
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,34 @@
1
+ require 'msgpack'
2
+
3
+ module Sequel::Plugins
4
+ module Cacheable
5
+ class Packer
6
+ def self.factory(lib)
7
+ case lib
8
+ when MessagePack
9
+ MessagePackPacker.new
10
+ else
11
+ Packer.new
12
+ end
13
+ end
14
+
15
+ def pack(obj)
16
+ Marshal.dump(obj)
17
+ end
18
+
19
+ def unpack(string)
20
+ Marshal.load(string)
21
+ end
22
+ end
23
+
24
+ class MessagePackPacker < Packer
25
+ def pack(obj)
26
+ obj.to_msgpack
27
+ end
28
+
29
+ def unpack(string)
30
+ MessagePack.unpack(string)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ module Sequel
2
+ module Plugins
3
+ module Cacheable
4
+ VERSION = '1.0.0'
5
+ end
6
+ end
7
+ end