sequel 4.3.0 → 4.4.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG +34 -0
- data/README.rdoc +7 -7
- data/Rakefile +2 -2
- data/doc/active_record.rdoc +2 -2
- data/doc/association_basics.rdoc +21 -7
- data/doc/bin_sequel.rdoc +2 -2
- data/doc/cheat_sheet.rdoc +2 -1
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/migration.rdoc +2 -2
- data/doc/object_model.rdoc +2 -2
- data/doc/opening_databases.rdoc +13 -1
- data/doc/querying.rdoc +9 -4
- data/doc/release_notes/4.4.0.txt +92 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +2 -2
- data/doc/sql.rdoc +3 -3
- data/doc/thread_safety.rdoc +1 -1
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/jdbc.rb +85 -19
- data/lib/sequel/adapters/jdbc/db2.rb +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +34 -3
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +57 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -2
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/oracle.rb +41 -4
- data/lib/sequel/adapters/shared/sqlanywhere.rb +458 -0
- data/lib/sequel/adapters/sqlanywhere.rb +177 -0
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +11 -3
- data/lib/sequel/core.rb +4 -4
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/dataset.rb +1 -1
- data/lib/sequel/dataset/actions.rb +2 -0
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/query.rb +37 -16
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +2 -2
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +5 -4
- data/lib/sequel/extensions/pg_array.rb +2 -2
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_hstore.rb +2 -2
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
- data/lib/sequel/extensions/pg_json.rb +2 -2
- data/lib/sequel/extensions/pg_json_ops.rb +2 -2
- data/lib/sequel/extensions/pg_range.rb +2 -2
- data/lib/sequel/extensions/pg_range_ops.rb +2 -2
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/pg_row_ops.rb +3 -3
- data/lib/sequel/model.rb +1 -1
- data/lib/sequel/model/associations.rb +106 -17
- data/lib/sequel/model/base.rb +23 -19
- data/lib/sequel/plugins/json_serializer.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +14 -6
- data/lib/sequel/plugins/pg_array_associations.rb +28 -0
- data/lib/sequel/plugins/rcte_tree.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +11 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/table_select.rb +41 -0
- data/lib/sequel/plugins/tree.rb +1 -1
- data/lib/sequel/sql.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/oracle_spec.rb +22 -1
- data/spec/adapters/postgres_spec.rb +31 -48
- data/spec/adapters/sqlanywhere_spec.rb +170 -0
- data/spec/core/dataset_spec.rb +109 -0
- data/spec/core/object_graph_spec.rb +7 -0
- data/spec/extensions/constraint_validations_spec.rb +7 -0
- data/spec/extensions/core_refinements_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +65 -0
- data/spec/extensions/pg_array_associations_spec.rb +44 -0
- data/spec/extensions/rcte_tree_spec.rb +3 -3
- data/spec/extensions/spec_helper.rb +1 -1
- data/spec/extensions/table_select_spec.rb +71 -0
- data/spec/integration/associations_test.rb +279 -7
- data/spec/integration/dataset_test.rb +13 -4
- data/spec/integration/schema_test.rb +12 -14
- data/spec/model/associations_spec.rb +472 -3
- data/spec/model/class_dataset_methods_spec.rb +1 -0
- data/spec/model/model_spec.rb +10 -0
- metadata +10 -2
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# The mssql_emulate_lateral_with_apply extension converts
|
|
2
2
|
# queries that use LATERAL into queries that use CROSS/OUTER
|
|
3
3
|
# APPLY, allowing code that works on databases that support
|
|
4
|
-
# LATERAL via Dataset#lateral to run on Microsoft SQL Server
|
|
4
|
+
# LATERAL via Dataset#lateral to run on Microsoft SQL Server
|
|
5
|
+
# and Sybase SQLAnywhere.
|
|
5
6
|
#
|
|
6
7
|
# This is available as a separate extension instead of
|
|
7
|
-
# integrated into the Microsoft SQL Server
|
|
8
|
-
# few people need it and there
|
|
9
|
-
# code that doesn't use it.
|
|
8
|
+
# integrated into the Microsoft SQL Server and Sybase
|
|
9
|
+
# SQLAnywhere support because few people need it and there
|
|
10
|
+
# is a performance hit to code that doesn't use it.
|
|
10
11
|
#
|
|
11
12
|
# It is possible there are cases where this emulation does
|
|
12
13
|
# not work. Users should probably verify that correct
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
#
|
|
18
18
|
# Sequel.pg_array(array)
|
|
19
19
|
#
|
|
20
|
-
# If you have loaded the {core_extensions extension}[
|
|
21
|
-
# or you have loaded the
|
|
20
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
21
|
+
# or you have loaded the core_refinements extension
|
|
22
22
|
# and have activated refinements for the file, you can also use Array#pg_array:
|
|
23
23
|
#
|
|
24
24
|
# array.pg_array
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
#
|
|
20
20
|
# ia = Sequel.expr(:int_array_column).pg_array
|
|
21
21
|
#
|
|
22
|
-
# If you have loaded the {core_extensions extension}[
|
|
23
|
-
# or you have loaded the
|
|
22
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
23
|
+
# or you have loaded the core_refinements extension
|
|
24
24
|
# and have activated refinements for the file, you can also use Symbol#pg_array:
|
|
25
25
|
#
|
|
26
26
|
# ia = :int_array_column.pg_array
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
#
|
|
20
20
|
# Sequel.hstore(hash)
|
|
21
21
|
#
|
|
22
|
-
# If you have loaded the {core_extensions extension}[
|
|
23
|
-
# or you have loaded the
|
|
22
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
23
|
+
# or you have loaded the core_refinements extension
|
|
24
24
|
# and have activated refinements for the file, you can also use Hash#hstore:
|
|
25
25
|
#
|
|
26
26
|
# hash.hstore
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
#
|
|
21
21
|
# h = Sequel.expr(:hstore_column).hstore
|
|
22
22
|
#
|
|
23
|
-
# If you have loaded the {core_extensions extension}[
|
|
24
|
-
# or you have loaded the
|
|
23
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
24
|
+
# or you have loaded the core_refinements extension
|
|
25
25
|
# and have activated refinements for the file, you can also use Symbol#hstore:
|
|
26
26
|
#
|
|
27
27
|
# h = :hstore_column.hstore
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
# Sequel.pg_json(array)
|
|
24
24
|
# Sequel.pg_json(hash)
|
|
25
25
|
#
|
|
26
|
-
# If you have loaded the {core_extensions extension}[
|
|
27
|
-
# or you have loaded the
|
|
26
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
27
|
+
# or you have loaded the core_refinements extension
|
|
28
28
|
# and have activated refinements for the file, you can also use Array#pg_json and Hash#pg_json:
|
|
29
29
|
#
|
|
30
30
|
# array.pg_json
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
#
|
|
21
21
|
# j = Sequel.expr(:json_column).pg_json
|
|
22
22
|
#
|
|
23
|
-
# If you have loaded the {core_extensions extension}[
|
|
24
|
-
# or you have loaded the
|
|
23
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
24
|
+
# or you have loaded the core_refinements extension
|
|
25
25
|
# and have activated refinements for the file, you can also use Symbol#pg_json:
|
|
26
26
|
#
|
|
27
27
|
# j = :json_column.pg_json
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
#
|
|
25
25
|
# Sequel.pg_range(range)
|
|
26
26
|
#
|
|
27
|
-
# If you have loaded the {core_extensions extension}[
|
|
28
|
-
# or you have loaded the
|
|
27
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
28
|
+
# or you have loaded the core_refinements extension
|
|
29
29
|
# and have activated refinements for the file, you can also use Range#pg_range:
|
|
30
30
|
#
|
|
31
31
|
# range.pg_range
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
#
|
|
20
20
|
# r = Sequel.expr(:range).pg_range
|
|
21
21
|
#
|
|
22
|
-
# If you have loaded the {core_extensions extension}[
|
|
23
|
-
# or you have loaded the
|
|
22
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
23
|
+
# or you have loaded the core_refinements extension
|
|
24
24
|
# and have activated refinements for the file, you can also use Symbol#pg_range:
|
|
25
25
|
#
|
|
26
26
|
# r = :range.pg_range
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
#
|
|
28
28
|
# Sequel.pg_row(array)
|
|
29
29
|
#
|
|
30
|
-
# If you have loaded the {core_extensions extension}[
|
|
31
|
-
# or you have loaded the
|
|
30
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
31
|
+
# or you have loaded the core_refinements extension
|
|
32
32
|
# and have activated refinements for the file, you can also use Array#pg_row:
|
|
33
33
|
#
|
|
34
34
|
# array.pg_row
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
#
|
|
20
20
|
# r = Sequel.expr(:row_column).pg_row
|
|
21
21
|
#
|
|
22
|
-
# If you have loaded the {core_extensions extension}[
|
|
23
|
-
# or you have loaded the
|
|
22
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
23
|
+
# or you have loaded the core_refinements extension
|
|
24
24
|
# and have activated refinements for the file, you can also use Symbol#pg_row:
|
|
25
25
|
#
|
|
26
26
|
# r = :row_column.pg_row
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
#
|
|
71
71
|
# DB[:a].select(a.splat).first # SELECT (a.*)::a FROM a
|
|
72
72
|
# # => {:a=>"(1,2)"} # or {:a=>{:a=>1, :b=>2}} if the "a" type has been registered
|
|
73
|
-
# # with the
|
|
73
|
+
# # with the pg_row extension
|
|
74
74
|
#
|
|
75
75
|
# This feature is mostly useful for a different way to graph tables:
|
|
76
76
|
#
|
data/lib/sequel/model.rb
CHANGED
|
@@ -104,7 +104,7 @@ module Sequel
|
|
|
104
104
|
# Empty instance methods to create that the user can override to get hook/callback behavior.
|
|
105
105
|
# Just like any other method defined by Sequel, if you override one of these, you should
|
|
106
106
|
# call +super+ to get the default behavior (while empty by default, they can also be defined
|
|
107
|
-
# by plugins). See the {"Model Hooks" guide}[
|
|
107
|
+
# by plugins). See the {"Model Hooks" guide}[rdoc-ref:doc/model_hooks.rdoc] for
|
|
108
108
|
# more detail on hooks.
|
|
109
109
|
HOOKS = BEFORE_HOOKS + AFTER_HOOKS
|
|
110
110
|
|
|
@@ -137,6 +137,21 @@ module Sequel
|
|
|
137
137
|
true
|
|
138
138
|
end
|
|
139
139
|
|
|
140
|
+
# Whether additional conditions should be added when using the filter
|
|
141
|
+
# by associations support.
|
|
142
|
+
def filter_by_associations_add_conditions?
|
|
143
|
+
self[:conditions] || self[:eager_block]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# The expression to use for the additional conditions to be added for
|
|
147
|
+
# the filter by association support, when the association itself is
|
|
148
|
+
# filtered. Works by using a subquery to test that the objects passed
|
|
149
|
+
# also meet the association filter criteria.
|
|
150
|
+
def filter_by_associations_conditions_expression(obj)
|
|
151
|
+
ds = filter_by_associations_conditions_dataset.where(filter_by_associations_conditions_subquery_conditions(obj))
|
|
152
|
+
{filter_by_associations_conditions_key=>ds}
|
|
153
|
+
end
|
|
154
|
+
|
|
140
155
|
# The limit and offset for this association (returned as a two element array).
|
|
141
156
|
def limit_and_offset
|
|
142
157
|
if (v = self[:limit]).is_a?(Array)
|
|
@@ -298,6 +313,35 @@ module Sequel
|
|
|
298
313
|
end
|
|
299
314
|
end
|
|
300
315
|
|
|
316
|
+
# The conditions to add to the filter by associations conditions
|
|
317
|
+
# subquery to restrict it to to the object(s) that was used as the
|
|
318
|
+
# filter value.
|
|
319
|
+
def filter_by_associations_conditions_subquery_conditions(obj)
|
|
320
|
+
key = qualify(associated_class.table_name, associated_class.primary_key)
|
|
321
|
+
case obj
|
|
322
|
+
when Array
|
|
323
|
+
{key=>obj.map{|o| o.pk}}
|
|
324
|
+
when Sequel::Dataset
|
|
325
|
+
{key=>obj.select(*Array(qualify(associated_class.table_name, associated_class.primary_key)))}
|
|
326
|
+
else
|
|
327
|
+
Array(key).zip(Array(obj.pk))
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# The base dataset to use for the filter by associations conditions
|
|
332
|
+
# subquery, regardless of the objects that are passed in as filter
|
|
333
|
+
# values.
|
|
334
|
+
def filter_by_associations_conditions_dataset
|
|
335
|
+
cached_fetch(:filter_by_associations_conditions_dataset) do
|
|
336
|
+
ds = associated_dataset.unordered.unlimited
|
|
337
|
+
ds = filter_by_associations_add_conditions_dataset_filter(ds)
|
|
338
|
+
ds = self[:eager_block].call(ds) if self[:eager_block]
|
|
339
|
+
ds
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# Whether the given association reflection is possible reciprocal
|
|
344
|
+
# association for the current association reflection.
|
|
301
345
|
def reciprocal_association?(assoc_reflect)
|
|
302
346
|
Array(reciprocal_type).include?(assoc_reflect[:type]) &&
|
|
303
347
|
assoc_reflect.associated_class == self[:model] &&
|
|
@@ -395,6 +439,15 @@ module Sequel
|
|
|
395
439
|
|
|
396
440
|
private
|
|
397
441
|
|
|
442
|
+
def filter_by_associations_add_conditions_dataset_filter(ds)
|
|
443
|
+
pk = qualify(associated_class.table_name, primary_keys)
|
|
444
|
+
ds.select(*pk).where(Sequel.negate(pk.zip([])))
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def filter_by_associations_conditions_key
|
|
448
|
+
qualify(self[:model].table_name, self[:key_column])
|
|
449
|
+
end
|
|
450
|
+
|
|
398
451
|
def reciprocal_association?(assoc_reflect)
|
|
399
452
|
super && self[:keys] == assoc_reflect[:keys] && primary_key == assoc_reflect.primary_key
|
|
400
453
|
end
|
|
@@ -465,6 +518,15 @@ module Sequel
|
|
|
465
518
|
|
|
466
519
|
private
|
|
467
520
|
|
|
521
|
+
def filter_by_associations_add_conditions_dataset_filter(ds)
|
|
522
|
+
k = qualify(associated_class.table_name, self[:keys])
|
|
523
|
+
ds.select(*k).where(Sequel.negate(k.zip([])))
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
def filter_by_associations_conditions_key
|
|
527
|
+
qualify(self[:model].table_name, self[:primary_key_column])
|
|
528
|
+
end
|
|
529
|
+
|
|
468
530
|
def reciprocal_association?(assoc_reflect)
|
|
469
531
|
super && self[:keys] == assoc_reflect[:keys] && primary_key == assoc_reflect.primary_key
|
|
470
532
|
end
|
|
@@ -636,6 +698,15 @@ module Sequel
|
|
|
636
698
|
|
|
637
699
|
private
|
|
638
700
|
|
|
701
|
+
def filter_by_associations_add_conditions_dataset_filter(ds)
|
|
702
|
+
ds.select(*qualify(join_table_alias, self[:left_keys])).
|
|
703
|
+
inner_join(self[:join_table], Array(self[:right_keys]).zip(right_primary_keys), :qualify=>:deep)
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
def filter_by_associations_conditions_key
|
|
707
|
+
qualify(self[:model].table_name, self[:left_primary_key_column])
|
|
708
|
+
end
|
|
709
|
+
|
|
639
710
|
def reciprocal_association?(assoc_reflect)
|
|
640
711
|
super && assoc_reflect[:left_keys] == self[:right_keys] &&
|
|
641
712
|
assoc_reflect[:right_keys] == self[:left_keys] &&
|
|
@@ -710,8 +781,8 @@ module Sequel
|
|
|
710
781
|
# as a column, you will probably end up with an association that doesn't work, or a SystemStackError.
|
|
711
782
|
#
|
|
712
783
|
# For a more in depth general overview, as well as a reference guide,
|
|
713
|
-
# see the {Association Basics guide}[
|
|
714
|
-
# For examples of advanced usage, see the {Advanced Associations guide}[
|
|
784
|
+
# see the {Association Basics guide}[rdoc-ref:doc/association_basics.rdoc].
|
|
785
|
+
# For examples of advanced usage, see the {Advanced Associations guide}[rdoc-ref:doc/advanced_associations.rdoc].
|
|
715
786
|
module ClassMethods
|
|
716
787
|
# All association reflections defined for this model (default: {}).
|
|
717
788
|
attr_reader :association_reflections
|
|
@@ -879,7 +950,7 @@ module Sequel
|
|
|
879
950
|
# array of symbols for a composite key association.
|
|
880
951
|
# :key_column :: Similar to, and usually identical to, :key, but :key refers to the model method
|
|
881
952
|
# to call, where :key_column refers to the underlying column. Should only be
|
|
882
|
-
# used if the
|
|
953
|
+
# used if the model method differs from the foreign key column, in conjunction
|
|
883
954
|
# with defining a model alias method for the key column.
|
|
884
955
|
# :primary_key :: column in the associated table that :key option references, as a symbol.
|
|
885
956
|
# Defaults to the primary key of the associated table. Can use an
|
|
@@ -902,7 +973,7 @@ module Sequel
|
|
|
902
973
|
# array of symbols for a composite key association.
|
|
903
974
|
# :primary_key_column :: Similar to, and usually identical to, :primary_key, but :primary_key refers
|
|
904
975
|
# to the model method call, where :primary_key_column refers to the underlying column.
|
|
905
|
-
# Should only be used if the
|
|
976
|
+
# Should only be used if the model method differs from the primary key column, in
|
|
906
977
|
# conjunction with defining a model alias method for the primary key column.
|
|
907
978
|
# === :many_to_many
|
|
908
979
|
# :graph_join_table_block :: The block to pass to +join_table+ for
|
|
@@ -958,7 +1029,7 @@ module Sequel
|
|
|
958
1029
|
opts = orig_opts.merge(:type => type, :name => name, :cache=>{}, :model => self)
|
|
959
1030
|
opts[:block] = block if block
|
|
960
1031
|
opts = assoc_class.new.merge!(opts)
|
|
961
|
-
opts[:eager_block] = block unless opts.include?(:eager_block)
|
|
1032
|
+
opts[:eager_block] = opts[:block] unless opts.include?(:eager_block)
|
|
962
1033
|
if !opts.has_key?(:predicate_key) && opts.has_key?(:eager_loading_predicate_key)
|
|
963
1034
|
opts[:predicate_key] = opts[:eager_loading_predicate_key]
|
|
964
1035
|
end
|
|
@@ -980,7 +1051,7 @@ module Sequel
|
|
|
980
1051
|
send(:"def_#{type}", opts)
|
|
981
1052
|
|
|
982
1053
|
orig_opts.delete(:clone)
|
|
983
|
-
orig_opts.merge!(:class_name=>opts[:class_name], :class=>opts[:class], :block=>block)
|
|
1054
|
+
orig_opts.merge!(:class_name=>opts[:class_name], :class=>opts[:class], :block=>opts[:block])
|
|
984
1055
|
opts[:orig_opts] = orig_opts
|
|
985
1056
|
# don't add to association_reflections until we are sure there are no errors
|
|
986
1057
|
association_reflections[name] = opts
|
|
@@ -1516,7 +1587,7 @@ module Sequel
|
|
|
1516
1587
|
elsif !o.is_a?(klass)
|
|
1517
1588
|
raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}")
|
|
1518
1589
|
end
|
|
1519
|
-
raise(Sequel::Error, "model object #{inspect} does not have a primary key")
|
|
1590
|
+
raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
|
1520
1591
|
ensure_associated_primary_key(opts, o, *args)
|
|
1521
1592
|
return if run_association_callbacks(opts, :before_add, o) == false
|
|
1522
1593
|
send(opts._add_method, o, *args)
|
|
@@ -1608,7 +1679,7 @@ module Sequel
|
|
|
1608
1679
|
|
|
1609
1680
|
# Remove all associated objects from the given association
|
|
1610
1681
|
def remove_all_associated_objects(opts, *args)
|
|
1611
|
-
raise(Sequel::Error, "model object #{inspect} does not have a primary key")
|
|
1682
|
+
raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
|
1612
1683
|
send(opts._remove_all_method, *args)
|
|
1613
1684
|
ret = associations[opts[:name]].each{|o| remove_reciprocal_object(opts, o)} if associations.include?(opts[:name])
|
|
1614
1685
|
associations[opts[:name]] = []
|
|
@@ -1625,7 +1696,7 @@ module Sequel
|
|
|
1625
1696
|
elsif opts.remove_should_check_existing? && send(opts.dataset_method).where(o.pk_hash).empty?
|
|
1626
1697
|
raise(Sequel::Error, "associated object #{o.inspect} is not currently associated to #{inspect}")
|
|
1627
1698
|
end
|
|
1628
|
-
raise(Sequel::Error, "model object #{inspect} does not have a primary key")
|
|
1699
|
+
raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
|
1629
1700
|
raise(Sequel::Error, "associated object #{o.inspect} does not have a primary key") if opts.need_associated_primary_key? && !o.pk
|
|
1630
1701
|
return if run_association_callbacks(opts, :before_remove, o) == false
|
|
1631
1702
|
send(opts._remove_method, o, *args)
|
|
@@ -1978,7 +2049,18 @@ module Sequel
|
|
|
1978
2049
|
end
|
|
1979
2050
|
|
|
1980
2051
|
private
|
|
1981
|
-
|
|
2052
|
+
|
|
2053
|
+
# If the association has conditions itself, then it requires additional filters be
|
|
2054
|
+
# added to the current dataset to ensure that the passed in object would also be
|
|
2055
|
+
# included by the association's conditions.
|
|
2056
|
+
def add_association_filter_conditions(ref, obj, expr)
|
|
2057
|
+
if expr != SQL::Constants::FALSE && ref.filter_by_associations_add_conditions?
|
|
2058
|
+
Sequel.&(expr, ref.filter_by_associations_conditions_expression(obj))
|
|
2059
|
+
else
|
|
2060
|
+
expr
|
|
2061
|
+
end
|
|
2062
|
+
end
|
|
2063
|
+
|
|
1982
2064
|
# Return an expression for filtering by the given association reflection and associated object.
|
|
1983
2065
|
def association_filter_expression(op, ref, obj)
|
|
1984
2066
|
meth = :"#{ref[:type]}_association_filter_expression"
|
|
@@ -2105,12 +2187,13 @@ module Sequel
|
|
|
2105
2187
|
ref.right_primary_key_methods
|
|
2106
2188
|
end
|
|
2107
2189
|
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
association_filter_handle_inversion(op, SQL::BooleanExpression.from_value_pairs(lpks=>model.db.from(ref[:join_table]).select(*ref.qualify(jt, lks)).where(exp).exclude(SQL::BooleanExpression.from_value_pairs(ref.qualify(jt, lks).zip([]), :OR))), Array(lpks))
|
|
2190
|
+
expr = association_filter_key_expression(ref.qualify(jt, rks), meths, obj)
|
|
2191
|
+
unless expr == SQL::Constants::FALSE
|
|
2192
|
+
expr = SQL::BooleanExpression.from_value_pairs(lpks=>model.db.from(ref[:join_table]).select(*ref.qualify(jt, lks)).where(expr).exclude(SQL::BooleanExpression.from_value_pairs(ref.qualify(jt, lks).zip([]), :OR)))
|
|
2193
|
+
expr = add_association_filter_conditions(ref, obj, expr)
|
|
2113
2194
|
end
|
|
2195
|
+
|
|
2196
|
+
association_filter_handle_inversion(op, expr, Array(lpks))
|
|
2114
2197
|
end
|
|
2115
2198
|
|
|
2116
2199
|
# Return a simple equality expression for filering by a many_to_one association
|
|
@@ -2121,7 +2204,10 @@ module Sequel
|
|
|
2121
2204
|
else
|
|
2122
2205
|
ref.primary_key_methods
|
|
2123
2206
|
end
|
|
2124
|
-
|
|
2207
|
+
|
|
2208
|
+
expr = association_filter_key_expression(keys, meths, obj)
|
|
2209
|
+
expr = add_association_filter_conditions(ref, obj, expr)
|
|
2210
|
+
association_filter_handle_inversion(op, expr, keys)
|
|
2125
2211
|
end
|
|
2126
2212
|
|
|
2127
2213
|
# Return a simple equality expression for filering by a one_to_* association
|
|
@@ -2132,7 +2218,10 @@ module Sequel
|
|
|
2132
2218
|
else
|
|
2133
2219
|
ref[:key_methods]
|
|
2134
2220
|
end
|
|
2135
|
-
|
|
2221
|
+
|
|
2222
|
+
expr = association_filter_key_expression(keys, meths, obj)
|
|
2223
|
+
expr = add_association_filter_conditions(ref, obj, expr)
|
|
2224
|
+
association_filter_handle_inversion(op, expr, keys)
|
|
2136
2225
|
end
|
|
2137
2226
|
alias one_to_one_association_filter_expression one_to_many_association_filter_expression
|
|
2138
2227
|
|
data/lib/sequel/model/base.rb
CHANGED
|
@@ -512,22 +512,7 @@ module Sequel
|
|
|
512
512
|
# sharding support.
|
|
513
513
|
def set_dataset(ds, opts=OPTS)
|
|
514
514
|
inherited = opts[:inherited]
|
|
515
|
-
|
|
516
|
-
when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, LiteralString
|
|
517
|
-
self.simple_table = db.literal(ds)
|
|
518
|
-
ds = db.from(ds)
|
|
519
|
-
when Dataset
|
|
520
|
-
self.simple_table = if ds.send(:simple_select_all?)
|
|
521
|
-
ds.literal(ds.first_source_table)
|
|
522
|
-
else
|
|
523
|
-
nil
|
|
524
|
-
end
|
|
525
|
-
@db = ds.db
|
|
526
|
-
else
|
|
527
|
-
raise(Error, "Model.set_dataset takes one of the following classes as an argument: Symbol, LiteralString, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, Dataset")
|
|
528
|
-
end
|
|
529
|
-
set_dataset_row_proc(ds)
|
|
530
|
-
@dataset = ds
|
|
515
|
+
@dataset = convert_input_dataset(ds)
|
|
531
516
|
@require_modification = Sequel::Model.require_modification.nil? ? @dataset.provides_accurate_rows_matched? : Sequel::Model.require_modification
|
|
532
517
|
if inherited
|
|
533
518
|
self.simple_table = superclass.simple_table
|
|
@@ -644,6 +629,25 @@ module Sequel
|
|
|
644
629
|
end
|
|
645
630
|
end
|
|
646
631
|
|
|
632
|
+
# Convert the given object to a Dataset that should be used as
|
|
633
|
+
# this model's dataset.
|
|
634
|
+
def convert_input_dataset(ds)
|
|
635
|
+
case ds
|
|
636
|
+
when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, LiteralString
|
|
637
|
+
self.simple_table = db.literal(ds)
|
|
638
|
+
ds = db.from(ds)
|
|
639
|
+
when Dataset
|
|
640
|
+
self.simple_table = if ds.send(:simple_select_all?)
|
|
641
|
+
ds.literal(ds.first_source_table)
|
|
642
|
+
end
|
|
643
|
+
@db = ds.db
|
|
644
|
+
else
|
|
645
|
+
raise(Error, "Model.set_dataset takes one of the following classes as an argument: Symbol, LiteralString, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, Dataset")
|
|
646
|
+
end
|
|
647
|
+
set_dataset_row_proc(ds)
|
|
648
|
+
ds
|
|
649
|
+
end
|
|
650
|
+
|
|
647
651
|
# Add the module to the class's dataset_method_modules. Extend the dataset with the
|
|
648
652
|
# module if the model has a dataset. Add dataset methods to the class for all
|
|
649
653
|
# public dataset methods.
|
|
@@ -703,7 +707,7 @@ module Sequel
|
|
|
703
707
|
schema_array = check_non_connection_error{db.schema(dataset, :reload=>reload)} if db.supports_schema_parsing?
|
|
704
708
|
if schema_array
|
|
705
709
|
schema_array.each{|k,v| schema_hash[k] = v}
|
|
706
|
-
if ds_opts.
|
|
710
|
+
if (select = ds_opts[:select]) && !(select.length == 1 && select.first.is_a?(SQL::ColumnAll))
|
|
707
711
|
# We don't remove the columns from the schema_hash,
|
|
708
712
|
# as it's possible they will be used for typecasting
|
|
709
713
|
# even if they are not selected.
|
|
@@ -1022,7 +1026,7 @@ module Sequel
|
|
|
1022
1026
|
|
|
1023
1027
|
# Like delete but runs hooks before and after delete.
|
|
1024
1028
|
# If before_destroy returns false, returns false without
|
|
1025
|
-
# deleting the object
|
|
1029
|
+
# deleting the object from the database. Otherwise, deletes
|
|
1026
1030
|
# the item from the database and returns self. Uses a transaction
|
|
1027
1031
|
# if use_transactions is true or if the :transaction option is given and
|
|
1028
1032
|
# true.
|
|
@@ -1473,7 +1477,7 @@ module Sequel
|
|
|
1473
1477
|
|
|
1474
1478
|
# Validates the object. If the object is invalid, errors should be added
|
|
1475
1479
|
# to the errors attribute. By default, does nothing, as all models
|
|
1476
|
-
# are valid by default. See the {"Model Validations" guide}[
|
|
1480
|
+
# are valid by default. See the {"Model Validations" guide}[rdoc-ref:doc/validations.rdoc].
|
|
1477
1481
|
# for details about validation. Should not be called directly by
|
|
1478
1482
|
# user code, call <tt>valid?</tt> instead to check if an object
|
|
1479
1483
|
# is valid.
|