sequel 2.7.1 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +56 -0
- data/README +1 -0
- data/Rakefile +1 -1
- data/lib/sequel_core.rb +9 -16
- data/lib/sequel_core/adapters/ado.rb +6 -15
- data/lib/sequel_core/adapters/db2.rb +8 -10
- data/lib/sequel_core/adapters/dbi.rb +6 -4
- data/lib/sequel_core/adapters/informix.rb +21 -22
- data/lib/sequel_core/adapters/jdbc.rb +69 -10
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +1 -0
- data/lib/sequel_core/adapters/mysql.rb +81 -13
- data/lib/sequel_core/adapters/odbc.rb +32 -4
- data/lib/sequel_core/adapters/openbase.rb +6 -5
- data/lib/sequel_core/adapters/oracle.rb +23 -7
- data/lib/sequel_core/adapters/postgres.rb +42 -32
- data/lib/sequel_core/adapters/shared/mssql.rb +37 -62
- data/lib/sequel_core/adapters/shared/mysql.rb +22 -7
- data/lib/sequel_core/adapters/shared/oracle.rb +27 -48
- data/lib/sequel_core/adapters/shared/postgres.rb +64 -43
- data/lib/sequel_core/adapters/shared/progress.rb +31 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +15 -4
- data/lib/sequel_core/adapters/sqlite.rb +6 -14
- data/lib/sequel_core/connection_pool.rb +47 -13
- data/lib/sequel_core/database.rb +60 -35
- data/lib/sequel_core/database/schema.rb +4 -4
- data/lib/sequel_core/dataset.rb +12 -3
- data/lib/sequel_core/dataset/convenience.rb +4 -13
- data/lib/sequel_core/dataset/prepared_statements.rb +30 -28
- data/lib/sequel_core/dataset/sql.rb +144 -85
- data/lib/sequel_core/dataset/stored_procedures.rb +75 -0
- data/lib/sequel_core/dataset/unsupported.rb +31 -0
- data/lib/sequel_core/exceptions.rb +6 -0
- data/lib/sequel_core/schema/generator.rb +4 -3
- data/lib/sequel_core/schema/sql.rb +41 -23
- data/lib/sequel_core/sql.rb +29 -1
- data/lib/sequel_model/associations.rb +1 -1
- data/lib/sequel_model/record.rb +31 -28
- data/spec/adapters/mysql_spec.rb +37 -4
- data/spec/adapters/oracle_spec.rb +26 -4
- data/spec/adapters/sqlite_spec.rb +7 -0
- data/spec/integration/prepared_statement_test.rb +24 -0
- data/spec/integration/schema_test.rb +1 -1
- data/spec/sequel_core/connection_pool_spec.rb +49 -2
- data/spec/sequel_core/core_sql_spec.rb +9 -2
- data/spec/sequel_core/database_spec.rb +64 -14
- data/spec/sequel_core/dataset_spec.rb +105 -7
- data/spec/sequel_core/schema_spec.rb +40 -12
- data/spec/sequel_core/spec_helper.rb +1 -0
- data/spec/sequel_model/spec_helper.rb +1 -0
- metadata +6 -3
@@ -0,0 +1,75 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Dataset
|
3
|
+
module StoredProcedureMethods
|
4
|
+
SQL_QUERY_TYPE = Hash.new{|h,k| h[k] = k}
|
5
|
+
SQL_QUERY_TYPE[:first] = SQL_QUERY_TYPE[:all] = :select
|
6
|
+
|
7
|
+
# The name of the stored procedure to call
|
8
|
+
attr_accessor :sproc_name
|
9
|
+
|
10
|
+
# Call the prepared statement
|
11
|
+
def call(*args, &block)
|
12
|
+
@sproc_args = args
|
13
|
+
case @sproc_type
|
14
|
+
when :select, :all
|
15
|
+
all(&block)
|
16
|
+
when :first
|
17
|
+
first
|
18
|
+
when :insert
|
19
|
+
insert
|
20
|
+
when :update
|
21
|
+
update
|
22
|
+
when :delete
|
23
|
+
delete
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Programmer friendly string showing this is a stored procedure,
|
28
|
+
# showing the name of the procedure.
|
29
|
+
def inspect
|
30
|
+
"<#{self.class.name}/StoredProcedure name=#{@sproc_name}>"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Set the type of the sproc and override the corresponding _sql
|
34
|
+
# method to return the empty string (since the result will be
|
35
|
+
# ignored anyway).
|
36
|
+
def sproc_type=(type)
|
37
|
+
@sproc_type = type
|
38
|
+
meta_def("#{sql_query_type}_sql"){|*a| ''}
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# The type of query (:select, :insert, :delete, :update).
|
44
|
+
def sql_query_type
|
45
|
+
SQL_QUERY_TYPE[@sproc_type]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module StoredProcedures
|
50
|
+
# For the given type (:select, :first, :insert, :update, or :delete),
|
51
|
+
# run the database stored procedure with the given name with the given
|
52
|
+
# arguments.
|
53
|
+
def call_sproc(type, name, *args)
|
54
|
+
prepare_sproc(type, name).call(*args)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Transform this dataset into a stored procedure that you can call
|
58
|
+
# multiple times with new arguments.
|
59
|
+
def prepare_sproc(type, name)
|
60
|
+
sp = clone
|
61
|
+
prepare_extend_sproc(sp)
|
62
|
+
sp.sproc_type = type
|
63
|
+
sp.sproc_name = name
|
64
|
+
sp
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Extend the dataset with the stored procedure methods.
|
70
|
+
def prepare_extend_sproc(ds)
|
71
|
+
ds.extend(StoredProcedureMethods)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Sequel::Dataset
|
2
|
+
# This module should be included in the dataset class for all databases that
|
3
|
+
# don't support INTERSECT or EXCEPT.
|
4
|
+
module UnsupportedIntersectExcept
|
5
|
+
# Raise an Error if EXCEPT is used
|
6
|
+
def except(ds, all=false)
|
7
|
+
raise(Sequel::Error, "EXCEPT not supported")
|
8
|
+
end
|
9
|
+
|
10
|
+
# Raise an Error if INTERSECT is used
|
11
|
+
def intersect(ds, all=false)
|
12
|
+
raise(Sequel::Error, "INTERSECT not supported")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# This module should be included in the dataset class for all databases that
|
17
|
+
# don't support INTERSECT ALL or EXCEPT ALL.
|
18
|
+
module UnsupportedIntersectExceptAll
|
19
|
+
# Raise an Error if EXCEPT is used
|
20
|
+
def except(ds, all=false)
|
21
|
+
raise(Sequel::Error, "EXCEPT ALL not supported") if all
|
22
|
+
super(ds)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Raise an Error if INTERSECT is used
|
26
|
+
def intersect(ds, all=false)
|
27
|
+
raise(Sequel::Error, "INTERSECT ALL not supported") if all
|
28
|
+
super(ds)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -31,4 +31,10 @@ module Sequel
|
|
31
31
|
# Generic error raised by the database adapters, indicating a
|
32
32
|
# problem originating from the database server.
|
33
33
|
class DatabaseError < Error; end
|
34
|
+
|
35
|
+
# Error that should be raised by adapters when they determine that the connection
|
36
|
+
# to the database has been lost. Instructs the connection pool code to
|
37
|
+
# remove that connection from the pool so that other connections can be acquired
|
38
|
+
# automatically.
|
39
|
+
class DatabaseDisconnectError < DatabaseError; end
|
34
40
|
end
|
@@ -127,9 +127,10 @@ module Sequel
|
|
127
127
|
# optional middle argument denotes the type.
|
128
128
|
#
|
129
129
|
# Examples:
|
130
|
-
# primary_key(:id)
|
130
|
+
# primary_key(:id)
|
131
131
|
# primary_key(:zip_code, :null => false)
|
132
132
|
# primary_key([:street_number, :house_number])
|
133
|
+
# primary_key(:id, :string, :auto_increment => false)
|
133
134
|
def primary_key(name, *args)
|
134
135
|
return composite_primary_key(name, *args) if name.is_a?(Array)
|
135
136
|
@primary_key = @db.serial_primary_key_options.merge({:name => name})
|
@@ -276,8 +277,8 @@ module Sequel
|
|
276
277
|
end
|
277
278
|
|
278
279
|
# Modify a column's type in the DDL for the table.
|
279
|
-
def set_column_type(name, type)
|
280
|
-
@operations << {:op => :set_column_type, :name => name, :type => type}
|
280
|
+
def set_column_type(name, type, opts={})
|
281
|
+
@operations << {:op => :set_column_type, :name => name, :type => type}.merge(opts)
|
281
282
|
end
|
282
283
|
|
283
284
|
# Modify a column's NOT NULL constraint.
|
@@ -29,7 +29,7 @@ module Sequel
|
|
29
29
|
when :rename_column
|
30
30
|
"RENAME COLUMN #{quoted_name} TO #{quote_identifier(op[:new_name])}"
|
31
31
|
when :set_column_type
|
32
|
-
"ALTER COLUMN #{quoted_name} TYPE #{op
|
32
|
+
"ALTER COLUMN #{quoted_name} TYPE #{type_literal(op)}"
|
33
33
|
when :set_column_default
|
34
34
|
"ALTER COLUMN #{quoted_name} SET DEFAULT #{literal(op[:default])}"
|
35
35
|
when :set_column_null
|
@@ -187,9 +187,9 @@ module Sequel
|
|
187
187
|
end
|
188
188
|
end
|
189
189
|
|
190
|
+
# Proxy the quote_schema_table method to the dataset
|
190
191
|
def quote_schema_table(table)
|
191
|
-
|
192
|
-
"#{"#{quote_identifier(schema)}." if schema}#{quote_identifier(table)}"
|
192
|
+
schema_utility_dataset.quote_schema_table(table)
|
193
193
|
end
|
194
194
|
|
195
195
|
# Proxy the quote_identifier method to the dataset, used for quoting tables and columns.
|
@@ -202,7 +202,7 @@ module Sequel
|
|
202
202
|
"ALTER TABLE #{quote_schema_table(name)} RENAME TO #{quote_schema_table(new_name)}"
|
203
203
|
end
|
204
204
|
|
205
|
-
# Parse the schema from the database
|
205
|
+
# Parse the schema from the database.
|
206
206
|
# If the table_name is not given, returns the schema for all tables as a hash.
|
207
207
|
# If the table_name is given, returns the schema for a single table as an
|
208
208
|
# array with all members being arrays of length 2. Available options are:
|
@@ -212,11 +212,17 @@ module Sequel
|
|
212
212
|
# unless you are sure that schema has not been called before with a
|
213
213
|
# table_name, otherwise you may only getting the schemas for tables
|
214
214
|
# that have been requested explicitly.
|
215
|
-
|
216
|
-
|
215
|
+
# * :schema - An explicit schema to use. It may also be implicitly provided
|
216
|
+
# via the table name.
|
217
|
+
def schema(table = nil, opts={})
|
218
|
+
if table
|
219
|
+
sch, table_name = schema_and_table(table)
|
220
|
+
quoted_name = quote_schema_table(table)
|
221
|
+
end
|
222
|
+
opts = opts.merge(:schema=>sch) if sch && !opts.include?(:schema)
|
217
223
|
if opts[:reload] && @schemas
|
218
224
|
if table_name
|
219
|
-
@schemas.delete(
|
225
|
+
@schemas.delete(quoted_name)
|
220
226
|
else
|
221
227
|
@schemas = nil
|
222
228
|
end
|
@@ -224,26 +230,31 @@ module Sequel
|
|
224
230
|
|
225
231
|
if @schemas
|
226
232
|
if table_name
|
227
|
-
return @schemas[
|
233
|
+
return @schemas[quoted_name] if @schemas[quoted_name]
|
228
234
|
else
|
229
235
|
return @schemas
|
230
236
|
end
|
231
237
|
end
|
238
|
+
|
239
|
+
@schemas ||= Hash.new do |h,k|
|
240
|
+
quote_name = quote_schema_table(k)
|
241
|
+
h[quote_name] if h.include?(quote_name)
|
242
|
+
end
|
232
243
|
|
233
244
|
if table_name
|
234
|
-
@schemas ||= {}
|
235
245
|
if respond_to?(:schema_parse_table, true)
|
236
|
-
@schemas[
|
246
|
+
@schemas[quoted_name] = schema_parse_table(table_name, opts)
|
237
247
|
else
|
238
248
|
raise Error, 'schema parsing is not implemented on this database'
|
239
249
|
end
|
240
250
|
else
|
241
251
|
if respond_to?(:schema_parse_tables, true)
|
242
|
-
@schemas
|
252
|
+
@schemas.merge!(schema_parse_tables(opts))
|
243
253
|
elsif respond_to?(:schema_parse_table, true) and respond_to?(:tables, true)
|
244
|
-
tables.each{|t|
|
254
|
+
tables.each{|t| @schemas[quote_identifier(t)] = schema_parse_table(t.to_s, opts)}
|
245
255
|
@schemas
|
246
256
|
else
|
257
|
+
@schemas = nil
|
247
258
|
raise Error, 'schema parsing is not implemented on this database'
|
248
259
|
end
|
249
260
|
end
|
@@ -256,30 +267,37 @@ module Sequel
|
|
256
267
|
|
257
268
|
private
|
258
269
|
|
270
|
+
# Remove the cached schema for the given schema name
|
271
|
+
def remove_cached_schema(table)
|
272
|
+
@schemas.delete(quote_schema_table(table)) if @schemas
|
273
|
+
end
|
274
|
+
|
259
275
|
# Match the database's column type to a ruby type via a
|
260
276
|
# regular expression. The following ruby types are supported:
|
261
277
|
# integer, string, date, datetime, boolean, and float.
|
262
278
|
def schema_column_type(db_type)
|
263
279
|
case db_type
|
264
|
-
when /\Atinyint/
|
280
|
+
when /\Atinyint/io
|
265
281
|
Sequel.convert_tinyint_to_bool ? :boolean : :integer
|
266
|
-
when /\
|
267
|
-
:
|
268
|
-
when /\A(character( varying)?|varchar|text)/
|
282
|
+
when /\Ainterval\z/io
|
283
|
+
:interval
|
284
|
+
when /\A(character( varying)?|varchar|text)/io
|
269
285
|
:string
|
270
|
-
when /\
|
286
|
+
when /\A(int(eger)?|bigint|smallint)/io
|
287
|
+
:integer
|
288
|
+
when /\Adate\z/io
|
271
289
|
:date
|
272
|
-
when /\A(datetime|timestamp( with(out)? time zone)?)\z/
|
290
|
+
when /\A(datetime|timestamp( with(out)? time zone)?)\z/io
|
273
291
|
:datetime
|
274
|
-
when /\Atime( with(out)? time zone)?\z/
|
292
|
+
when /\Atime( with(out)? time zone)?\z/io
|
275
293
|
:time
|
276
|
-
when
|
294
|
+
when /\Aboolean\z/io
|
277
295
|
:boolean
|
278
|
-
when /\A(real|float|double( precision)?)\z/
|
296
|
+
when /\A(real|float|double( precision)?)\z/io
|
279
297
|
:float
|
280
|
-
when /\A(numeric(\(\d+,\d+\))?|decimal|money)\z/
|
298
|
+
when /\A(numeric(\(\d+,\d+\))?|decimal|money)\z/io
|
281
299
|
:decimal
|
282
|
-
when
|
300
|
+
when /\Abytea\z/io
|
283
301
|
:blob
|
284
302
|
end
|
285
303
|
end
|
data/lib/sequel_core/sql.rb
CHANGED
@@ -685,6 +685,34 @@ module Sequel
|
|
685
685
|
end
|
686
686
|
end
|
687
687
|
|
688
|
+
# Represents a literal string with placeholders and arguments.
|
689
|
+
# This is necessary to ensure delayed literalization of the arguments
|
690
|
+
# required for the prepared statement support
|
691
|
+
class PlaceholderLiteralString < SpecificExpression
|
692
|
+
# The arguments that will be subsituted into the placeholders.
|
693
|
+
attr_reader :args
|
694
|
+
|
695
|
+
# The literal string containing placeholders
|
696
|
+
attr_reader :str
|
697
|
+
|
698
|
+
# Whether to surround the expression with parantheses
|
699
|
+
attr_reader :parens
|
700
|
+
|
701
|
+
# Create an object with the given conditions and
|
702
|
+
# default value.
|
703
|
+
def initialize(str, args, parens=false)
|
704
|
+
@str = str
|
705
|
+
@args = args
|
706
|
+
@parens = parens
|
707
|
+
end
|
708
|
+
|
709
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
710
|
+
# since it may be database dependent.
|
711
|
+
def to_s(ds)
|
712
|
+
ds.placeholder_literal_string_sql(self)
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
688
716
|
# Subclass of ComplexExpression where the expression results
|
689
717
|
# in a numeric value in SQL.
|
690
718
|
class NumericExpression < ComplexExpression
|
@@ -831,7 +859,7 @@ module Sequel
|
|
831
859
|
# LiteralString is used to represent literal SQL expressions. A
|
832
860
|
# LiteralString is copied verbatim into an SQL statement. Instances of
|
833
861
|
# LiteralString can be created by calling String#lit.
|
834
|
-
# LiteralStrings can use all of the SQL::
|
862
|
+
# LiteralStrings can also use all of the SQL::OrderMethods and the
|
835
863
|
# SQL::ComplexExpressionMethods.
|
836
864
|
class LiteralString < ::String
|
837
865
|
include SQL::OrderMethods
|
@@ -394,7 +394,7 @@ module Sequel::Model::Associations
|
|
394
394
|
return if old_val and run_association_callbacks(opts, :before_remove, old_val) == false
|
395
395
|
return if o and run_association_callbacks(opts, :before_add, o) == false
|
396
396
|
send(opts._setter_method, o)
|
397
|
-
|
397
|
+
associations[name] = o
|
398
398
|
remove_reciprocal_object(opts, old_val) if old_val
|
399
399
|
add_reciprocal_object(opts, o) if o
|
400
400
|
run_association_callbacks(opts, :after_add, o) if o
|
data/lib/sequel_model/record.rb
CHANGED
@@ -4,15 +4,6 @@ module Sequel
|
|
4
4
|
# to be called automatically via set.
|
5
5
|
RESTRICTED_SETTER_METHODS = %w"== === []= taguri= typecast_empty_string_to_nil= typecast_on_assignment= strict_param_setting= raise_on_save_failure= raise_on_typecast_failure="
|
6
6
|
|
7
|
-
# The current cached associations. A hash with the keys being the
|
8
|
-
# association name symbols and the values being the associated object
|
9
|
-
# or nil (many_to_one), or the array of associated objects (*_to_many).
|
10
|
-
attr_reader :associations
|
11
|
-
|
12
|
-
# The columns that have been updated. This isn't completely accurate,
|
13
|
-
# see Model#[]=.
|
14
|
-
attr_reader :changed_columns
|
15
|
-
|
16
7
|
# The hash of attribute values. Keys are symbols with the names of the
|
17
8
|
# underlying database columns.
|
18
9
|
attr_reader :values
|
@@ -32,9 +23,7 @@ module Sequel
|
|
32
23
|
# string keys will work if from_db is false.
|
33
24
|
# * from_db - should only be set by Model.load, forget it
|
34
25
|
# exists.
|
35
|
-
def initialize(values = {}, from_db = false
|
36
|
-
@associations = {}
|
37
|
-
@changed_columns = []
|
26
|
+
def initialize(values = {}, from_db = false)
|
38
27
|
if from_db
|
39
28
|
@new = false
|
40
29
|
@values = values
|
@@ -42,8 +31,8 @@ module Sequel
|
|
42
31
|
@values = {}
|
43
32
|
@new = true
|
44
33
|
set(values)
|
45
|
-
|
46
|
-
yield self if
|
34
|
+
changed_columns.clear
|
35
|
+
yield self if block_given?
|
47
36
|
end
|
48
37
|
after_initialize
|
49
38
|
end
|
@@ -61,7 +50,7 @@ module Sequel
|
|
61
50
|
# If the column isn't in @values, we can't assume it is
|
62
51
|
# NULL in the database, so assume it has changed.
|
63
52
|
if new? || !@values.include?(column) || value != @values[column]
|
64
|
-
|
53
|
+
changed_columns << column unless changed_columns.include?(column)
|
65
54
|
@values[column] = typecast_value(column, value)
|
66
55
|
end
|
67
56
|
end
|
@@ -84,6 +73,19 @@ module Sequel
|
|
84
73
|
# self.class.
|
85
74
|
alias_method :model, :class
|
86
75
|
|
76
|
+
# The current cached associations. A hash with the keys being the
|
77
|
+
# association name symbols and the values being the associated object
|
78
|
+
# or nil (many_to_one), or the array of associated objects (*_to_many).
|
79
|
+
def associations
|
80
|
+
@associations ||= {}
|
81
|
+
end
|
82
|
+
|
83
|
+
# The columns that have been updated. This isn't completely accurate,
|
84
|
+
# see Model#[]=.
|
85
|
+
def changed_columns
|
86
|
+
@changed_columns ||= []
|
87
|
+
end
|
88
|
+
|
87
89
|
# Deletes and returns self. Does not run destroy hooks.
|
88
90
|
# Look into using destroy instead.
|
89
91
|
def delete
|
@@ -171,7 +173,8 @@ module Sequel
|
|
171
173
|
# exists in the database.
|
172
174
|
def refresh
|
173
175
|
@values = this.first || raise(Error, "Record not found")
|
174
|
-
|
176
|
+
changed_columns.clear
|
177
|
+
associations.clear
|
175
178
|
self
|
176
179
|
end
|
177
180
|
alias_method :reload, :refresh
|
@@ -220,12 +223,12 @@ module Sequel
|
|
220
223
|
else
|
221
224
|
return save_failure(:update) if before_update == false
|
222
225
|
if columns.empty?
|
223
|
-
vals = opts[:changed] ? @values.reject{|k,v|
|
226
|
+
vals = opts[:changed] ? @values.reject{|k,v| !changed_columns.include?(k)} : @values
|
224
227
|
this.update(vals)
|
225
|
-
|
228
|
+
changed_columns.clear
|
226
229
|
else # update only the specified columns
|
227
|
-
this.update(@values.reject
|
228
|
-
|
230
|
+
this.update(@values.reject{|k, v| !columns.include?(k)})
|
231
|
+
changed_columns.reject!{|c| columns.include?(c)}
|
229
232
|
end
|
230
233
|
after_update
|
231
234
|
end
|
@@ -237,7 +240,7 @@ module Sequel
|
|
237
240
|
# chanaged. If no columns have been changed, returns nil. If unable to
|
238
241
|
# save, returns false unless raise_on_save_failure is true.
|
239
242
|
def save_changes
|
240
|
-
save(:changed=>true) || false unless
|
243
|
+
save(:changed=>true) || false unless changed_columns.empty?
|
241
244
|
end
|
242
245
|
|
243
246
|
# Updates the instance with the supplied values with support for virtual
|
@@ -357,7 +360,7 @@ module Sequel
|
|
357
360
|
raise(Sequel::Error, 'associated object does not have a primary key') if opts.need_associated_primary_key? && !o.pk
|
358
361
|
return if run_association_callbacks(opts, :before_add, o) == false
|
359
362
|
send(opts._add_method, o)
|
360
|
-
|
363
|
+
associations[opts[:name]].push(o) if associations.include?(opts[:name])
|
361
364
|
add_reciprocal_object(opts, o)
|
362
365
|
run_association_callbacks(opts, :after_add, o)
|
363
366
|
o
|
@@ -378,8 +381,8 @@ module Sequel
|
|
378
381
|
# Load the associated objects using the dataset
|
379
382
|
def load_associated_objects(opts, reload=false)
|
380
383
|
name = opts[:name]
|
381
|
-
if
|
382
|
-
|
384
|
+
if associations.include?(name) and !reload
|
385
|
+
associations[name]
|
383
386
|
else
|
384
387
|
objs = if opts.returns_array?
|
385
388
|
send(opts.dataset_method).all
|
@@ -393,7 +396,7 @@ module Sequel
|
|
393
396
|
run_association_callbacks(opts, :after_load, objs)
|
394
397
|
# Only one_to_many associations should set the reciprocal object
|
395
398
|
objs.each{|o| add_reciprocal_object(opts, o)} if opts.set_reciprocal_to_self?
|
396
|
-
|
399
|
+
associations[name] = objs
|
397
400
|
end
|
398
401
|
end
|
399
402
|
|
@@ -401,8 +404,8 @@ module Sequel
|
|
401
404
|
def remove_all_associated_objects(opts)
|
402
405
|
raise(Sequel::Error, 'model object does not have a primary key') unless pk
|
403
406
|
send(opts._remove_all_method)
|
404
|
-
ret =
|
405
|
-
|
407
|
+
ret = associations[opts[:name]].each{|o| remove_reciprocal_object(opts, o)} if associations.include?(opts[:name])
|
408
|
+
associations[opts[:name]] = []
|
406
409
|
ret
|
407
410
|
end
|
408
411
|
|
@@ -412,7 +415,7 @@ module Sequel
|
|
412
415
|
raise(Sequel::Error, 'associated object does not have a primary key') if opts.need_associated_primary_key? && !o.pk
|
413
416
|
return if run_association_callbacks(opts, :before_remove, o) == false
|
414
417
|
send(opts._remove_method, o)
|
415
|
-
|
418
|
+
associations[opts[:name]].delete_if{|x| o === x} if associations.include?(opts[:name])
|
416
419
|
remove_reciprocal_object(opts, o)
|
417
420
|
run_association_callbacks(opts, :after_remove, o)
|
418
421
|
o
|