sequel_model 0.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/CHANGELOG +3 -0
- data/COPYING +18 -0
- data/README +251 -0
- data/Rakefile +146 -0
- data/lib/sequel_model.rb +326 -0
- data/lib/sequel_model/base.rb +97 -0
- data/lib/sequel_model/caching.rb +42 -0
- data/lib/sequel_model/hooks.rb +122 -0
- data/lib/sequel_model/plugins.rb +44 -0
- data/lib/sequel_model/pretty_table.rb +73 -0
- data/lib/sequel_model/record.rb +309 -0
- data/lib/sequel_model/relations.rb +107 -0
- data/lib/sequel_model/schema.rb +52 -0
- data/lib/sequel_model/validations.rb +117 -0
- data/spec/base_spec.rb +150 -0
- data/spec/caching_spec.rb +150 -0
- data/spec/hooks_spec.rb +107 -0
- data/spec/model_spec.rb +564 -0
- data/spec/plugins_spec.rb +61 -0
- data/spec/rcov.opts +4 -0
- data/spec/record_spec.rb +362 -0
- data/spec/relations_spec.rb +150 -0
- data/spec/schema_spec.rb +82 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/validations_spec.rb +294 -0
- metadata +111 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Model
|
3
|
+
ID_POSTFIX = '_id'.freeze
|
4
|
+
|
5
|
+
# Creates a 1-1 relationship by defining an association method, e.g.:
|
6
|
+
#
|
7
|
+
# class Session < Sequel::Model(:sessions)
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# class Node < Sequel::Model(:nodes)
|
11
|
+
# one_to_one :producer, :from => Session
|
12
|
+
# # which is equivalent to
|
13
|
+
# def producer
|
14
|
+
# Session[producer_id] if producer_id
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# You can also set the foreign key explicitly by including a :key option:
|
19
|
+
#
|
20
|
+
# one_to_one :producer, :from => Session, :key => :producer_id
|
21
|
+
#
|
22
|
+
# The one_to_one macro also creates a setter, which accepts nil, a hash or
|
23
|
+
# a model instance, e.g.:
|
24
|
+
#
|
25
|
+
# p = Producer[1234]
|
26
|
+
# node = Node[:path => '/']
|
27
|
+
# node.producer = p
|
28
|
+
# node.producer_id #=> 1234
|
29
|
+
#
|
30
|
+
def self.one_to_one(name, opts)
|
31
|
+
# deprecation
|
32
|
+
if opts[:class]
|
33
|
+
warn "The :class option has been deprecated. Please use :from instead."
|
34
|
+
opts[:from] = opts[:class]
|
35
|
+
end
|
36
|
+
|
37
|
+
from = opts[:from]
|
38
|
+
from || (raise Error, "No association source defined (use :from option)")
|
39
|
+
key = opts[:key] || (name.to_s + ID_POSTFIX).to_sym
|
40
|
+
|
41
|
+
setter_name = "#{name}=".to_sym
|
42
|
+
|
43
|
+
case from
|
44
|
+
when Symbol
|
45
|
+
class_def(name) {(k = @values[key]) ? db[from][:id => k] : nil}
|
46
|
+
when Sequel::Dataset
|
47
|
+
class_def(name) {(k = @values[key]) ? from[:id => k] : nil}
|
48
|
+
else
|
49
|
+
class_def(name) {(k = @values[key]) ? from[k] : nil}
|
50
|
+
end
|
51
|
+
class_def(setter_name) do |v|
|
52
|
+
case v
|
53
|
+
when nil
|
54
|
+
set(key => nil)
|
55
|
+
when Sequel::Model
|
56
|
+
set(key => v.pk)
|
57
|
+
when Hash
|
58
|
+
set(key => v[:id])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# define_method name, &eval(ONE_TO_ONE_PROC % [key, from])
|
63
|
+
end
|
64
|
+
|
65
|
+
# Creates a 1-N relationship by defining an association method, e.g.:
|
66
|
+
#
|
67
|
+
# class Book < Sequel::Model(:books)
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# class Author < Sequel::Model(:authors)
|
71
|
+
# one_to_many :books, :from => Book
|
72
|
+
# # which is equivalent to
|
73
|
+
# def books
|
74
|
+
# Book.filter(:author_id => id)
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# You can also set the foreign key explicitly by including a :key option:
|
79
|
+
#
|
80
|
+
# one_to_many :books, :from => Book, :key => :author_id
|
81
|
+
#
|
82
|
+
def self.one_to_many(name, opts)
|
83
|
+
# deprecation
|
84
|
+
if opts[:class]
|
85
|
+
warn "The :class option has been deprecated. Please use :from instead."
|
86
|
+
opts[:from] = opts[:class]
|
87
|
+
end
|
88
|
+
# deprecation
|
89
|
+
if opts[:on]
|
90
|
+
warn "The :on option has been deprecated. Please use :key instead."
|
91
|
+
opts[:key] = opts[:on]
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
from = opts[:from]
|
96
|
+
from || (raise Error, "No association source defined (use :from option)")
|
97
|
+
key = opts[:key] || (self.to_s + ID_POSTFIX).to_sym
|
98
|
+
|
99
|
+
case from
|
100
|
+
when Symbol
|
101
|
+
class_def(name) {db[from].filter(key => pk)}
|
102
|
+
else
|
103
|
+
class_def(name) {from.filter(key => pk)}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Model
|
3
|
+
# Defines a table schema (see Schema::Generator for more information).
|
4
|
+
#
|
5
|
+
# This is only needed if you want to use the create_table or drop_table
|
6
|
+
# methods.
|
7
|
+
def self.set_schema(name = nil, &block)
|
8
|
+
name ? set_dataset(db[name]) : name = table_name
|
9
|
+
@schema = Schema::Generator.new(db, &block)
|
10
|
+
if @schema.primary_key_name
|
11
|
+
set_primary_key @schema.primary_key_name
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns table schema for direct descendant of Model.
|
16
|
+
def self.schema
|
17
|
+
@schema || ((superclass != Model) && (superclass.schema))
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns name of table.
|
21
|
+
def self.table_name
|
22
|
+
dataset.opts[:from].first
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns true if table exists, false otherwise.
|
26
|
+
def self.table_exists?
|
27
|
+
db.table_exists?(table_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Creates table.
|
31
|
+
def self.create_table
|
32
|
+
db.create_table_sql_list(table_name, *schema.create_info).each {|s| db << s}
|
33
|
+
end
|
34
|
+
|
35
|
+
# Drops table.
|
36
|
+
def self.drop_table
|
37
|
+
db.execute db.drop_table_sql(table_name)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Like create_table but invokes drop_table when table_exists? is true.
|
41
|
+
def self.create_table!
|
42
|
+
drop_table if table_exists?
|
43
|
+
create_table
|
44
|
+
end
|
45
|
+
|
46
|
+
# Deprecated, use create_table! instead.
|
47
|
+
def self.recreate_table
|
48
|
+
warn "Model.recreate_table is deprecated. Please use Model.create_table! instead."
|
49
|
+
create_table!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Model
|
3
|
+
# =Basic Sequel Validations
|
4
|
+
#
|
5
|
+
# Sequel validations are based on the Validatable gem http://validatable.rubyforge.org/
|
6
|
+
#
|
7
|
+
# To assign default validations to a sequel model:
|
8
|
+
#
|
9
|
+
# class MyModel < SequelModel(:items)
|
10
|
+
# validates do
|
11
|
+
# format_of...
|
12
|
+
# presence_of...
|
13
|
+
# acceptance_of...
|
14
|
+
# confirmation_of...
|
15
|
+
# length_of...
|
16
|
+
# true_for...
|
17
|
+
# numericality_of...
|
18
|
+
# format_of...
|
19
|
+
# validates_base...
|
20
|
+
# validates_each...
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# You may also perform the usual 'longhand' way to assign default model validates
|
25
|
+
# directly within the model class itself:
|
26
|
+
#
|
27
|
+
# class MyModel < SequelModel(:items)
|
28
|
+
# validates_format_of...
|
29
|
+
# validates_presence_of...
|
30
|
+
# validates_acceptance_of...
|
31
|
+
# validates_confirmation_of...
|
32
|
+
# validates_length_of...
|
33
|
+
# validates_true_for...
|
34
|
+
# validates_numericality_of...
|
35
|
+
# validates_format_of...
|
36
|
+
# validates_base...
|
37
|
+
# validates_each...
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# Each validation allows for arguments:
|
41
|
+
# TODO: fill the argument options in here
|
42
|
+
#
|
43
|
+
# =Advanced Sequel Validations
|
44
|
+
#
|
45
|
+
# TODO: verify that advanced validates work as stated (aka write specs)
|
46
|
+
# NOTE: experimental
|
47
|
+
#
|
48
|
+
# To store validates for conditional usage simply specify a name with which to store them
|
49
|
+
# class User < Sequel::Model
|
50
|
+
#
|
51
|
+
# # This set of validates becomes stored as :default and gets injected into the model.
|
52
|
+
# validates do
|
53
|
+
# # standard validates calls
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# validates(:registration) do
|
57
|
+
# # user registration specific validates
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# validates(:promotion) do
|
61
|
+
# # user promotion validates
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# To use the above validates:
|
67
|
+
#
|
68
|
+
# @user.valid? # Runs the default validations only.
|
69
|
+
# @user.valid?(:registration) # Runs both default and registration validations
|
70
|
+
# @user.valid?(:promotion) # Runs both default and promotion validations
|
71
|
+
#
|
72
|
+
# You may determine whether the model has validates via:
|
73
|
+
#
|
74
|
+
# has_validations? # will return true / false based on existence of validations on the model.
|
75
|
+
#
|
76
|
+
# You may also retrieve the validations block if needed:
|
77
|
+
#
|
78
|
+
# validates(:registration) # returns the registration validation block.
|
79
|
+
#
|
80
|
+
# validates() method parameters:
|
81
|
+
# a validations block - runs the validations block on the model & stores as :default
|
82
|
+
# a name and a validations block - stores the block under the name
|
83
|
+
# a name - returns a stored block of that name or nil
|
84
|
+
# nothing - returns true / false based on if validations exist for the model.
|
85
|
+
#
|
86
|
+
module Validations
|
87
|
+
class Generator
|
88
|
+
def initialize(model_class ,&block)
|
89
|
+
@model_class = model_class
|
90
|
+
instance_eval(&block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def method_missing(method, *args)
|
94
|
+
method = :"validates_#{method}"
|
95
|
+
@model_class.send(method, *args)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
begin
|
101
|
+
require "validatable"
|
102
|
+
include ::Validatable
|
103
|
+
def self.validates(&block)
|
104
|
+
Validations::Generator.new(self, &block)
|
105
|
+
end
|
106
|
+
# return true if there are validations stored, false otherwise
|
107
|
+
def self.has_validations?
|
108
|
+
validations.length > 0 ? true : false
|
109
|
+
end
|
110
|
+
rescue LoadError
|
111
|
+
STDERR.puts <<-MESSAGE
|
112
|
+
Install the validatable gem in order to use Sequel Model validations
|
113
|
+
If you would like model validations to work, install the validatable gem
|
114
|
+
MESSAGE
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe "Model attribute setters" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
MODEL_DB.reset
|
7
|
+
|
8
|
+
@c = Class.new(Sequel::Model(:items)) do
|
9
|
+
def columns
|
10
|
+
[:id, :x, :y]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should mark the column value as changed" do
|
16
|
+
o = @c.new
|
17
|
+
o.changed_columns.should == []
|
18
|
+
|
19
|
+
o.x = 2
|
20
|
+
o.changed_columns.should == [:x]
|
21
|
+
|
22
|
+
o.y = 3
|
23
|
+
o.changed_columns.should == [:x, :y]
|
24
|
+
|
25
|
+
o.changed_columns.clear
|
26
|
+
|
27
|
+
o[:x] = 2
|
28
|
+
o.changed_columns.should == [:x]
|
29
|
+
|
30
|
+
o[:y] = 3
|
31
|
+
o.changed_columns.should == [:x, :y]
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "Model#serialize" do
|
37
|
+
|
38
|
+
before(:each) do
|
39
|
+
MODEL_DB.reset
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should translate values to YAML when creating records" do
|
43
|
+
@c = Class.new(Sequel::Model(:items)) do
|
44
|
+
no_primary_key
|
45
|
+
serialize :abc
|
46
|
+
end
|
47
|
+
|
48
|
+
@c.create(:abc => 1)
|
49
|
+
@c.create(:abc => "hello")
|
50
|
+
|
51
|
+
MODEL_DB.sqls.should == [ \
|
52
|
+
"INSERT INTO items (abc) VALUES ('--- 1\n')", \
|
53
|
+
"INSERT INTO items (abc) VALUES ('--- hello\n')", \
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should support calling after the class is defined" do
|
58
|
+
@c = Class.new(Sequel::Model(:items)) do
|
59
|
+
no_primary_key
|
60
|
+
end
|
61
|
+
|
62
|
+
@c.serialize :def
|
63
|
+
|
64
|
+
@c.create(:def => 1)
|
65
|
+
@c.create(:def => "hello")
|
66
|
+
|
67
|
+
MODEL_DB.sqls.should == [ \
|
68
|
+
"INSERT INTO items (def) VALUES ('--- 1\n')", \
|
69
|
+
"INSERT INTO items (def) VALUES ('--- hello\n')", \
|
70
|
+
]
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should support using the Marshal format" do
|
74
|
+
@c = Class.new(Sequel::Model(:items)) do
|
75
|
+
no_primary_key
|
76
|
+
serialize :abc, :format => :marshal
|
77
|
+
end
|
78
|
+
|
79
|
+
@c.create(:abc => 1)
|
80
|
+
@c.create(:abc => "hello")
|
81
|
+
|
82
|
+
MODEL_DB.sqls.should == [ \
|
83
|
+
"INSERT INTO items (abc) VALUES ('\004\bi\006')", \
|
84
|
+
"INSERT INTO items (abc) VALUES ('\004\b\"\nhello')", \
|
85
|
+
]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should translate values to and from YAML using accessor methods" do
|
89
|
+
@c = Class.new(Sequel::Model(:items)) do
|
90
|
+
serialize :abc, :def
|
91
|
+
end
|
92
|
+
|
93
|
+
ds = @c.dataset
|
94
|
+
ds.extend(Module.new {
|
95
|
+
attr_accessor :raw
|
96
|
+
|
97
|
+
def fetch_rows(sql, &block)
|
98
|
+
block.call(@raw)
|
99
|
+
end
|
100
|
+
|
101
|
+
@@sqls = nil
|
102
|
+
|
103
|
+
def insert(*args)
|
104
|
+
@@sqls = insert_sql(*args)
|
105
|
+
end
|
106
|
+
|
107
|
+
def update(*args)
|
108
|
+
@@sqls = update_sql(*args)
|
109
|
+
end
|
110
|
+
|
111
|
+
def sqls
|
112
|
+
@@sqls
|
113
|
+
end
|
114
|
+
|
115
|
+
def columns
|
116
|
+
[:id, :abc, :def]
|
117
|
+
end
|
118
|
+
}
|
119
|
+
)
|
120
|
+
|
121
|
+
ds.raw = {:id => 1, :abc => "--- 1\n", :def => "--- hello\n"}
|
122
|
+
o = @c.first
|
123
|
+
o.id.should == 1
|
124
|
+
o.abc.should == 1
|
125
|
+
o.def.should == "hello"
|
126
|
+
|
127
|
+
o.set(:abc => 23)
|
128
|
+
ds.sqls.should == "UPDATE items SET abc = '#{23.to_yaml}' WHERE (id = 1)"
|
129
|
+
|
130
|
+
ds.raw = {:id => 1, :abc => "--- 1\n", :def => "--- hello\n"}
|
131
|
+
o = @c.create(:abc => [1, 2, 3])
|
132
|
+
ds.sqls.should == "INSERT INTO items (abc) VALUES ('#{[1, 2, 3].to_yaml}')"
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
describe Sequel::Model, "super_dataset" do
|
138
|
+
|
139
|
+
before(:each) do
|
140
|
+
MODEL_DB.reset
|
141
|
+
class SubClass < Sequel::Model(:items) ; end
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should call the superclass's dataset" do
|
145
|
+
SubClass.should_receive(:superclass).exactly(3).times.and_return(Sequel::Model(:items))
|
146
|
+
Sequel::Model(:items).should_receive(:dataset)
|
147
|
+
SubClass.super_dataset
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Sequel::Model, "caching" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
MODEL_DB.reset
|
7
|
+
|
8
|
+
@cache_class = Class.new(Hash) do
|
9
|
+
attr_accessor :ttl
|
10
|
+
def set(k, v, ttl); self[k] = v; @ttl = ttl; end
|
11
|
+
def get(k); self[k]; end
|
12
|
+
end
|
13
|
+
cache = @cache_class.new
|
14
|
+
@cache = cache
|
15
|
+
|
16
|
+
@c = Class.new(Sequel::Model(:items)) do
|
17
|
+
set_cache cache
|
18
|
+
|
19
|
+
def self.columns
|
20
|
+
[:name, :id]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
$cache_dataset_row = {:name => 'sharon', :id => 1}
|
25
|
+
@dataset = @c.dataset
|
26
|
+
$sqls = []
|
27
|
+
@dataset.extend(Module.new {
|
28
|
+
def fetch_rows(sql)
|
29
|
+
$sqls << sql
|
30
|
+
yield $cache_dataset_row
|
31
|
+
end
|
32
|
+
|
33
|
+
def update(values)
|
34
|
+
$sqls << update_sql(values)
|
35
|
+
$cache_dataset_row.merge!(values)
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete
|
39
|
+
$sqls << delete_sql
|
40
|
+
end
|
41
|
+
})
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should set the model's cache store" do
|
45
|
+
@c.cache_store.should be(@cache)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have a default ttl of 3600" do
|
49
|
+
@c.cache_ttl.should == 3600
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should take a ttl option" do
|
53
|
+
@c.set_cache @cache, :ttl => 1234
|
54
|
+
@c.cache_ttl.should == 1234
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should offer a set_cache_ttl method for setting the ttl" do
|
58
|
+
@c.cache_ttl.should == 3600
|
59
|
+
@c.set_cache_ttl 1234
|
60
|
+
@c.cache_ttl.should == 1234
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should generate a cache key appropriate to the class" do
|
64
|
+
m = @c.new
|
65
|
+
m.values[:id] = 1
|
66
|
+
m.cache_key.should == "#{m.class}:1"
|
67
|
+
|
68
|
+
# custom primary key
|
69
|
+
@c.set_primary_key :ttt
|
70
|
+
m = @c.new
|
71
|
+
m.values[:ttt] = 333
|
72
|
+
m.cache_key.should == "#{m.class}:333"
|
73
|
+
|
74
|
+
# composite primary key
|
75
|
+
@c.set_primary_key [:a, :b, :c]
|
76
|
+
m = @c.new
|
77
|
+
m.values[:a] = 123
|
78
|
+
m.values[:c] = 456
|
79
|
+
m.values[:b] = 789
|
80
|
+
m.cache_key.should == "#{m.class}:123,789,456"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should raise error if attempting to generate cache_key and primary key value is null" do
|
84
|
+
m = @c.new
|
85
|
+
proc {m.cache_key}.should raise_error(Sequel::Error)
|
86
|
+
|
87
|
+
m.values[:id] = 1
|
88
|
+
proc {m.cache_key}.should_not raise_error(Sequel::Error)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should set the cache when reading from the database" do
|
92
|
+
$sqls.should == []
|
93
|
+
@cache.should be_empty
|
94
|
+
|
95
|
+
m = @c[1]
|
96
|
+
$sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
|
97
|
+
m.values.should == $cache_dataset_row
|
98
|
+
@cache[m.cache_key].should == m
|
99
|
+
|
100
|
+
# read from cache
|
101
|
+
m2 = @c[1]
|
102
|
+
$sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
|
103
|
+
m2.should == m
|
104
|
+
m2.values.should == $cache_dataset_row
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should delete the cache when writing to the database" do
|
108
|
+
# fill the cache
|
109
|
+
m = @c[1]
|
110
|
+
@cache[m.cache_key].should == m
|
111
|
+
|
112
|
+
m.set(:name => 'tutu')
|
113
|
+
@cache.has_key?(m.cache_key).should be_false
|
114
|
+
$sqls.last.should == "UPDATE items SET name = 'tutu' WHERE (id = 1)"
|
115
|
+
|
116
|
+
m = @c[1]
|
117
|
+
@cache[m.cache_key].should == m
|
118
|
+
m.name = 'hey'
|
119
|
+
m.save
|
120
|
+
@cache.has_key?(m.cache_key).should be_false
|
121
|
+
$sqls.last.should == "UPDATE items SET name = 'hey', id = 1 WHERE (id = 1)"
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should delete the cache when deleting the record" do
|
125
|
+
# fill the cache
|
126
|
+
m = @c[1]
|
127
|
+
@cache[m.cache_key].should == m
|
128
|
+
|
129
|
+
m.delete
|
130
|
+
@cache.has_key?(m.cache_key).should be_false
|
131
|
+
$sqls.last.should == "DELETE FROM items WHERE (id = 1)"
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should support #[] as a shortcut to #find with hash" do
|
135
|
+
m = @c[:id => 3]
|
136
|
+
@cache[m.cache_key].should be_nil
|
137
|
+
$sqls.last.should == "SELECT * FROM items WHERE (id = 3) LIMIT 1"
|
138
|
+
|
139
|
+
m = @c[1]
|
140
|
+
@cache[m.cache_key].should == m
|
141
|
+
$sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
|
142
|
+
"SELECT * FROM items WHERE (id = 1) LIMIT 1"]
|
143
|
+
|
144
|
+
@c[:id => 4]
|
145
|
+
$sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
|
146
|
+
"SELECT * FROM items WHERE (id = 1) LIMIT 1", \
|
147
|
+
"SELECT * FROM items WHERE (id = 4) LIMIT 1"]
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|