redis_object 0.5.0
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/.coveralls.yml +1 -0
- data/.gitignore +6 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/README.markdown +179 -0
- data/Rakefile +10 -0
- data/lib/redis_object.rb +47 -0
- data/lib/redis_object/base.rb +408 -0
- data/lib/redis_object/collection.rb +388 -0
- data/lib/redis_object/defaults.rb +42 -0
- data/lib/redis_object/experimental/history.rb +49 -0
- data/lib/redis_object/ext/benchmark.rb +34 -0
- data/lib/redis_object/ext/cleaner.rb +14 -0
- data/lib/redis_object/ext/filters.rb +68 -0
- data/lib/redis_object/ext/script_cache.rb +92 -0
- data/lib/redis_object/ext/shardable.rb +18 -0
- data/lib/redis_object/ext/triggers.rb +101 -0
- data/lib/redis_object/ext/view_caching.rb +258 -0
- data/lib/redis_object/ext/views.rb +102 -0
- data/lib/redis_object/external_index.rb +25 -0
- data/lib/redis_object/indices.rb +97 -0
- data/lib/redis_object/inheritance_tracking.rb +23 -0
- data/lib/redis_object/keys.rb +37 -0
- data/lib/redis_object/storage.rb +93 -0
- data/lib/redis_object/storage/adapter.rb +46 -0
- data/lib/redis_object/storage/aws.rb +71 -0
- data/lib/redis_object/storage/mysql.rb +47 -0
- data/lib/redis_object/storage/redis.rb +119 -0
- data/lib/redis_object/timestamps.rb +74 -0
- data/lib/redis_object/tpl.rb +17 -0
- data/lib/redis_object/types.rb +276 -0
- data/lib/redis_object/validation.rb +89 -0
- data/lib/redis_object/version.rb +5 -0
- data/redis_object.gemspec +26 -0
- data/spec/adapter_spec.rb +43 -0
- data/spec/base_spec.rb +90 -0
- data/spec/benchmark_spec.rb +46 -0
- data/spec/collections_spec.rb +144 -0
- data/spec/defaults_spec.rb +56 -0
- data/spec/filters_spec.rb +29 -0
- data/spec/indices_spec.rb +45 -0
- data/spec/rename_class_spec.rb +96 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/timestamp_spec.rb +28 -0
- data/spec/trigger_spec.rb +51 -0
- data/spec/types_spec.rb +103 -0
- data/spec/view_caching_spec.rb +130 -0
- data/spec/views_spec.rb +72 -0
- metadata +172 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module DefaultSpec
|
4
|
+
|
5
|
+
TestValues = {
|
6
|
+
date: Date.today,
|
7
|
+
number: 27,
|
8
|
+
int: 356192,
|
9
|
+
float: 72.362517,
|
10
|
+
bool: true,
|
11
|
+
# boolean: false,
|
12
|
+
# array: [:test1,:test2],
|
13
|
+
json: {test1: true, test2: "false"}
|
14
|
+
}
|
15
|
+
|
16
|
+
TestData = TestValues.inject({}){|acc,(k,v)| acc["a_#{k}".to_sym] = v; acc }
|
17
|
+
|
18
|
+
# Delicious pizza!
|
19
|
+
class DefaultedObject < RedisObject
|
20
|
+
|
21
|
+
TestValues.keys.each do |type|
|
22
|
+
send(type.to_sym,"a_#{type}".to_sym)
|
23
|
+
end
|
24
|
+
default_for :testy, "test"
|
25
|
+
default_for :a_number, 42
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe Seabright::DefaultValues do
|
30
|
+
before do
|
31
|
+
RedisObject.store.flushdb
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns default value" do
|
35
|
+
|
36
|
+
obj = DefaultedObject.create(TestData)
|
37
|
+
|
38
|
+
obj.testy.should eq("test")
|
39
|
+
obj.get(:a_number).should eq(27)
|
40
|
+
obj.unset(:a_number)
|
41
|
+
obj.get(:a_number).should eq(42)
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns default value after unset" do
|
46
|
+
|
47
|
+
obj = DefaultedObject.create(TestData)
|
48
|
+
|
49
|
+
obj.get(:a_number).should eq(27)
|
50
|
+
obj.unset(:a_number)
|
51
|
+
obj.get(:a_number).should eq(42)
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module FilterSpec
|
4
|
+
|
5
|
+
class FilteredObject < RedisObject
|
6
|
+
|
7
|
+
def double(k,v)
|
8
|
+
(k == :testy) && v ? [:testy,v*2] : [k,v]
|
9
|
+
end
|
10
|
+
set_filter :double
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Seabright::Filters do
|
15
|
+
before do
|
16
|
+
RedisObject.store.flushdb
|
17
|
+
end
|
18
|
+
|
19
|
+
it "modifies set and gets correctly" do
|
20
|
+
|
21
|
+
obj = FilteredObject.create("test")
|
22
|
+
|
23
|
+
obj.set(:testy,"test")
|
24
|
+
obj.get(:testy).should eq("testtest")
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module IndexSpec
|
4
|
+
|
5
|
+
TestValues = {
|
6
|
+
date: Date.today,
|
7
|
+
number: 27,
|
8
|
+
int: 356192,
|
9
|
+
float: 72.362517,
|
10
|
+
bool: true,
|
11
|
+
# boolean: false,
|
12
|
+
# array: [:test1,:test2],
|
13
|
+
json: {test1: true, test2: "false"}
|
14
|
+
}
|
15
|
+
|
16
|
+
TestData = TestValues.inject({}){|acc,(k,v)| acc["a_#{k}".to_sym] = v; acc }
|
17
|
+
|
18
|
+
# Delicious pizza!
|
19
|
+
class IndexedObject < RedisObject
|
20
|
+
|
21
|
+
TestValues.keys.each do |type|
|
22
|
+
send(type.to_sym,"a_#{type}".to_sym)
|
23
|
+
end
|
24
|
+
|
25
|
+
sort_by :a_number
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe Seabright::Indices do
|
30
|
+
before do
|
31
|
+
RedisObject.store.flushdb
|
32
|
+
end
|
33
|
+
|
34
|
+
it "indexes on integer field" do
|
35
|
+
|
36
|
+
5.times do
|
37
|
+
obj = IndexedObject.create(a_number: Random.rand(100))
|
38
|
+
end
|
39
|
+
|
40
|
+
IndexedObject.indexed(:a_number,3,true).count.should eq(3)
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module RenameClassSpec
|
4
|
+
# Delicious pizza!
|
5
|
+
class Pizza < RedisObject; end
|
6
|
+
# We love toppings but our current name Topping is too ambiguous!
|
7
|
+
class Topping < RedisObject; end
|
8
|
+
# Let's change the class name to PizzaTopping!
|
9
|
+
class PizzaTopping < RedisObject; end
|
10
|
+
|
11
|
+
describe Seabright::Storage::Redis, "#rename_class" do
|
12
|
+
before do
|
13
|
+
RedisObject.store.flushdb
|
14
|
+
|
15
|
+
mozzarella = Topping.create(:mozzarella)
|
16
|
+
basil = Topping.create(:basil)
|
17
|
+
tomato = Topping.create(:tomato)
|
18
|
+
garlic = Topping.create(:garlic)
|
19
|
+
oregano = Topping.create(:oregano)
|
20
|
+
olive_oil = Topping.create(:olive_oil)
|
21
|
+
|
22
|
+
marinara = Pizza.create(:marinara)
|
23
|
+
[ tomato, garlic, oregano, olive_oil ].each{|topping| marinara << topping }
|
24
|
+
|
25
|
+
margherita = Pizza.create(:margherita)
|
26
|
+
[ tomato, mozzarella, basil, olive_oil ].each{|topping| margherita << topping }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "setup works" do
|
30
|
+
margherita = Pizza.find(:margherita)
|
31
|
+
marinara = Pizza.find(:marinara)
|
32
|
+
mozzarella = Topping.find(:mozzarella)
|
33
|
+
basil = Topping.find(:basil)
|
34
|
+
tomato = Topping.find(:tomato)
|
35
|
+
garlic = Topping.find(:garlic)
|
36
|
+
oregano = Topping.find(:oregano)
|
37
|
+
olive_oil = Topping.find(:olive_oil)
|
38
|
+
|
39
|
+
[ mozzarella, basil, tomato, garlic, oregano, olive_oil ].each do |topping|
|
40
|
+
topping.get(:class).should == Topping.name
|
41
|
+
topping.get(:key).should == "RenameClassSpec::Topping:#{topping.id}"
|
42
|
+
topping.get(:topping_id).should == topping.id
|
43
|
+
end
|
44
|
+
|
45
|
+
Topping.indexed(:created_at).first.should_not be_nil
|
46
|
+
Topping.indexed(:created_at).count.should == 5
|
47
|
+
|
48
|
+
[margherita, marinara].each do |pizza|
|
49
|
+
pizza.pizza_toppings.should be_nil
|
50
|
+
pizza.toppings.count.should == 4
|
51
|
+
pizza.toppings.should include(tomato.hkey)
|
52
|
+
pizza.toppings.should include(olive_oil.hkey)
|
53
|
+
end
|
54
|
+
|
55
|
+
margherita.toppings.should include(basil.hkey)
|
56
|
+
margherita.toppings.should include(mozzarella.hkey)
|
57
|
+
marinara.toppings.should include(oregano.hkey)
|
58
|
+
marinara.toppings.should include(garlic.hkey)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "renames a class" do
|
62
|
+
RedisObject.store.rename_class(:"RenameClassSpec::Topping", :"RenameClassSpec::PizzaTopping")
|
63
|
+
|
64
|
+
margherita = Pizza.find(:margherita)
|
65
|
+
marinara = Pizza.find(:marinara)
|
66
|
+
mozzarella = PizzaTopping.find(:mozzarella)
|
67
|
+
basil = PizzaTopping.find(:basil)
|
68
|
+
tomato = PizzaTopping.find(:tomato)
|
69
|
+
garlic = PizzaTopping.find(:garlic)
|
70
|
+
oregano = PizzaTopping.find(:oregano)
|
71
|
+
olive_oil = PizzaTopping.find(:olive_oil)
|
72
|
+
|
73
|
+
[ mozzarella, basil, tomato, garlic, oregano, olive_oil ].each do |topping|
|
74
|
+
topping.get(:class).should == PizzaTopping.name
|
75
|
+
topping.get(:key).should == "RenameClassSpec::PizzaTopping:#{topping.id}"
|
76
|
+
topping.get(:"renameclassspec::pizzatopping_id").should == topping.id
|
77
|
+
# topping.get(:topping_id).should == nil
|
78
|
+
end
|
79
|
+
|
80
|
+
[margherita, marinara].each do |pizza|
|
81
|
+
pizza.toppings.should be_nil
|
82
|
+
pizza.pizza_toppings.count.should == 4
|
83
|
+
pizza.pizza_toppings.should include(tomato.hkey)
|
84
|
+
pizza.pizza_toppings.should include(olive_oil.hkey)
|
85
|
+
end
|
86
|
+
|
87
|
+
margherita.pizza_toppings.should include(basil.hkey)
|
88
|
+
margherita.pizza_toppings.should include(mozzarella.hkey)
|
89
|
+
marinara.pizza_toppings.should include(oregano.hkey)
|
90
|
+
marinara.pizza_toppings.should include(garlic.hkey)
|
91
|
+
|
92
|
+
PizzaTopping.indexed(:created_at).first.should_not be_nil
|
93
|
+
PizzaTopping.indexed(:created_at).count.should == 5
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'rspec'
|
7
|
+
|
8
|
+
require 'simplecov'
|
9
|
+
require 'coveralls'
|
10
|
+
|
11
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
12
|
+
SimpleCov::Formatter::HTMLFormatter,
|
13
|
+
Coveralls::SimpleCov::Formatter
|
14
|
+
]
|
15
|
+
SimpleCov.start do
|
16
|
+
add_filter "_spec.rb"
|
17
|
+
add_filter "/experimental/"
|
18
|
+
add_group "Extensions", "lib/redis_object/ext/"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'redis_object'
|
22
|
+
|
23
|
+
class DebugMode
|
24
|
+
def initialize(o=nil); @opts = o; end
|
25
|
+
def verbose?; debug? && !!@opts[:verbose]; end
|
26
|
+
def debug?; !!@opts; end
|
27
|
+
end
|
28
|
+
Debug = if ENV['DEBUG']
|
29
|
+
require 'debugger'
|
30
|
+
DEBUG = true
|
31
|
+
DebugMode.new(verbose:true)
|
32
|
+
else
|
33
|
+
DEBUG = false
|
34
|
+
DebugMode.new
|
35
|
+
end
|
36
|
+
|
37
|
+
raise 'must specify TEST_DB' unless ENV['TEST_DB']
|
38
|
+
RedisObject.configure_store({adapter:'Redis', db:ENV['TEST_DB']},:global,:alias)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module TriggerSpec
|
4
|
+
|
5
|
+
class TimestampedObject < RedisObject;end
|
6
|
+
|
7
|
+
class UnTimestampedObject < RedisObject
|
8
|
+
# time_matters_not!
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Seabright::Triggers do
|
12
|
+
before do
|
13
|
+
RedisObject.store.flushdb
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should get recently created object" do
|
17
|
+
|
18
|
+
(1..5).each do |n|
|
19
|
+
TimestampedObject.create(n.to_s)
|
20
|
+
sleep Random.rand(1.0)
|
21
|
+
end
|
22
|
+
|
23
|
+
TimestampedObject.recently_created.first.id.should eq("5")
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module TriggerSpec
|
4
|
+
|
5
|
+
class TriggeredObject < RedisObject
|
6
|
+
|
7
|
+
int :raw_phone
|
8
|
+
bool :mailed_flag
|
9
|
+
bool :mail_was_sent_for_realz
|
10
|
+
date :srsly_updated
|
11
|
+
|
12
|
+
def track_phone_raw(k,v)
|
13
|
+
set(:raw_phone, v.gsub(/[^0-9]/,'').to_i)
|
14
|
+
end
|
15
|
+
|
16
|
+
trigger_on_set :phone, :track_phone_raw
|
17
|
+
|
18
|
+
def sent_mail(k,v)
|
19
|
+
set(:mail_was_sent_for_realz, true)
|
20
|
+
end
|
21
|
+
|
22
|
+
def updated_redundant(k,v)
|
23
|
+
set(:srsly_updated, Time.now)
|
24
|
+
end
|
25
|
+
|
26
|
+
trigger_on_set :mailed_flag, :sent_mail
|
27
|
+
trigger_on_update :updated_redundant
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Seabright::Triggers do
|
32
|
+
before do
|
33
|
+
RedisObject.store.flushdb
|
34
|
+
end
|
35
|
+
|
36
|
+
it "triggers on a call" do
|
37
|
+
|
38
|
+
obj = TriggeredObject.create("trig")
|
39
|
+
|
40
|
+
obj.phone = "(970) 555-1212"
|
41
|
+
obj.raw_phone.should eq(9705551212)
|
42
|
+
success = obj.setnx(:mailed_flag,true)
|
43
|
+
success.should eq(true)
|
44
|
+
obj.mail_was_sent_for_realz.should eq(true)
|
45
|
+
success = obj.setnx(:mailed_flag,true)
|
46
|
+
success.should eq(false)
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/spec/types_spec.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module TypeSpec
|
4
|
+
|
5
|
+
TestValues = {
|
6
|
+
date: Date.today,
|
7
|
+
number: 27,
|
8
|
+
int: 356192,
|
9
|
+
float: 72.362517,
|
10
|
+
bool: true,
|
11
|
+
boolean: false,
|
12
|
+
array: ["test1","test2"],
|
13
|
+
json: {test1: true, test2: "false"}
|
14
|
+
}
|
15
|
+
|
16
|
+
TestData = TestValues.inject({}){|acc,(k,v)| acc["a_#{k}".to_sym] = v; acc }
|
17
|
+
|
18
|
+
class TypedObject < RedisObject
|
19
|
+
TestValues.keys.each do |type|
|
20
|
+
send(type.to_sym,"a_#{type}".to_sym)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class TypedChild < TypedObject; end
|
25
|
+
|
26
|
+
describe Seabright::Types do
|
27
|
+
before do
|
28
|
+
RedisObject.store.flushdb
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can be created via data packet" do
|
32
|
+
|
33
|
+
obj = TypedObject.create(TestData)
|
34
|
+
|
35
|
+
TestData.each do |k,v|
|
36
|
+
obj.get(k).should eq(v)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
it "inherits types" do
|
42
|
+
|
43
|
+
obj = TypedChild.create(TestData)
|
44
|
+
|
45
|
+
TestData.each do |k,v|
|
46
|
+
obj.get(k).should eq(v)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
it "can be instantiated (new) via data packet" do
|
52
|
+
|
53
|
+
obj = TypedObject.new(TestData)
|
54
|
+
|
55
|
+
TestData.each do |k,v|
|
56
|
+
obj.get(k).should eq(v)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
it "can be created via individual sets" do
|
62
|
+
|
63
|
+
obj = TypedObject.new
|
64
|
+
|
65
|
+
TestData.each do |k,v|
|
66
|
+
obj.set(k,v)
|
67
|
+
obj.get(k).should eq(v)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
it "gets correct values after being found" do
|
73
|
+
|
74
|
+
objc = TypedObject.create(TestData)
|
75
|
+
obj = TypedObject.find(objc.id)
|
76
|
+
|
77
|
+
TestData.each do |k,v|
|
78
|
+
obj.get(k).should eq(v)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
it "nullifies non-date date value" do
|
84
|
+
|
85
|
+
obj = TypedObject.new
|
86
|
+
|
87
|
+
obj.a_date = "sjahfgasjfg"
|
88
|
+
obj.a_date.should eq(nil)
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
it "describes itself" do
|
93
|
+
|
94
|
+
obj = TypedObject.create(TestData)
|
95
|
+
objc = TypedChild.create(TestData)
|
96
|
+
|
97
|
+
desc = TypedObject.describe
|
98
|
+
TypedObject.dump_schema(File.open("/tmp/redisobject_dump_test","w"))
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|