sequel_model 0.3.3 → 0.4
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 +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
|