sequel 2.10.0 → 2.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +51 -1
- data/README.rdoc +2 -2
- data/Rakefile +2 -2
- data/doc/advanced_associations.rdoc +6 -18
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/lib/sequel_core/adapters/ado.rb +3 -0
- data/lib/sequel_core/adapters/db2.rb +0 -11
- data/lib/sequel_core/adapters/dbi.rb +0 -11
- data/lib/sequel_core/adapters/do.rb +0 -12
- data/lib/sequel_core/adapters/firebird.rb +21 -16
- data/lib/sequel_core/adapters/informix.rb +1 -11
- data/lib/sequel_core/adapters/jdbc.rb +1 -13
- data/lib/sequel_core/adapters/jdbc/h2.rb +3 -11
- data/lib/sequel_core/adapters/jdbc/mysql.rb +0 -17
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +3 -15
- data/lib/sequel_core/adapters/mysql.rb +31 -27
- data/lib/sequel_core/adapters/odbc.rb +34 -28
- data/lib/sequel_core/adapters/openbase.rb +0 -11
- data/lib/sequel_core/adapters/oracle.rb +11 -9
- data/lib/sequel_core/adapters/postgres.rb +14 -17
- data/lib/sequel_core/adapters/shared/mssql.rb +6 -15
- data/lib/sequel_core/adapters/shared/mysql.rb +29 -14
- data/lib/sequel_core/adapters/shared/oracle.rb +4 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +30 -35
- data/lib/sequel_core/adapters/shared/progress.rb +4 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +73 -13
- data/lib/sequel_core/adapters/sqlite.rb +8 -18
- data/lib/sequel_core/adapters/utils/date_format.rb +21 -0
- data/lib/sequel_core/{dataset → adapters/utils}/stored_procedures.rb +0 -0
- data/lib/sequel_core/{dataset → adapters/utils}/unsupported.rb +0 -0
- data/lib/sequel_core/core_ext.rb +1 -1
- data/lib/sequel_core/core_sql.rb +9 -4
- data/lib/sequel_core/database.rb +63 -62
- data/lib/sequel_core/dataset.rb +9 -4
- data/lib/sequel_core/dataset/convenience.rb +10 -9
- data/lib/sequel_core/dataset/prepared_statements.rb +1 -1
- data/lib/sequel_core/dataset/sql.rb +130 -36
- data/lib/sequel_core/schema/sql.rb +2 -2
- data/lib/sequel_core/sql.rb +44 -51
- data/lib/sequel_core/version.rb +1 -1
- data/lib/sequel_model/associations.rb +25 -17
- data/lib/sequel_model/base.rb +35 -7
- data/lib/sequel_model/caching.rb +1 -6
- data/lib/sequel_model/record.rb +23 -5
- data/lib/sequel_model/validations.rb +20 -5
- data/spec/adapters/firebird_spec.rb +6 -1
- data/spec/adapters/mysql_spec.rb +12 -0
- data/spec/adapters/postgres_spec.rb +2 -2
- data/spec/adapters/sqlite_spec.rb +81 -2
- data/spec/integration/dataset_test.rb +2 -2
- data/spec/integration/type_test.rb +12 -2
- data/spec/sequel_core/core_sql_spec.rb +46 -12
- data/spec/sequel_core/database_spec.rb +24 -12
- data/spec/sequel_core/dataset_spec.rb +82 -32
- data/spec/sequel_core/schema_spec.rb +16 -0
- data/spec/sequel_model/associations_spec.rb +89 -0
- data/spec/sequel_model/base_spec.rb +66 -0
- data/spec/sequel_model/eager_loading_spec.rb +32 -0
- data/spec/sequel_model/record_spec.rb +9 -9
- data/spec/sequel_model/spec_helper.rb +3 -0
- data/spec/sequel_model/validations_spec.rb +63 -3
- metadata +41 -4
@@ -12,7 +12,7 @@ module Sequel
|
|
12
12
|
SET_DEFAULT = 'SET DEFAULT'.freeze
|
13
13
|
SET_NULL = 'SET NULL'.freeze
|
14
14
|
TYPES = Hash.new {|h, k| k}
|
15
|
-
TYPES.merge!(:double=>'double precision', String=>'varchar',
|
15
|
+
TYPES.merge!(:double=>'double precision', String=>'varchar(255)',
|
16
16
|
Integer=>'integer', Fixnum=>'integer', Bignum=>'bigint',
|
17
17
|
Float=>'double precision', BigDecimal=>'numeric', Numeric=>'numeric',
|
18
18
|
Date=>'date', DateTime=>'timestamp', Time=>'timestamp', File=>'blob',
|
@@ -124,7 +124,7 @@ module Sequel
|
|
124
124
|
# for certain databases.
|
125
125
|
def default_index_name(table_name, columns)
|
126
126
|
schema, table = schema_and_table(table_name)
|
127
|
-
"#{"#{schema}_" if schema and schema != default_schema}#{table}_#{columns.join(UNDERSCORE)}_index"
|
127
|
+
"#{"#{schema}_" if schema and schema != default_schema}#{table}_#{columns.map{|c| c.is_one_of?(String, Symbol) ? c : literal(c).gsub(/\W/, '_')}.join(UNDERSCORE)}_index"
|
128
128
|
end
|
129
129
|
|
130
130
|
# The SQL to drop an index for the table.
|
data/lib/sequel_core/sql.rb
CHANGED
@@ -181,21 +181,21 @@ module Sequel
|
|
181
181
|
module CastMethods
|
182
182
|
# Cast the reciever to the given SQL type
|
183
183
|
def cast(sql_type)
|
184
|
-
|
184
|
+
Cast.new(self, sql_type)
|
185
185
|
end
|
186
186
|
alias_method :cast_as, :cast
|
187
187
|
|
188
188
|
# Cast the reciever to the given SQL type (or integer if none given),
|
189
189
|
# and return the result as a NumericExpression.
|
190
190
|
def cast_numeric(sql_type = nil)
|
191
|
-
cast(sql_type ||
|
191
|
+
cast(sql_type || Integer).sql_number
|
192
192
|
end
|
193
193
|
|
194
194
|
# Cast the reciever to the given SQL type (or text if none given),
|
195
195
|
# and return the result as a StringExpression, so you can use +
|
196
196
|
# directly on the result for SQL string concatenation.
|
197
197
|
def cast_string(sql_type = nil)
|
198
|
-
cast(sql_type ||
|
198
|
+
cast(sql_type || String).sql_string
|
199
199
|
end
|
200
200
|
end
|
201
201
|
|
@@ -336,12 +336,12 @@ module Sequel
|
|
336
336
|
module ComplexExpressionMethods
|
337
337
|
# Extract a datetime_part (e.g. year, month) from self:
|
338
338
|
#
|
339
|
-
# :date.extract(:year) # SQL: extract(year FROM date)
|
339
|
+
# :date.extract(:year) # SQL: extract(year FROM "date")
|
340
340
|
#
|
341
341
|
# Also has the benefit of returning the result as a
|
342
342
|
# NumericExpression instead of a generic ComplexExpression.
|
343
343
|
def extract(datetime_part)
|
344
|
-
|
344
|
+
Function.new(:extract, PlaceholderLiteralString.new("#{datetime_part} FROM ?", [self])).sql_number
|
345
345
|
end
|
346
346
|
|
347
347
|
# Return a BooleanExpression representation of self.
|
@@ -400,22 +400,6 @@ module Sequel
|
|
400
400
|
end
|
401
401
|
end
|
402
402
|
|
403
|
-
# Represents an SQL array. Added so it is possible to deal with a
|
404
|
-
# ruby array of all two pairs as an SQL array instead of an ordered
|
405
|
-
# hash-like conditions specifier.
|
406
|
-
class SQLArray < Expression
|
407
|
-
# Create an object with the given array.
|
408
|
-
def initialize(array)
|
409
|
-
@array = array
|
410
|
-
end
|
411
|
-
|
412
|
-
# Delegate the creation of the resulting SQL to the given dataset,
|
413
|
-
# since it may be database dependent.
|
414
|
-
def to_s(ds)
|
415
|
-
ds.array_sql(@array)
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
403
|
# Blob is used to represent binary data in the Ruby environment that is
|
420
404
|
# stored as a blob type in the database. In PostgreSQL, the blob type is
|
421
405
|
# called bytea. Sequel represents binary data as a Blob object because
|
@@ -423,9 +407,10 @@ module Sequel
|
|
423
407
|
# escaped.
|
424
408
|
class Blob < ::String
|
425
409
|
# return self.
|
426
|
-
def
|
410
|
+
def to_sequel_blob
|
427
411
|
self
|
428
412
|
end
|
413
|
+
alias to_blob to_sequel_blob
|
429
414
|
end
|
430
415
|
|
431
416
|
# Subclass of ComplexExpression where the expression results
|
@@ -516,6 +501,27 @@ module Sequel
|
|
516
501
|
end
|
517
502
|
end
|
518
503
|
|
504
|
+
# Represents a cast of an SQL expression to a specific type.
|
505
|
+
class Cast < GenericExpression
|
506
|
+
# The expression to cast
|
507
|
+
attr_reader :expr
|
508
|
+
|
509
|
+
# The type to which to cast the expression
|
510
|
+
attr_reader :type
|
511
|
+
|
512
|
+
# Set the attributes to the given arguments
|
513
|
+
def initialize(expr, type)
|
514
|
+
@expr = expr
|
515
|
+
@type = type
|
516
|
+
end
|
517
|
+
|
518
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
519
|
+
# since it may be database dependent.
|
520
|
+
def to_s(ds)
|
521
|
+
ds.cast_sql(expr, type)
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
519
525
|
# Represents all columns in a given table, table.* in SQL
|
520
526
|
class ColumnAll < SpecificExpression
|
521
527
|
# The table containing the columns being selected
|
@@ -586,35 +592,6 @@ module Sequel
|
|
586
592
|
end
|
587
593
|
end
|
588
594
|
|
589
|
-
# IrregularFunction is used for the SQL EXTRACT and CAST functions,
|
590
|
-
# which don't use regular function calling syntax. The IrregularFunction
|
591
|
-
# replaces the commas the regular function uses with a custom
|
592
|
-
# join string.
|
593
|
-
#
|
594
|
-
# This shouldn't be used directly, see CastMethods#cast and
|
595
|
-
# ComplexExpressionMethods#extract.
|
596
|
-
class IrregularFunction < Function
|
597
|
-
# The arguments to pass to the function (may be blank)
|
598
|
-
attr_reader :arg1, :arg2
|
599
|
-
|
600
|
-
# The SQL function to call
|
601
|
-
attr_reader :f
|
602
|
-
|
603
|
-
# The literal string to use in place of a comma to join arguments
|
604
|
-
attr_reader :joiner
|
605
|
-
|
606
|
-
# Set the attributes to the given arguments
|
607
|
-
def initialize(f, arg1, joiner, arg2)
|
608
|
-
@f, @arg1, @joiner, @arg2 = f, arg1, joiner, arg2
|
609
|
-
end
|
610
|
-
|
611
|
-
# Delegate the creation of the resulting SQL to the given dataset,
|
612
|
-
# since it may be database dependent.
|
613
|
-
def to_s(ds)
|
614
|
-
ds.irregular_function_sql(self)
|
615
|
-
end
|
616
|
-
end
|
617
|
-
|
618
595
|
# Represents an SQL JOIN clause, used for joining tables.
|
619
596
|
class JoinClause < SpecificExpression
|
620
597
|
# The type of join to do
|
@@ -785,6 +762,22 @@ module Sequel
|
|
785
762
|
end
|
786
763
|
end
|
787
764
|
|
765
|
+
# Represents an SQL array. Added so it is possible to deal with a
|
766
|
+
# ruby array of all two pairs as an SQL array instead of an ordered
|
767
|
+
# hash-like conditions specifier.
|
768
|
+
class SQLArray < Expression
|
769
|
+
# Create an object with the given array.
|
770
|
+
def initialize(array)
|
771
|
+
@array = array
|
772
|
+
end
|
773
|
+
|
774
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
775
|
+
# since it may be database dependent.
|
776
|
+
def to_s(ds)
|
777
|
+
ds.array_sql(@array)
|
778
|
+
end
|
779
|
+
end
|
780
|
+
|
788
781
|
# Represents an SQL array access, with multiple possible arguments.
|
789
782
|
class Subscript < GenericExpression
|
790
783
|
# The SQL array column
|
data/lib/sequel_core/version.rb
CHANGED
@@ -51,6 +51,15 @@
|
|
51
51
|
# one_to_many :attributes
|
52
52
|
# has_many :attributes
|
53
53
|
module Sequel::Model::Associations
|
54
|
+
# This module contains methods added to all association datasets
|
55
|
+
module DatasetMethods
|
56
|
+
# The model object that created the association dataset
|
57
|
+
attr_accessor :model_object
|
58
|
+
|
59
|
+
# The association reflection related to the association dataset
|
60
|
+
attr_accessor :association_reflection
|
61
|
+
end
|
62
|
+
|
54
63
|
# Array of all association reflections for this model class
|
55
64
|
def all_association_reflections
|
56
65
|
association_reflections.values
|
@@ -100,6 +109,10 @@ module Sequel::Model::Associations
|
|
100
109
|
# - :class - The associated class or its name. If not
|
101
110
|
# given, uses the association's name, which is camelized (and
|
102
111
|
# singularized unless the type is :many_to_one)
|
112
|
+
# - :clone - Merge the current options and block into the options and block used in defining
|
113
|
+
# the given association. Can be used to DRY up a bunch of similar associations that
|
114
|
+
# all share the same options such as :class and :key, while changing the order and block used.
|
115
|
+
# - :conditions - The conditions to use to filter the association, can be any argument passed to filter.
|
103
116
|
# - :dataset - A proc that is instance_evaled to get the base dataset
|
104
117
|
# to use for the _dataset method (before the other options are applied).
|
105
118
|
# - :eager - The associations to eagerly load via EagerLoading#eager when loading the associated object(s).
|
@@ -126,7 +139,8 @@ module Sequel::Model::Associations
|
|
126
139
|
# - :graph_block - The block to pass to join_table when eagerly loading
|
127
140
|
# the association via eager_graph.
|
128
141
|
# - :graph_conditions - The additional conditions to use on the SQL join when eagerly loading
|
129
|
-
# the association via eager_graph. Should be a hash or an array of all two pairs.
|
142
|
+
# the association via eager_graph. Should be a hash or an array of all two pairs. If not
|
143
|
+
# specified, the :conditions option is used if it is a hash or array of all two pairs.
|
130
144
|
# - :graph_join_type - The type of SQL join to use when eagerly loading the association via
|
131
145
|
# eager_graph. Defaults to :left_outer.
|
132
146
|
# - :graph_only_conditions - The conditions to use on the SQL join when eagerly loading
|
@@ -203,11 +217,16 @@ module Sequel::Model::Associations
|
|
203
217
|
raise(Error, 'Model.associate name argument must be a symbol') unless Symbol === name
|
204
218
|
|
205
219
|
# merge early so we don't modify opts
|
206
|
-
|
220
|
+
orig_opts = opts.dup
|
221
|
+
orig_opts = association_reflection(opts[:clone])[:orig_opts].merge(orig_opts) if opts[:clone]
|
222
|
+
opts = orig_opts.merge(:type => type, :name => name, :cache => true, :model => self)
|
223
|
+
opts[:block] = block if block
|
207
224
|
opts = assoc_class.new.merge!(opts)
|
208
225
|
opts[:eager_block] = block unless opts.include?(:eager_block)
|
209
226
|
opts[:graph_join_type] ||= :left_outer
|
210
227
|
opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
|
228
|
+
conds = opts[:conditions]
|
229
|
+
opts[:graph_conditions] = conds if !opts.include?(:graph_conditions) and (conds.is_a?(Hash) or (conds.is_a?(Array) and conds.all_two_pairs?))
|
211
230
|
opts[:graph_conditions] = opts[:graph_conditions] ? opts[:graph_conditions].to_a : []
|
212
231
|
opts[:graph_select] = Array(opts[:graph_select]) if opts[:graph_select]
|
213
232
|
[:before_add, :before_remove, :after_add, :after_remove, :after_load, :extend].each do |cb_type|
|
@@ -225,6 +244,9 @@ module Sequel::Model::Associations
|
|
225
244
|
|
226
245
|
send(:"def_#{type}", opts)
|
227
246
|
|
247
|
+
orig_opts.delete(:clone)
|
248
|
+
orig_opts.merge!(:class_name=>opts[:class_name], :class=>opts[:class], :block=>block)
|
249
|
+
opts[:orig_opts] = orig_opts
|
228
250
|
# don't add to association_reflections until we are sure there are no errors
|
229
251
|
association_reflections[name] = opts
|
230
252
|
end
|
@@ -386,21 +408,7 @@ module Sequel::Model::Associations
|
|
386
408
|
return if opts[:read_only]
|
387
409
|
|
388
410
|
association_module_private_def(opts._setter_method){|o| send(:"#{key}=", (o.send(opts.primary_key) if o))}
|
389
|
-
|
390
|
-
association_module_def(opts.setter_method) do |o|
|
391
|
-
raise(Sequel::Error, "model object #{model} does not have a primary key") if o && !o.pk
|
392
|
-
old_val = send(opts.association_method)
|
393
|
-
return o if old_val == o
|
394
|
-
return if old_val and run_association_callbacks(opts, :before_remove, old_val) == false
|
395
|
-
return if o and run_association_callbacks(opts, :before_add, o) == false
|
396
|
-
send(opts._setter_method, o)
|
397
|
-
associations[name] = o
|
398
|
-
remove_reciprocal_object(opts, old_val) if old_val
|
399
|
-
add_reciprocal_object(opts, o) if o
|
400
|
-
run_association_callbacks(opts, :after_add, o) if o
|
401
|
-
run_association_callbacks(opts, :after_remove, old_val) if old_val
|
402
|
-
o
|
403
|
-
end
|
411
|
+
association_module_def(opts.setter_method){|o| set_associated_object(opts, o)}
|
404
412
|
end
|
405
413
|
|
406
414
|
# Adds one_to_many association instance methods
|
data/lib/sequel_model/base.rb
CHANGED
@@ -2,16 +2,25 @@ module Sequel
|
|
2
2
|
class Model
|
3
3
|
@allowed_columns = nil
|
4
4
|
@association_reflections = {}
|
5
|
+
@cache_store = nil
|
6
|
+
@cache_ttl = nil
|
7
|
+
@db = nil
|
8
|
+
@db_schema = nil
|
5
9
|
@dataset_methods = {}
|
6
10
|
@hooks = {}
|
11
|
+
@overridable_methods_module = nil
|
7
12
|
@primary_key = :id
|
8
13
|
@raise_on_save_failure = true
|
9
14
|
@raise_on_typecast_failure = true
|
10
15
|
@restrict_primary_key = true
|
11
16
|
@restricted_columns = nil
|
17
|
+
@simple_pk = nil
|
18
|
+
@simple_table = nil
|
19
|
+
@skip_superclass_validations = nil
|
12
20
|
@sti_dataset = nil
|
13
21
|
@sti_key = nil
|
14
22
|
@strict_param_setting = true
|
23
|
+
@transform = nil
|
15
24
|
@typecast_empty_string_to_nil = true
|
16
25
|
@typecast_on_assignment = true
|
17
26
|
|
@@ -41,6 +50,14 @@ module Sequel
|
|
41
50
|
# (default: no columns).
|
42
51
|
metaattr_reader :restricted_columns
|
43
52
|
|
53
|
+
# Should be the literal primary key column name if this Model's table has a simple primary key, or
|
54
|
+
# nil if the model has a compound primary key or no primary key.
|
55
|
+
metaattr_reader :simple_pk
|
56
|
+
|
57
|
+
# Should be the literal table name if this Model's dataset is a simple table (no select, order, join, etc.),
|
58
|
+
# or nil otherwise.
|
59
|
+
metaattr_reader :simple_table
|
60
|
+
|
44
61
|
# The base dataset for STI, to which filters are added to get
|
45
62
|
# only the models for the specific STI subclass.
|
46
63
|
metaattr_reader :sti_dataset
|
@@ -68,15 +85,19 @@ module Sequel
|
|
68
85
|
left_outer_join limit map multi_insert naked order order_by order_more
|
69
86
|
paginate print query range reverse_order right_outer_join select
|
70
87
|
select_all select_more server set set_graph_aliases single_value size to_csv to_hash
|
71
|
-
transform union uniq unfiltered unordered update where'.map{|x| x.to_sym}
|
88
|
+
transform union uniq unfiltered unordered update where with_sql'.map{|x| x.to_sym}
|
72
89
|
|
73
90
|
# Instance variables that are inherited in subclasses
|
74
91
|
INHERITED_INSTANCE_VARIABLES = {:@allowed_columns=>:dup, :@cache_store=>nil,
|
75
92
|
:@cache_ttl=>nil, :@dataset_methods=>:dup, :@primary_key=>nil,
|
76
93
|
:@raise_on_save_failure=>nil, :@restricted_columns=>:dup, :@restrict_primary_key=>nil,
|
94
|
+
:@simple_pk=>nil, :@simple_table=>nil,
|
77
95
|
:@sti_dataset=>nil, :@sti_key=>nil, :@strict_param_setting=>nil,
|
78
96
|
:@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
|
79
97
|
:@raise_on_typecast_failure=>nil, :@association_reflections=>:dup}
|
98
|
+
|
99
|
+
# Empty instance variables, for -w compliance
|
100
|
+
EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@transform, :@db, :@skip_superclass_validations]
|
80
101
|
|
81
102
|
# Returns the first record from the database matching the conditions.
|
82
103
|
# If a hash is given, it is used as the conditions. If another
|
@@ -85,11 +106,12 @@ module Sequel
|
|
85
106
|
# first before a dataset lookup is attempted unless a hash is supplied.
|
86
107
|
def self.[](*args)
|
87
108
|
args = args.first if (args.size == 1)
|
88
|
-
|
89
|
-
|
90
|
-
|
109
|
+
return dataset[args] if args.is_a?(Hash)
|
110
|
+
return cache_lookup(args) if @cache_store
|
111
|
+
if t = simple_table and p = simple_pk
|
112
|
+
with_sql("SELECT * FROM #{t} WHERE #{p} = #{dataset.literal(args)} LIMIT 1").first
|
91
113
|
else
|
92
|
-
|
114
|
+
dataset[primary_key_hash(args)]
|
93
115
|
end
|
94
116
|
end
|
95
117
|
|
@@ -174,6 +196,7 @@ module Sequel
|
|
174
196
|
# Modify and return eager loading dataset based on association options
|
175
197
|
def self.eager_loading_dataset(opts, ds, select, associations)
|
176
198
|
ds = ds.select(*select) if select
|
199
|
+
ds = ds.filter(opts[:conditions]) if opts[:conditions]
|
177
200
|
ds = ds.order(*opts[:order]) if opts[:order]
|
178
201
|
ds = ds.eager(opts[:eager]) if opts[:eager]
|
179
202
|
ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph]
|
@@ -201,6 +224,7 @@ module Sequel
|
|
201
224
|
def self.inherited(subclass)
|
202
225
|
sup_class = subclass.superclass
|
203
226
|
ivs = subclass.instance_variables.collect{|x| x.to_s}
|
227
|
+
EMPTY_INSTANCE_VARIABLES.each{|iv| subclass.instance_variable_set(iv, nil) unless ivs.include?(iv.to_s)}
|
204
228
|
INHERITED_INSTANCE_VARIABLES.each do |iv, dup|
|
205
229
|
next if ivs.include?(iv.to_s)
|
206
230
|
sup_class_value = sup_class.instance_variable_get(iv)
|
@@ -211,7 +235,7 @@ module Sequel
|
|
211
235
|
db
|
212
236
|
begin
|
213
237
|
if sup_class == Model
|
214
|
-
subclass.set_dataset(
|
238
|
+
subclass.set_dataset(subclass.implicit_table_name) unless subclass.name.blank?
|
215
239
|
elsif ds = sup_class.instance_variable_get(:@dataset)
|
216
240
|
subclass.set_dataset(sup_class.sti_key ? sup_class.sti_dataset.filter(sup_class.sti_key=>subclass.name.to_s) : ds.clone, :inherited=>true)
|
217
241
|
end
|
@@ -239,7 +263,7 @@ module Sequel
|
|
239
263
|
# Mark the model as not having a primary key. Not having a primary key
|
240
264
|
# can cause issues, among which is that you won't be able to update records.
|
241
265
|
def self.no_primary_key
|
242
|
-
@primary_key = nil
|
266
|
+
@simple_pk = @primary_key = nil
|
243
267
|
end
|
244
268
|
|
245
269
|
# Returns primary key attribute hash. If using a composite primary key
|
@@ -317,8 +341,10 @@ module Sequel
|
|
317
341
|
inherited = opts[:inherited]
|
318
342
|
@dataset = case ds
|
319
343
|
when Symbol
|
344
|
+
@simple_table = db.literal(ds)
|
320
345
|
db[ds]
|
321
346
|
when Dataset
|
347
|
+
@simple_table = nil
|
322
348
|
@db = ds.db
|
323
349
|
ds
|
324
350
|
else
|
@@ -327,6 +353,7 @@ module Sequel
|
|
327
353
|
@dataset.set_model(self)
|
328
354
|
@dataset.transform(@transform) if @transform
|
329
355
|
if inherited
|
356
|
+
@simple_table = sti_key ? nil : superclass.simple_table
|
330
357
|
@columns = @dataset.columns rescue nil
|
331
358
|
else
|
332
359
|
@dataset.extend(DatasetMethods)
|
@@ -354,6 +381,7 @@ module Sequel
|
|
354
381
|
# You can set it to nil to not have a primary key, but that
|
355
382
|
# cause certain things not to work, see #no_primary_key.
|
356
383
|
def self.set_primary_key(*key)
|
384
|
+
@simple_pk = key.length == 1 ? db.literal(key.first) : nil
|
357
385
|
@primary_key = (key.length == 1) ? key[0] : key.flatten
|
358
386
|
end
|
359
387
|
|
data/lib/sequel_model/caching.rb
CHANGED
@@ -17,7 +17,7 @@ module Sequel
|
|
17
17
|
def self.set_cache(store, opts = {})
|
18
18
|
@cache_store = store
|
19
19
|
@cache_ttl = opts[:ttl] || 3600
|
20
|
-
|
20
|
+
before_update :cache_delete
|
21
21
|
before_update_values :cache_delete
|
22
22
|
before_delete :cache_delete
|
23
23
|
end
|
@@ -78,10 +78,5 @@ module Sequel
|
|
78
78
|
def cache_delete
|
79
79
|
model.send(:cache_delete, cache_key)
|
80
80
|
end
|
81
|
-
|
82
|
-
# Delete this object from the cache unless it is a new record
|
83
|
-
def cache_delete_unless_new
|
84
|
-
cache_delete unless new?
|
85
|
-
end
|
86
81
|
end
|
87
82
|
end
|
data/lib/sequel_model/record.rb
CHANGED
@@ -345,8 +345,12 @@ module Sequel
|
|
345
345
|
def _dataset(opts)
|
346
346
|
raise(Sequel::Error, "model object #{model} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
347
347
|
ds = send(opts._dataset_method)
|
348
|
+
ds.extend(Associations::DatasetMethods)
|
349
|
+
ds.model_object = self
|
350
|
+
ds.association_reflection = opts
|
348
351
|
opts[:extend].each{|m| ds.extend(m)}
|
349
352
|
ds = ds.select(*opts.select) if opts.select
|
353
|
+
ds = ds.filter(opts[:conditions]) if opts[:conditions]
|
350
354
|
ds = ds.order(*opts[:order]) if opts[:order]
|
351
355
|
ds = ds.limit(*opts[:limit]) if opts[:limit]
|
352
356
|
ds = ds.eager(*opts[:eager]) if opts[:eager]
|
@@ -470,6 +474,24 @@ module Sequel
|
|
470
474
|
end
|
471
475
|
end
|
472
476
|
|
477
|
+
# Set the given object as the associated object for the given association
|
478
|
+
def set_associated_object(opts, o)
|
479
|
+
raise(Sequel::Error, "model object #{model} does not have a primary key") if o && !o.pk
|
480
|
+
old_val = send(opts.association_method)
|
481
|
+
return o if old_val == o
|
482
|
+
return if old_val and run_association_callbacks(opts, :before_remove, old_val) == false
|
483
|
+
return if o and run_association_callbacks(opts, :before_add, o) == false
|
484
|
+
send(opts._setter_method, o)
|
485
|
+
associations[opts[:name]] = o
|
486
|
+
remove_reciprocal_object(opts, old_val) if old_val
|
487
|
+
if o
|
488
|
+
add_reciprocal_object(opts, o)
|
489
|
+
run_association_callbacks(opts, :after_add, o)
|
490
|
+
end
|
491
|
+
run_association_callbacks(opts, :after_remove, old_val) if old_val
|
492
|
+
o
|
493
|
+
end
|
494
|
+
|
473
495
|
# Set the columns, filtered by the only and except arrays.
|
474
496
|
def set_restricted(hash, only, except)
|
475
497
|
columns_not_set = model.instance_variable_get(:@columns).blank?
|
@@ -527,11 +549,7 @@ module Sequel
|
|
527
549
|
begin
|
528
550
|
model.db.typecast_value(col_schema[:type], value)
|
529
551
|
rescue Error::InvalidValue
|
530
|
-
|
531
|
-
raise
|
532
|
-
else
|
533
|
-
value
|
534
|
-
end
|
552
|
+
raise_on_typecast_failure ? raise : value
|
535
553
|
end
|
536
554
|
end
|
537
555
|
|