sequel_model 0.3.3 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +8 -0
- data/COPYING +1 -1
- data/Rakefile +3 -3
- data/lib/sequel_model/record.rb +11 -12
- data/lib/sequel_model/validations.rb +3 -1
- data/lib/sequel_model.rb +1 -1
- data/spec/hooks_spec.rb +2 -2
- data/spec/model_spec.rb +1 -1
- data/spec/record_spec.rb +29 -4
- data/spec/validations_spec.rb +17 -5
- metadata +13 -15
- data/lib/sequel_model/relationships.rb +0 -224
- data/spec/relationships_spec.rb +0 -191
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 0.4 (2008-02-05)
|
2
|
+
|
3
|
+
* Fixed Model#set to work with string keys (#143).
|
4
|
+
|
5
|
+
* Fixed Model.create to correctly initialize instances marked as new (#135).
|
6
|
+
|
7
|
+
* Fixed Model#initialize to convert string keys into symbol keys. This also fixes problem with validating objects initialized with string keys (#136).
|
8
|
+
|
1
9
|
=== 0.3.3 (2008-01-25)
|
2
10
|
|
3
11
|
* Finalized support for virtual attributes.
|
data/COPYING
CHANGED
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ include FileUtils
|
|
9
9
|
# Configuration
|
10
10
|
##############################################################################
|
11
11
|
NAME = "sequel_model"
|
12
|
-
VERS = "0.
|
12
|
+
VERS = "0.4"
|
13
13
|
CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
|
14
14
|
RDOC_OPTS = [
|
15
15
|
"--quiet",
|
@@ -117,7 +117,7 @@ require "spec/rake/spectask"
|
|
117
117
|
|
118
118
|
desc "Run specs with coverage"
|
119
119
|
Spec::Rake::SpecTask.new("spec") do |t|
|
120
|
-
t.spec_files = FileList["spec
|
120
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
121
121
|
t.spec_opts = File.read("spec/spec.opts").split("\n")
|
122
122
|
t.rcov_opts = File.read("spec/rcov.opts").split("\n")
|
123
123
|
t.rcov = true
|
@@ -125,7 +125,7 @@ end
|
|
125
125
|
|
126
126
|
desc "Run specs without coverage"
|
127
127
|
Spec::Rake::SpecTask.new("spec_no_cov") do |t|
|
128
|
-
t.spec_files = FileList["spec
|
128
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
129
129
|
t.spec_opts = File.read("spec/spec.opts").split("\n")
|
130
130
|
end
|
131
131
|
|
data/lib/sequel_model/record.rb
CHANGED
@@ -171,7 +171,9 @@ module Sequel
|
|
171
171
|
@primary_key ||= self.class.primary_key
|
172
172
|
end
|
173
173
|
|
174
|
-
# Returns the primary key value identifying the model instance.
|
174
|
+
# Returns the primary key value identifying the model instance. If the
|
175
|
+
# model's primary key is changed (using #set_primary_key or #no_primary_key)
|
176
|
+
# this method is redefined accordingly.
|
175
177
|
def pk
|
176
178
|
@pk ||= @values[:id]
|
177
179
|
end
|
@@ -196,26 +198,22 @@ module Sequel
|
|
196
198
|
values.delete(k)
|
197
199
|
end
|
198
200
|
end
|
199
|
-
|
201
|
+
values.inject(@values) {|m, kv| m[kv[0].to_sym] = kv[1]; m}
|
202
|
+
# @values.merge!(values)
|
200
203
|
end
|
201
204
|
else
|
202
205
|
@values = values || {}
|
203
206
|
end
|
204
207
|
|
205
208
|
k = primary_key
|
206
|
-
|
207
|
-
@new = k == nil
|
208
|
-
else
|
209
|
-
# if there's no primary key for the model class, or
|
210
|
-
# @values doesn't contain a primary key value, then
|
211
|
-
# we regard this instance as new.
|
212
|
-
@new = (k == nil) || (!(Array === k) && !@values[k])
|
213
|
-
end
|
209
|
+
@new = !from_db
|
214
210
|
|
215
211
|
block[self] if block
|
216
212
|
after_initialize
|
217
213
|
end
|
218
214
|
|
215
|
+
# Initializes a model instance as an existing record. This constructor is
|
216
|
+
# used by Sequel to initialize model instances when fetching records.
|
219
217
|
def self.load(values)
|
220
218
|
new(values, true)
|
221
219
|
end
|
@@ -272,8 +270,9 @@ module Sequel
|
|
272
270
|
|
273
271
|
# Updates and saves values to database from the passed-in Hash.
|
274
272
|
def set(values)
|
275
|
-
|
276
|
-
|
273
|
+
v = values.inject({}) {|m, kv| m[kv[0].to_sym] = kv[1]; m}
|
274
|
+
this.update(v)
|
275
|
+
v.each {|k, v| @values[k] = v}
|
277
276
|
end
|
278
277
|
alias_method :update, :set
|
279
278
|
|
data/lib/sequel_model.rb
CHANGED
data/spec/hooks_spec.rb
CHANGED
@@ -179,7 +179,7 @@ describe "Model#before_update && Model#after_update" do
|
|
179
179
|
end
|
180
180
|
|
181
181
|
specify "should be called around record update" do
|
182
|
-
m = @c.
|
182
|
+
m = @c.load(:id => 2233)
|
183
183
|
m.save
|
184
184
|
MODEL_DB.sqls.should == [
|
185
185
|
'BLAH before',
|
@@ -200,7 +200,7 @@ describe "Model#before_save && Model#after_save" do
|
|
200
200
|
end
|
201
201
|
|
202
202
|
specify "should be called around record update" do
|
203
|
-
m = @c.
|
203
|
+
m = @c.load(:id => 2233)
|
204
204
|
m.save
|
205
205
|
MODEL_DB.sqls.should == [
|
206
206
|
'BLAH before',
|
data/spec/model_spec.rb
CHANGED
data/spec/record_spec.rb
CHANGED
@@ -20,7 +20,7 @@ describe "Model#save" do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should update a record for an existing model instance" do
|
23
|
-
o = @c.
|
23
|
+
o = @c.load(:id => 3, :x => 1)
|
24
24
|
o.save
|
25
25
|
|
26
26
|
MODEL_DB.sqls.first.should =~
|
@@ -28,7 +28,7 @@ describe "Model#save" do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should update only the given columns if given" do
|
31
|
-
o = @c.
|
31
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
32
32
|
o.save(:y)
|
33
33
|
|
34
34
|
MODEL_DB.sqls.first.should == "UPDATE items SET y = NULL WHERE (id = 3)"
|
@@ -63,10 +63,15 @@ describe "Model#save_changes" do
|
|
63
63
|
o.save_changes
|
64
64
|
|
65
65
|
MODEL_DB.sqls.should be_empty
|
66
|
+
|
67
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
68
|
+
o.save_changes
|
69
|
+
|
70
|
+
MODEL_DB.sqls.should be_empty
|
66
71
|
end
|
67
72
|
|
68
73
|
it "should update only changed columns" do
|
69
|
-
o = @c.
|
74
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
70
75
|
o.x = 2
|
71
76
|
|
72
77
|
o.save_changes
|
@@ -111,6 +116,14 @@ describe "Model#set" do
|
|
111
116
|
o.x.should == 1
|
112
117
|
end
|
113
118
|
|
119
|
+
it "should support string keys" do
|
120
|
+
o = @c.new(:id => 1)
|
121
|
+
o.x.should be_nil
|
122
|
+
o.set('x' => 1)
|
123
|
+
o.x.should == 1
|
124
|
+
MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
|
125
|
+
end
|
126
|
+
|
114
127
|
it "should be aliased by #update" do
|
115
128
|
o = @c.new(:id => 1)
|
116
129
|
o.update(:x => 1)
|
@@ -291,7 +304,7 @@ describe Sequel::Model, "update_with_params" do
|
|
291
304
|
def self.columns; [:x, :y]; end
|
292
305
|
end
|
293
306
|
@o1 = @c.new
|
294
|
-
@o2 = @c.
|
307
|
+
@o2 = @c.load(:id => 5)
|
295
308
|
end
|
296
309
|
|
297
310
|
it "should filter the given params using the model columns" do
|
@@ -485,6 +498,11 @@ describe Sequel::Model, "#initialize" do
|
|
485
498
|
m.values.should == {:id => 1, :x => 2}
|
486
499
|
m.blah.should == 3
|
487
500
|
end
|
501
|
+
|
502
|
+
specify "should convert string keys into symbol keys" do
|
503
|
+
m = @c.new('id' => 1, 'x' => 2)
|
504
|
+
m.values.should == {:id => 1, :x => 2}
|
505
|
+
end
|
488
506
|
end
|
489
507
|
|
490
508
|
describe Sequel::Model, ".create" do
|
@@ -517,6 +535,13 @@ describe Sequel::Model, ".create" do
|
|
517
535
|
o2.should == :blah
|
518
536
|
MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (333)", "SELECT * FROM items WHERE (id IN ('INSERT INTO items (x) VALUES (333)')) LIMIT 1"]
|
519
537
|
end
|
538
|
+
|
539
|
+
it "should create a row for a model with custom primary key" do
|
540
|
+
@c.set_primary_key :x
|
541
|
+
o = @c.create(:x => 30)
|
542
|
+
o.class.should == @c
|
543
|
+
MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (30)", "SELECT * FROM items WHERE (x = 30) LIMIT 1"]
|
544
|
+
end
|
520
545
|
end
|
521
546
|
|
522
547
|
describe Sequel::Model, "#refresh" do
|
data/spec/validations_spec.rb
CHANGED
@@ -138,7 +138,7 @@ describe Sequel::Model, "Validations" do
|
|
138
138
|
@cow.should be_valid
|
139
139
|
end
|
140
140
|
|
141
|
-
it "should have a validates block that
|
141
|
+
it "should have a validates block that contains multiple validations" do
|
142
142
|
class Person < Sequel::Model
|
143
143
|
validations.clear
|
144
144
|
validates do
|
@@ -182,6 +182,18 @@ describe Sequel::Model, "Validations" do
|
|
182
182
|
Person.should have_validations
|
183
183
|
Smurf.should_not have_validations
|
184
184
|
end
|
185
|
+
|
186
|
+
it "should validate correctly instances initialized with string keys" do
|
187
|
+
class Can < Sequel::Model
|
188
|
+
def columns; [:id, :name]; end
|
189
|
+
|
190
|
+
validates_length_of :name, :minimum => 4
|
191
|
+
end
|
192
|
+
|
193
|
+
Can.new('name' => 'ab').should_not be_valid
|
194
|
+
Can.new('name' => 'abcd').should be_valid
|
195
|
+
end
|
196
|
+
|
185
197
|
end
|
186
198
|
|
187
199
|
describe "Model#save!" do
|
@@ -193,7 +205,7 @@ describe "Model#save!" do
|
|
193
205
|
o.errors[a] << 'blah' unless v == 5
|
194
206
|
end
|
195
207
|
end
|
196
|
-
@m = @c.
|
208
|
+
@m = @c.load(:id => 4)
|
197
209
|
MODEL_DB.reset
|
198
210
|
end
|
199
211
|
|
@@ -204,7 +216,7 @@ describe "Model#save!" do
|
|
204
216
|
end
|
205
217
|
end
|
206
218
|
|
207
|
-
describe "Model#save
|
219
|
+
describe "Model#save" do
|
208
220
|
setup do
|
209
221
|
@c = Class.new(Sequel::Model(:people)) do
|
210
222
|
def columns; [:id]; end
|
@@ -213,7 +225,7 @@ describe "Model#save!" do
|
|
213
225
|
o.errors[a] << 'blah' unless v == 5
|
214
226
|
end
|
215
227
|
end
|
216
|
-
@m = @c.
|
228
|
+
@m = @c.load(:id => 4)
|
217
229
|
MODEL_DB.reset
|
218
230
|
end
|
219
231
|
|
@@ -224,7 +236,7 @@ describe "Model#save!" do
|
|
224
236
|
|
225
237
|
@m.id = 5
|
226
238
|
@m.should be_valid
|
227
|
-
@m.save
|
239
|
+
@m.save.should_not be_false
|
228
240
|
MODEL_DB.sqls.should == ['UPDATE people SET id = 5 WHERE (id = 5)']
|
229
241
|
end
|
230
242
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: "0.4"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-02-05 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -44,30 +44,28 @@ files:
|
|
44
44
|
- COPYING
|
45
45
|
- README
|
46
46
|
- Rakefile
|
47
|
+
- spec/hooks_spec.rb
|
47
48
|
- spec/base_spec.rb
|
48
49
|
- spec/caching_spec.rb
|
49
|
-
- spec/
|
50
|
-
- spec/model_spec.rb
|
51
|
-
- spec/plugins_spec.rb
|
52
|
-
- spec/rcov.opts
|
50
|
+
- spec/validations_spec.rb
|
53
51
|
- spec/record_spec.rb
|
52
|
+
- spec/spec_helper.rb
|
53
|
+
- spec/model_spec.rb
|
54
54
|
- spec/relations_spec.rb
|
55
|
-
- spec/relationships_spec.rb
|
56
55
|
- spec/schema_spec.rb
|
56
|
+
- spec/rcov.opts
|
57
|
+
- spec/plugins_spec.rb
|
57
58
|
- spec/spec.opts
|
58
|
-
- spec/spec_helper.rb
|
59
|
-
- spec/validations_spec.rb
|
60
59
|
- lib/sequel_model
|
61
|
-
- lib/sequel_model/
|
62
|
-
- lib/sequel_model/caching.rb
|
63
|
-
- lib/sequel_model/hooks.rb
|
64
|
-
- lib/sequel_model/plugins.rb
|
60
|
+
- lib/sequel_model/validations.rb
|
65
61
|
- lib/sequel_model/pretty_table.rb
|
66
62
|
- lib/sequel_model/record.rb
|
67
63
|
- lib/sequel_model/relations.rb
|
68
|
-
- lib/sequel_model/relationships.rb
|
69
64
|
- lib/sequel_model/schema.rb
|
70
|
-
- lib/sequel_model/
|
65
|
+
- lib/sequel_model/plugins.rb
|
66
|
+
- lib/sequel_model/hooks.rb
|
67
|
+
- lib/sequel_model/base.rb
|
68
|
+
- lib/sequel_model/caching.rb
|
71
69
|
- lib/sequel_model.rb
|
72
70
|
- CHANGELOG
|
73
71
|
has_rdoc: true
|
@@ -1,224 +0,0 @@
|
|
1
|
-
# = Sequel Relationships
|
2
|
-
# Database modelling is generally done with an ER (Entity Relationship) diagram.
|
3
|
-
# Shouldn't ORM's facilitate simlilar specification?
|
4
|
-
|
5
|
-
# class Post < Sequel::Model
|
6
|
-
# relationships do
|
7
|
-
# # Specify the relationships that exist with the User model (users table)
|
8
|
-
# # These relationships are precisely the ER diagram connecting arrows.
|
9
|
-
# end
|
10
|
-
# end
|
11
|
-
|
12
|
-
#
|
13
|
-
# = Relationships
|
14
|
-
#
|
15
|
-
# are specifications of the ends of the ER diagrams connectors that are touching
|
16
|
-
# the current model.
|
17
|
-
#
|
18
|
-
# one_to_one, has_one
|
19
|
-
# many_to_one, belongs_to
|
20
|
-
# many_to_many, has_many
|
21
|
-
|
22
|
-
# ?parameters may be :zero, :one, :many which specifies the cardinality of the connection
|
23
|
-
|
24
|
-
# Example:
|
25
|
-
# class Post < Sequel::Model
|
26
|
-
# relationships do
|
27
|
-
# has :one, :blog, :required => true, :normalized => false # uses a blog_id field, which cannot be null, in the Post model
|
28
|
-
# has :one, :account # uses a join table called accounts_posts to link the post with it's account.
|
29
|
-
# has :many, :comments # uses a comments_posts join table
|
30
|
-
# has :many, :authors, :required => true # authors_posts join table, requires at least one author
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# Relationship API Details
|
36
|
-
#
|
37
|
-
|
38
|
-
#
|
39
|
-
# == belongs_to
|
40
|
-
#
|
41
|
-
|
42
|
-
# Defines an blog and blog= method
|
43
|
-
# belongs_to :blog
|
44
|
-
|
45
|
-
# Same, but uses "b_id" as the blog's id field.
|
46
|
-
# belongs_to :blog, :key => :b_id
|
47
|
-
|
48
|
-
# has_many :comments
|
49
|
-
# * Defines comments method which will query the join table appropriately.
|
50
|
-
# * Checks to see if a "comments_posts" join table exists (alphabetical order)
|
51
|
-
# ** If it does not exist, will create the join table.
|
52
|
-
# ** If options are passed in these will be used to further define the join table.
|
53
|
-
|
54
|
-
|
55
|
-
# Benefits:
|
56
|
-
# * Normalized DB
|
57
|
-
# * Easy to define join objects
|
58
|
-
# * Efficient queries, database gets to use indexed fields (pkeys) instead of a string field and an id.
|
59
|
-
#
|
60
|
-
# For example, polymorphic associations now become:
|
61
|
-
# [user] 1-* [addresses_users] *-1 [addresses]
|
62
|
-
# [companies] 1-* [addresses_companies] *-1 [addresses]
|
63
|
-
# [clients] 1-* [addresses_clients] *-1 [addresses]
|
64
|
-
# it is automatically polymorphic by specifying the has relationship inside the 2User and Company tables to addresses. Addresses themselves don't care. so we have by default polymorphism.
|
65
|
-
# If you need to talk about a 'Company Address' then you can subclass, CompanyAddress < Address and do has :many, :company_addresses
|
66
|
-
|
67
|
-
module Sequel
|
68
|
-
|
69
|
-
class Model
|
70
|
-
|
71
|
-
module Relationships
|
72
|
-
class Generator
|
73
|
-
def initialize(model_class, &block)
|
74
|
-
@model_class = model_class
|
75
|
-
instance_eval(&block)
|
76
|
-
end
|
77
|
-
|
78
|
-
def method_missing(method, *args)
|
79
|
-
@model_class.send(method, *args)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class << self
|
85
|
-
@@model_relationships = []
|
86
|
-
|
87
|
-
def relationship_exists?(arity,relation)
|
88
|
-
@@model_relationships.detect do |relation|
|
89
|
-
relation[:arity] == arity &&
|
90
|
-
relation[:klass] == relation
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# has arity<Symbol>, model<Symbol>
|
95
|
-
# has :one, :blog, :required => true # blog_id field, cannot be null
|
96
|
-
# has :one, :account # account_id field
|
97
|
-
# has :many, :comments # comments_posts join table
|
98
|
-
def has(arity, klass, options = {})
|
99
|
-
|
100
|
-
# Commence with the sanity checks!
|
101
|
-
unless [:one,:many].include? arity
|
102
|
-
raise Sequel::Error, "Arity must be specified {:one, :many}."
|
103
|
-
end
|
104
|
-
|
105
|
-
if relationship_exists?(arity, klass)
|
106
|
-
raise Sequel::Error, "The relationship '#{self} has #{arity} #{klass}' is already defined."
|
107
|
-
end
|
108
|
-
|
109
|
-
# Make sure the join table exists
|
110
|
-
auto_create_join_table(klass, options)
|
111
|
-
|
112
|
-
# Store the relationship
|
113
|
-
@@model_relationships << {
|
114
|
-
:arity => arity,
|
115
|
-
:klass => klass,
|
116
|
-
:options => options
|
117
|
-
}
|
118
|
-
|
119
|
-
# Define relationship methods
|
120
|
-
after_initialize do
|
121
|
-
define_relationship_method arity, klass, options
|
122
|
-
end
|
123
|
-
|
124
|
-
#unless normalized
|
125
|
-
# :required => true # The relationship must be populated to save
|
126
|
-
# can only be used with normalized => false :
|
127
|
-
#end
|
128
|
-
# save the relationship
|
129
|
-
end
|
130
|
-
|
131
|
-
# the proxy methods has_xxx ... , simply pass thru to to has :xxx, ...
|
132
|
-
def has_one(klass, options = {})
|
133
|
-
has :one, klass, options
|
134
|
-
end
|
135
|
-
|
136
|
-
def has_many(klass, options = {})
|
137
|
-
has :many, klass, options
|
138
|
-
end
|
139
|
-
|
140
|
-
def belongs_to(klass, options = {})
|
141
|
-
has :one, klass, options
|
142
|
-
end
|
143
|
-
|
144
|
-
# returns true if exists, false if not
|
145
|
-
def join_table?(first, second)
|
146
|
-
# we still have to test this out
|
147
|
-
db[join_table(first, second)].table_exists?
|
148
|
-
end
|
149
|
-
|
150
|
-
# TODO: Move this elsewhere? outside relationships?
|
151
|
-
# creates a join table given two table names
|
152
|
-
def create_join_table(first, second)
|
153
|
-
first_key, second_key = "#{first}_id", "#{second}_id"
|
154
|
-
db.create_table join_table(first, second).to_sym do
|
155
|
-
#primary_key [first_key.to_sym, second_key.to_sym]
|
156
|
-
integer first_key, :null => false
|
157
|
-
integer second_key, :null => false
|
158
|
-
end unless join_table?(first, second)
|
159
|
-
end
|
160
|
-
|
161
|
-
def create_join_table!(first, second)
|
162
|
-
db.drop_table join_table(first, second)
|
163
|
-
create_join_table(first, second)
|
164
|
-
end
|
165
|
-
|
166
|
-
def auto_create_join_table!(klass)
|
167
|
-
auto_create_join_table(klass, :force => true)
|
168
|
-
end
|
169
|
-
|
170
|
-
def auto_create_join_table(klass, options = {})
|
171
|
-
first, second = table_name, klass.to_s.pluralize
|
172
|
-
if join_table?(first, second) && options[:force] == true
|
173
|
-
create_join_table!(first, second)
|
174
|
-
else
|
175
|
-
create_join_table(first, second)
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
# Given two models, it outputs the join table name
|
180
|
-
# which is sorted alphabetically with each table name pluralized
|
181
|
-
# Examples:
|
182
|
-
# join_table(user, post) #=> :posts_users
|
183
|
-
# join_table(users, posts) #=> :posts_users
|
184
|
-
def join_table(first, second)
|
185
|
-
first, second = first.to_s.pluralize, second.to_s.pluralize
|
186
|
-
[first, second].sort.join("_").to_sym
|
187
|
-
end
|
188
|
-
|
189
|
-
# relationships do
|
190
|
-
# ...
|
191
|
-
# end
|
192
|
-
def relationships(&block)
|
193
|
-
Relationships::Generator.new(self, &block)
|
194
|
-
end
|
195
|
-
|
196
|
-
# return true if there are validations stored, false otherwise
|
197
|
-
def has_relationships?
|
198
|
-
model_relationships.length > 0 ? true : false
|
199
|
-
end
|
200
|
-
|
201
|
-
def model_relationships
|
202
|
-
@@model_relationships
|
203
|
-
end
|
204
|
-
|
205
|
-
end
|
206
|
-
|
207
|
-
# Defines relationship method from the current class to the klass specified
|
208
|
-
def define_relationship_method(arity, relation, options)
|
209
|
-
if arity == :one
|
210
|
-
self.instance_eval "
|
211
|
-
def #{relation}
|
212
|
-
self.dataset.left_outer_join(#{relation}, :id => :#{self.class.table_name.to_s.singularize}_id).limit(1)
|
213
|
-
end
|
214
|
-
"
|
215
|
-
elsif arity == :many
|
216
|
-
self.instance_eval "
|
217
|
-
def #{relation}
|
218
|
-
self.dataset.left_outer_join(#{relation}, :id => :#{self.class.table_name.to_s.singularize}_id)
|
219
|
-
end
|
220
|
-
"
|
221
|
-
end
|
222
|
-
end # define_relationship_method
|
223
|
-
end # Model
|
224
|
-
end # Sequel
|
data/spec/relationships_spec.rb
DELETED
@@ -1,191 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
-
|
3
|
-
#__END__
|
4
|
-
|
5
|
-
# class Post < Sequel::Model
|
6
|
-
# relationships do
|
7
|
-
# has :one, :blog, :required => true, :normalized => false # uses a blog_id field, which cannot be null, in the Post model
|
8
|
-
# has :one, :account # uses a join table called accounts_posts to link the post with it's account.
|
9
|
-
# has :many, :comments # uses a comments_posts join table
|
10
|
-
# has :many, :authors, :required => true # authors_posts join table, requires at least one author
|
11
|
-
# end
|
12
|
-
# end
|
13
|
-
describe Sequel::Model, "relationships" do
|
14
|
-
before :all do
|
15
|
-
class Smurf < Sequel::Model
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
after :each do
|
20
|
-
Smurf.model_relationships.clear
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "has" do
|
24
|
-
|
25
|
-
it "should raise an exception if an arity {:one, :many} is not specified" do
|
26
|
-
Smurf.should_not_receive(:auto_create_join_table).with(:smurfette, {}).and_return(true)
|
27
|
-
Smurf.should_not_receive(:relationship_exists?).with(:one, :smurfette).and_return(true)
|
28
|
-
Smurf.stub!(:after_initialize)
|
29
|
-
lambda {
|
30
|
-
class Smurf
|
31
|
-
relationships do
|
32
|
-
has :sex, :with_smurfette
|
33
|
-
end
|
34
|
-
end
|
35
|
-
}.should raise_error Sequel::Error, "Arity must be specified {:one, :many}."
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should check to see if the relationship exists" do
|
39
|
-
Smurf.should_not_receive(:relationship_exists?).with(:one, :smurfette).and_return(true)
|
40
|
-
Smurf.stub!(:after_initialize)
|
41
|
-
lambda {
|
42
|
-
class Smurf
|
43
|
-
relationships do
|
44
|
-
has :sex, :with_smurfette
|
45
|
-
end
|
46
|
-
end
|
47
|
-
}.should raise_error Sequel::Error, "Arity must be specified {:one, :many}."
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should raise an exception if the relationship has already been specified" do
|
51
|
-
Smurf.should_receive(:relationship_exists?).with(:one, :smurfette).and_return(true)
|
52
|
-
Smurf.stub!(:after_initialize)
|
53
|
-
lambda {
|
54
|
-
class Smurf
|
55
|
-
relationships do
|
56
|
-
has :one, :smurfette
|
57
|
-
end
|
58
|
-
end
|
59
|
-
}.should raise_error Sequel::Error, "The relationship 'Smurf has one smurfette' is already defined."
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should establish a has :one relationship" do
|
63
|
-
Smurf.stub!(:auto_create_join_table)
|
64
|
-
Smurf.should_receive(:relationship_exists?).with(:one, :smurfette).and_return(false)
|
65
|
-
Smurf.should_receive(:after_initialize)
|
66
|
-
class Smurf
|
67
|
-
relationships do
|
68
|
-
has :one, :smurfette
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
@smurf = Smurf.new
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should establish a has :many relationship" do
|
77
|
-
Smurf.should_receive(:auto_create_join_table).with(:smurfette, {}).and_return(true)
|
78
|
-
Smurf.should_receive(:relationship_exists?).with(:many, :smurfette).and_return(false)
|
79
|
-
Smurf.should_receive(:after_initialize)
|
80
|
-
class Smurf
|
81
|
-
relationships do
|
82
|
-
has :many, :smurfette
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
@smurf = Smurf.new
|
87
|
-
end
|
88
|
-
|
89
|
-
it "should call the auto_create_join_table method" do
|
90
|
-
Smurf.should_receive(:auto_create_join_table).with(:smurfette, {}).and_return(true)
|
91
|
-
|
92
|
-
class Smurf
|
93
|
-
relationships do
|
94
|
-
has :one, :smurfette
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
it "should store the relationship to ensure there is no duplication" do
|
100
|
-
class Smurf
|
101
|
-
relationships do
|
102
|
-
has :one, :smurfette
|
103
|
-
has :many, :legs
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
Smurf.model_relationships.should == [
|
108
|
-
{:arity=>:one, :options=>{}, :klass=>:smurfette},
|
109
|
-
{:arity=>:many, :options=>{}, :klass=>:legs}
|
110
|
-
]
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
it "should create an instance method for the has one relationship" do
|
115
|
-
class Smurf
|
116
|
-
relationships do
|
117
|
-
has :one, :smurfette
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
@smurf = Smurf.new
|
122
|
-
@smurf.should respond_to(:smurfette)
|
123
|
-
@smurf.should_not respond_to(:smurfettes)
|
124
|
-
end
|
125
|
-
|
126
|
-
it "should create an instance method for the has many relationship" do
|
127
|
-
class Smurf
|
128
|
-
relationships do
|
129
|
-
has :one, :smurfettes
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
@smurf = Smurf.new
|
134
|
-
@smurf.should respond_to(:smurfettes)
|
135
|
-
@smurf.should_not respond_to(:smurf)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
describe "has_one" do
|
140
|
-
it "should be an alias for has :one" do
|
141
|
-
Smurf.should_receive(:has).with(:one, :smurfette, {})
|
142
|
-
class Smurf
|
143
|
-
relationships do
|
144
|
-
has_one :smurfette
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
describe "has_many" do
|
151
|
-
it "should be an alias for has :many" do
|
152
|
-
Smurf.should_receive(:has).with(:many, :smurfette, {})
|
153
|
-
class Smurf
|
154
|
-
relationships do
|
155
|
-
has_many :smurfette
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
describe "belongs_to" do
|
162
|
-
it "should be an alias for has :one" do
|
163
|
-
Smurf.should_receive(:has).with(:one, :smurfette, {})
|
164
|
-
class Smurf
|
165
|
-
relationships do
|
166
|
-
belongs_to :smurfette
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
describe "has_relationships?" do
|
173
|
-
it "should return true if the class has any relationships" do
|
174
|
-
class Smurf
|
175
|
-
relationships do
|
176
|
-
belongs_to :smurfette
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
Smurf.has_relationships?.should be_true
|
181
|
-
end
|
182
|
-
|
183
|
-
it "should return false if the class has no relationships" do
|
184
|
-
class Smurf
|
185
|
-
end
|
186
|
-
|
187
|
-
Smurf.has_relationships?.should be_false
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
end
|