sequel 3.33.0 → 3.34.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.
- data/CHANGELOG +140 -0
- data/Rakefile +7 -0
- data/bin/sequel +22 -2
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/mass_assignment.rdoc +3 -1
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +23 -3
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/schema_modification.rdoc +18 -2
- data/doc/virtual_rows.rdoc +49 -0
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/ibmdb.rb +9 -4
- data/lib/sequel/adapters/jdbc.rb +9 -4
- data/lib/sequel/adapters/jdbc/h2.rb +8 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
- data/lib/sequel/adapters/mock.rb +24 -3
- data/lib/sequel/adapters/mysql.rb +29 -50
- data/lib/sequel/adapters/mysql2.rb +13 -28
- data/lib/sequel/adapters/oracle.rb +8 -2
- data/lib/sequel/adapters/postgres.rb +115 -20
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +14 -3
- data/lib/sequel/adapters/shared/mysql.rb +59 -11
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +127 -30
- data/lib/sequel/adapters/shared/sqlite.rb +55 -38
- data/lib/sequel/adapters/sqlite.rb +9 -3
- data/lib/sequel/adapters/swift.rb +2 -2
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +10 -0
- data/lib/sequel/ast_transformer.rb +4 -0
- data/lib/sequel/connection_pool.rb +8 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +14 -0
- data/lib/sequel/core.rb +24 -3
- data/lib/sequel/database/connecting.rb +24 -14
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +16 -25
- data/lib/sequel/database/query.rb +20 -2
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +120 -23
- data/lib/sequel/dataset/actions.rb +91 -18
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -2
- data/lib/sequel/dataset/sql.rb +68 -51
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +227 -31
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +11 -2
- data/lib/sequel/model/associations.rb +35 -7
- data/lib/sequel/model/base.rb +159 -36
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +11 -3
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +4 -3
- data/lib/sequel/plugins/prepared_statements.rb +3 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +417 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +12 -15
- data/spec/adapters/mysql_spec.rb +81 -23
- data/spec/adapters/postgres_spec.rb +444 -77
- data/spec/adapters/spec_helper.rb +2 -0
- data/spec/adapters/sqlite_spec.rb +8 -8
- data/spec/core/connection_pool_spec.rb +85 -0
- data/spec/core/database_spec.rb +29 -5
- data/spec/core/dataset_spec.rb +171 -3
- data/spec/core/expression_filters_spec.rb +364 -0
- data/spec/core/mock_adapter_spec.rb +17 -3
- data/spec/core/schema_spec.rb +133 -0
- data/spec/extensions/association_dependencies_spec.rb +13 -13
- data/spec/extensions/caching_spec.rb +26 -3
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +5 -2
- data/spec/extensions/identity_map_spec.rb +17 -0
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/lazy_attributes_spec.rb +2 -2
- data/spec/extensions/list_spec.rb +4 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +6 -2
- data/spec/extensions/nested_attributes_spec.rb +20 -0
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +2 -2
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_spec.rb +4 -0
- data/spec/extensions/pretty_table_spec.rb +6 -0
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +231 -11
- data/spec/extensions/schema_spec.rb +14 -2
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/sharding_spec.rb +6 -6
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +2 -1
- data/spec/extensions/sql_expr_spec.rb +28 -19
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +9 -1
- data/spec/integration/associations_test.rb +6 -6
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +89 -26
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +85 -22
- data/spec/integration/prepared_statement_test.rb +28 -8
- data/spec/integration/schema_test.rb +78 -7
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +4 -6
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +94 -8
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/hooks_spec.rb +2 -2
- data/spec/model/model_spec.rb +19 -7
- data/spec/model/record_spec.rb +135 -58
- data/spec/model/spec_helper.rb +1 -0
- metadata +35 -7
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# The select_remove extension adds Sequel::Dataset#select_remove for removing existing selected
|
|
2
|
+
# columns from a dataset. It's not part of Sequel core as it is rarely needed and has
|
|
3
|
+
# some corner cases where it can't work correctly.
|
|
4
|
+
|
|
5
|
+
module Sequel
|
|
6
|
+
class Dataset
|
|
7
|
+
# Remove columns from the list of selected columns. If any of the currently selected
|
|
8
|
+
# columns use expressions/aliases, this will remove selected columns with the given
|
|
9
|
+
# aliases. It will also remove entries from the selection that match exactly:
|
|
10
|
+
#
|
|
11
|
+
# # Assume columns a, b, and c in items table
|
|
12
|
+
# DB[:items] # SELECT * FROM items
|
|
13
|
+
# DB[:items].select_remove(:c) # SELECT a, b FROM items
|
|
14
|
+
# DB[:items].select(:a, :b___c, :c___b).select_remove(:c) # SELECT a, c AS b FROM items
|
|
15
|
+
# DB[:items].select(:a, :b___c, :c___b).select_remove(:c___b) # SELECT a, b AS c FROM items
|
|
16
|
+
#
|
|
17
|
+
# Note that there are a few cases where this method may not work correctly:
|
|
18
|
+
#
|
|
19
|
+
# * This dataset joins multiple tables and does not have an existing explicit selection.
|
|
20
|
+
# In this case, the code will currently use unqualified column names for all columns
|
|
21
|
+
# the dataset returns, except for the columns given.
|
|
22
|
+
# * This dataset has an existing explicit selection containing an item that returns
|
|
23
|
+
# multiple database columns (e.g. :table.*, 'column1, column2'.lit). In this case,
|
|
24
|
+
# the behavior is undefined and this method should not be used.
|
|
25
|
+
#
|
|
26
|
+
# There may be other cases where this method does not work correctly, use it with caution.
|
|
27
|
+
def select_remove(*cols)
|
|
28
|
+
if (sel = @opts[:select]) && !sel.empty?
|
|
29
|
+
select(*(columns.zip(sel).reject{|c, s| cols.include?(c)}.map{|c, s| s} - cols))
|
|
30
|
+
else
|
|
31
|
+
select(*(columns - cols))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The sql_expr extension adds the sql_expr method to every object, which
|
|
2
|
-
# returns an object that works nicely with Sequel's DSL
|
|
3
|
-
#
|
|
2
|
+
# returns an wrapped object that works nicely with Sequel's DSL by calling
|
|
3
|
+
# Sequel.expr:
|
|
4
4
|
#
|
|
5
5
|
# 1.sql_expr < :a # 1 < a
|
|
6
6
|
# false.sql_expr & :a # FALSE AND a
|
|
@@ -8,115 +8,9 @@
|
|
|
8
8
|
# ~nil.sql_expr # NOT NULL
|
|
9
9
|
# "a".sql_expr + "b" # 'a' || 'b'
|
|
10
10
|
|
|
11
|
-
module Sequel
|
|
12
|
-
module SQL
|
|
13
|
-
# The GenericComplexExpression acts like a
|
|
14
|
-
# GenericExpression in terms of methods,
|
|
15
|
-
# but has an internal structure of a
|
|
16
|
-
# ComplexExpression. It is used by Object#sql_expr.
|
|
17
|
-
# Since we don't know what specific type of object
|
|
18
|
-
# we are dealing with it, we treat it similarly to
|
|
19
|
-
# how we treat symbols or literal strings, allowing
|
|
20
|
-
# many different types of methods.
|
|
21
|
-
class GenericComplexExpression < ComplexExpression
|
|
22
|
-
include AliasMethods
|
|
23
|
-
include BooleanMethods
|
|
24
|
-
include CastMethods
|
|
25
|
-
include ComplexExpressionMethods
|
|
26
|
-
include InequalityMethods
|
|
27
|
-
include NumericMethods
|
|
28
|
-
include OrderMethods
|
|
29
|
-
include StringMethods
|
|
30
|
-
include SubscriptMethods
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
11
|
class Object
|
|
36
|
-
# Return
|
|
37
|
-
# Sequel::SQL::GenericComplexExpression. Allows easy use
|
|
38
|
-
# of the Object with Sequel's DSL. You'll probably have
|
|
39
|
-
# to make sure that Sequel knows how to literalize the
|
|
40
|
-
# object properly, though.
|
|
41
|
-
def sql_expr
|
|
42
|
-
Sequel::SQL::GenericComplexExpression.new(:NOOP, self)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
class FalseClass
|
|
47
|
-
# Returns a copy of the object wrapped in a
|
|
48
|
-
# Sequel::SQL::BooleanExpression, allowing easy use
|
|
49
|
-
# of Sequel's DSL:
|
|
50
|
-
#
|
|
51
|
-
# false.sql_expr & :a # FALSE AND a
|
|
52
|
-
def sql_expr
|
|
53
|
-
Sequel::SQL::BooleanExpression.new(:NOOP, self)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
class NilClass
|
|
58
|
-
# Returns a copy of the object wrapped in a
|
|
59
|
-
# Sequel::SQL::BooleanExpression, allowing easy use
|
|
60
|
-
# of Sequel's DSL:
|
|
61
|
-
#
|
|
62
|
-
# ~nil.sql_expr # NOT NULL
|
|
63
|
-
def sql_expr
|
|
64
|
-
Sequel::SQL::BooleanExpression.new(:NOOP, self)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
class Numeric
|
|
69
|
-
# Returns a copy of the object wrapped in a
|
|
70
|
-
# Sequel::SQL::NumericExpression, allowing easy use
|
|
71
|
-
# of Sequel's DSL:
|
|
72
|
-
#
|
|
73
|
-
# 1.sql_expr < :a # 1 < a
|
|
74
|
-
def sql_expr
|
|
75
|
-
Sequel::SQL::NumericExpression.new(:NOOP, self)
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
class Proc
|
|
80
|
-
# Evaluates the proc as a virtual row block.
|
|
81
|
-
# If a hash or array of two element arrays is returned,
|
|
82
|
-
# they are converted to a Sequel::SQL::BooleanExpression. Otherwise,
|
|
83
|
-
# unless the object returned is already an Sequel::SQL::Expression,
|
|
84
|
-
# convert the object to an Sequel::SQL::GenericComplexExpression.
|
|
85
|
-
#
|
|
86
|
-
# proc{a(b)}.sql_expr + 1 # a(b) + 1
|
|
87
|
-
# proc{{a=>b}}.sql_expr | true # (a = b) OR TRUE
|
|
88
|
-
# proc{1}.sql_expr + :a # 1 + a
|
|
89
|
-
def sql_expr
|
|
90
|
-
o = Sequel.virtual_row(&self)
|
|
91
|
-
if Sequel.condition_specifier?(o)
|
|
92
|
-
Sequel::SQL::BooleanExpression.from_value_pairs(o, :AND)
|
|
93
|
-
elsif o.is_a?(Sequel::SQL::Expression)
|
|
94
|
-
o
|
|
95
|
-
else
|
|
96
|
-
Sequel::SQL::GenericComplexExpression.new(:NOOP, o)
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
class String
|
|
102
|
-
# Returns a copy of the object wrapped in a
|
|
103
|
-
# Sequel::SQL::StringExpression, allowing easy use
|
|
104
|
-
# of Sequel's DSL:
|
|
105
|
-
#
|
|
106
|
-
# "a".sql_expr + :a # 'a' || a
|
|
12
|
+
# Return the object wrapper in an appropriate Sequel expression object.
|
|
107
13
|
def sql_expr
|
|
108
|
-
Sequel
|
|
14
|
+
Sequel.expr(self)
|
|
109
15
|
end
|
|
110
16
|
end
|
|
111
|
-
|
|
112
|
-
class TrueClass
|
|
113
|
-
# Returns a copy of the object wrapped in a
|
|
114
|
-
# Sequel::SQL::BooleanExpression, allowing easy use
|
|
115
|
-
# of Sequel's DSL:
|
|
116
|
-
#
|
|
117
|
-
# true.sql_expr | :a # TRUE OR a
|
|
118
|
-
def sql_expr
|
|
119
|
-
Sequel::SQL::BooleanExpression.new(:NOOP, self)
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
|
data/lib/sequel/model.rb
CHANGED
|
@@ -35,13 +35,18 @@ module Sequel
|
|
|
35
35
|
# dataset # => DB1[:comments]
|
|
36
36
|
# end
|
|
37
37
|
def self.Model(source)
|
|
38
|
-
Model::ANONYMOUS_MODEL_CLASSES[source]
|
|
38
|
+
if Sequel::Model.cache_anonymous_models && (klass = Model::ANONYMOUS_MODEL_CLASSES[source])
|
|
39
|
+
return klass
|
|
40
|
+
end
|
|
41
|
+
klass = if source.is_a?(Database)
|
|
39
42
|
c = Class.new(Model)
|
|
40
43
|
c.db = source
|
|
41
44
|
c
|
|
42
45
|
else
|
|
43
46
|
Class.new(Model).set_dataset(source)
|
|
44
47
|
end
|
|
48
|
+
Model::ANONYMOUS_MODEL_CLASSES[source] = klass if Sequel::Model.cache_anonymous_models
|
|
49
|
+
klass
|
|
45
50
|
end
|
|
46
51
|
|
|
47
52
|
# <tt>Sequel::Model</tt> is an object relational mapper built on top of Sequel core. Each
|
|
@@ -58,6 +63,9 @@ module Sequel
|
|
|
58
63
|
# You can set the +SEQUEL_NO_ASSOCIATIONS+ constant or environment variable to
|
|
59
64
|
# make Sequel not load the associations plugin by default.
|
|
60
65
|
class Model
|
|
66
|
+
# Cache anonymous models created by Sequel::Model()
|
|
67
|
+
@cache_anonymous_models = true
|
|
68
|
+
|
|
61
69
|
# Map that stores model classes created with <tt>Sequel::Model()</tt>, to allow the reopening
|
|
62
70
|
# of classes when dealing with code reloading.
|
|
63
71
|
ANONYMOUS_MODEL_CLASSES = {}
|
|
@@ -105,7 +113,8 @@ module Sequel
|
|
|
105
113
|
:@simple_pk=>nil, :@simple_table=>nil, :@strict_param_setting=>nil,
|
|
106
114
|
:@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
|
|
107
115
|
:@raise_on_typecast_failure=>nil, :@plugins=>:dup, :@setter_methods=>nil,
|
|
108
|
-
:@use_after_commit_rollback=>nil
|
|
116
|
+
:@use_after_commit_rollback=>nil, :@fast_pk_lookup_sql=>nil,
|
|
117
|
+
:@fast_instance_delete_sql=>nil}
|
|
109
118
|
|
|
110
119
|
# Regular expression that determines if a method name is normal in the sense that
|
|
111
120
|
# it could be used literally in ruby code without using send. Used to
|
|
@@ -1373,6 +1373,14 @@ module Sequel
|
|
|
1373
1373
|
def associations
|
|
1374
1374
|
@associations ||= {}
|
|
1375
1375
|
end
|
|
1376
|
+
|
|
1377
|
+
# Freeze the associations cache when freezing the object. Note that
|
|
1378
|
+
# retrieving associations after freezing will still work in most cases,
|
|
1379
|
+
# but the associations will not be cached in the association cache.
|
|
1380
|
+
def freeze
|
|
1381
|
+
associations.freeze
|
|
1382
|
+
super
|
|
1383
|
+
end
|
|
1376
1384
|
|
|
1377
1385
|
# Formally used internally by the associations code, like pk but doesn't raise
|
|
1378
1386
|
# an Error if the model has no primary key. Not used any longer, deprecated.
|
|
@@ -1424,15 +1432,29 @@ module Sequel
|
|
|
1424
1432
|
opts[:join_table_block] ? opts[:join_table_block].call(ds) : ds
|
|
1425
1433
|
end
|
|
1426
1434
|
|
|
1435
|
+
# Return the associated single object for the given association reflection and dynamic options
|
|
1436
|
+
# (or nil if no associated object).
|
|
1437
|
+
def _load_associated_object(opts, dynamic_opts)
|
|
1438
|
+
_load_associated_object_array(opts, dynamic_opts).first
|
|
1439
|
+
end
|
|
1440
|
+
|
|
1441
|
+
# Load the associated objects for the given association reflection and dynamic options
|
|
1442
|
+
# as an array.
|
|
1443
|
+
def _load_associated_object_array(opts, dynamic_opts)
|
|
1444
|
+
_associated_dataset(opts, dynamic_opts).all
|
|
1445
|
+
end
|
|
1446
|
+
|
|
1427
1447
|
# Return the associated objects from the dataset, without association callbacks, reciprocals, and caching.
|
|
1428
1448
|
# Still apply the dynamic callback if present.
|
|
1429
1449
|
def _load_associated_objects(opts, dynamic_opts={})
|
|
1430
|
-
if opts.
|
|
1431
|
-
opts.
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1450
|
+
if opts.can_have_associated_objects?(self)
|
|
1451
|
+
if opts.returns_array?
|
|
1452
|
+
_load_associated_object_array(opts, dynamic_opts)
|
|
1453
|
+
else
|
|
1454
|
+
_load_associated_object(opts, dynamic_opts)
|
|
1435
1455
|
end
|
|
1456
|
+
else
|
|
1457
|
+
[] if opts.returns_array?
|
|
1436
1458
|
end
|
|
1437
1459
|
end
|
|
1438
1460
|
|
|
@@ -1466,6 +1488,7 @@ module Sequel
|
|
|
1466
1488
|
|
|
1467
1489
|
# Add/Set the current object to/as the given object's reciprocal association.
|
|
1468
1490
|
def add_reciprocal_object(opts, o)
|
|
1491
|
+
return if o.frozen?
|
|
1469
1492
|
return unless reciprocal = opts.reciprocal
|
|
1470
1493
|
if opts.reciprocal_array?
|
|
1471
1494
|
if array = o.associations[reciprocal] and !array.include?(self)
|
|
@@ -1514,9 +1537,14 @@ module Sequel
|
|
|
1514
1537
|
add_reciprocal_object(opts, objs)
|
|
1515
1538
|
end
|
|
1516
1539
|
end
|
|
1517
|
-
|
|
1540
|
+
|
|
1541
|
+
# If the current object is frozen, you can't update the associations
|
|
1542
|
+
# cache. This can cause issues for after_load procs that expect
|
|
1543
|
+
# the objects to be already cached in the associations, but
|
|
1544
|
+
# unfortunately that case cannot be handled.
|
|
1545
|
+
associations[name] = objs unless frozen?
|
|
1518
1546
|
run_association_callbacks(opts, :after_load, objs)
|
|
1519
|
-
associations[name]
|
|
1547
|
+
frozen? ? objs : associations[name]
|
|
1520
1548
|
end
|
|
1521
1549
|
end
|
|
1522
1550
|
|
data/lib/sequel/model/base.rb
CHANGED
|
@@ -13,6 +13,11 @@ module Sequel
|
|
|
13
13
|
# Which columns should be the only columns allowed in a call to a mass assignment method (e.g. set)
|
|
14
14
|
# (default: not set, so all columns not otherwise restricted are allowed).
|
|
15
15
|
attr_reader :allowed_columns
|
|
16
|
+
|
|
17
|
+
# Whether to cache the anonymous models created by Sequel::Model(). This is
|
|
18
|
+
# required for reloading them correctly (avoiding the superclass mismatch). True
|
|
19
|
+
# by default for backwards compatibility.
|
|
20
|
+
attr_accessor :cache_anonymous_models
|
|
16
21
|
|
|
17
22
|
# Array of modules that extend this model's dataset. Stored
|
|
18
23
|
# so that if the model's dataset is changed, it will be extended
|
|
@@ -24,6 +29,14 @@ module Sequel
|
|
|
24
29
|
# will be applied to the new dataset.
|
|
25
30
|
attr_reader :dataset_methods
|
|
26
31
|
|
|
32
|
+
# SQL string fragment used for faster DELETE statement creation when deleting/destroying
|
|
33
|
+
# model instances, or nil if the optimization should not be used. For internal use only.
|
|
34
|
+
attr_reader :fast_instance_delete_sql
|
|
35
|
+
|
|
36
|
+
# The dataset that instance datasets (#this) are based on. Generally a naked version of
|
|
37
|
+
# the model's dataset limited to one row. For internal use only.
|
|
38
|
+
attr_reader :instance_dataset
|
|
39
|
+
|
|
27
40
|
# Array of plugin modules loaded by this class
|
|
28
41
|
#
|
|
29
42
|
# Sequel::Model.plugins
|
|
@@ -107,8 +120,8 @@ module Sequel
|
|
|
107
120
|
# Artist[:name=>'Bob'] # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
|
|
108
121
|
# # => #<Artist {:name=>'Bob', ...}>
|
|
109
122
|
def [](*args)
|
|
110
|
-
args = args.first if
|
|
111
|
-
args.is_a?(Hash) ? dataset[args] : primary_key_lookup(args)
|
|
123
|
+
args = args.first if args.size <= 1
|
|
124
|
+
args.is_a?(Hash) ? dataset[args] : (primary_key_lookup(args) unless args.nil?)
|
|
112
125
|
end
|
|
113
126
|
|
|
114
127
|
# Initializes a model instance as an existing record. This constructor is
|
|
@@ -394,7 +407,7 @@ module Sequel
|
|
|
394
407
|
# Artist.primary_key # => nil
|
|
395
408
|
def no_primary_key
|
|
396
409
|
clear_setter_methods_cache
|
|
397
|
-
|
|
410
|
+
self.simple_pk = @primary_key = nil
|
|
398
411
|
end
|
|
399
412
|
|
|
400
413
|
# Loads a plugin for use with the model class, passing optional arguments
|
|
@@ -402,16 +415,16 @@ module Sequel
|
|
|
402
415
|
# require the plugin from either sequel/plugins/#{plugin} or
|
|
403
416
|
# sequel_#{plugin}, and then attempt to load the module using a
|
|
404
417
|
# the camelized plugin name under Sequel::Plugins.
|
|
405
|
-
def plugin(plugin, *args, &
|
|
418
|
+
def plugin(plugin, *args, &block)
|
|
406
419
|
m = plugin.is_a?(Module) ? plugin : plugin_module(plugin)
|
|
407
420
|
unless @plugins.include?(m)
|
|
408
421
|
@plugins << m
|
|
409
|
-
m.apply(self, *args, &
|
|
422
|
+
m.apply(self, *args, &block) if m.respond_to?(:apply)
|
|
410
423
|
include(m::InstanceMethods) if plugin_module_defined?(m, :InstanceMethods)
|
|
411
424
|
extend(m::ClassMethods)if plugin_module_defined?(m, :ClassMethods)
|
|
412
425
|
dataset_extend(m::DatasetMethods) if plugin_module_defined?(m, :DatasetMethods)
|
|
413
426
|
end
|
|
414
|
-
m.configure(self, *args, &
|
|
427
|
+
m.configure(self, *args, &block) if m.respond_to?(:configure)
|
|
415
428
|
end
|
|
416
429
|
|
|
417
430
|
# Returns primary key attribute hash. If using a composite primary key
|
|
@@ -498,10 +511,10 @@ module Sequel
|
|
|
498
511
|
inherited = opts[:inherited]
|
|
499
512
|
@dataset = case ds
|
|
500
513
|
when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, LiteralString
|
|
501
|
-
|
|
514
|
+
self.simple_table = db.literal(ds)
|
|
502
515
|
db.from(ds)
|
|
503
516
|
when Dataset
|
|
504
|
-
|
|
517
|
+
self.simple_table = if ds.send(:simple_select_all?)
|
|
505
518
|
ds.literal(ds.first_source_table)
|
|
506
519
|
else
|
|
507
520
|
nil
|
|
@@ -514,7 +527,7 @@ module Sequel
|
|
|
514
527
|
@dataset.row_proc = self
|
|
515
528
|
@require_modification = Sequel::Model.require_modification.nil? ? @dataset.provides_accurate_rows_matched? : Sequel::Model.require_modification
|
|
516
529
|
if inherited
|
|
517
|
-
|
|
530
|
+
self.simple_table = superclass.simple_table
|
|
518
531
|
@columns = @dataset.columns rescue nil
|
|
519
532
|
else
|
|
520
533
|
@dataset_method_modules.each{|m| @dataset.extend(m)} if @dataset_method_modules
|
|
@@ -522,6 +535,7 @@ module Sequel
|
|
|
522
535
|
end
|
|
523
536
|
@dataset.model = self if @dataset.respond_to?(:model=)
|
|
524
537
|
check_non_connection_error{@db_schema = (inherited ? superclass.db_schema : get_db_schema)}
|
|
538
|
+
@instance_dataset = @dataset.limit(1).naked
|
|
525
539
|
self
|
|
526
540
|
end
|
|
527
541
|
|
|
@@ -542,7 +556,7 @@ module Sequel
|
|
|
542
556
|
def set_primary_key(*key)
|
|
543
557
|
clear_setter_methods_cache
|
|
544
558
|
key = key.flatten
|
|
545
|
-
|
|
559
|
+
self.simple_pk = if key.length == 1
|
|
546
560
|
(@dataset || db).literal(key.first)
|
|
547
561
|
else
|
|
548
562
|
nil
|
|
@@ -552,7 +566,7 @@ module Sequel
|
|
|
552
566
|
|
|
553
567
|
# Set the columns to restrict when using mass assignment (e.g. +set+). Using this means that
|
|
554
568
|
# attempts to call setter methods for the columns listed here will cause an
|
|
555
|
-
# exception or be silently skipped (based on the +strict_param_setting+ setting.
|
|
569
|
+
# exception or be silently skipped (based on the +strict_param_setting+ setting).
|
|
556
570
|
# If you have any virtual setter methods (methods that end in =) that you
|
|
557
571
|
# want not to be used during mass assignment, they need to be listed here as well (without the =).
|
|
558
572
|
#
|
|
@@ -769,13 +783,31 @@ module Sequel
|
|
|
769
783
|
|
|
770
784
|
# Find the row in the dataset that matches the primary key. Uses
|
|
771
785
|
# a static SQL optimization if the table and primary key are simple.
|
|
786
|
+
#
|
|
787
|
+
# This method should not be called with a nil primary key, in case
|
|
788
|
+
# it is overridden by plugins which assume that the passed argument
|
|
789
|
+
# is valid.
|
|
772
790
|
def primary_key_lookup(pk)
|
|
773
|
-
if
|
|
774
|
-
|
|
791
|
+
if sql = @fast_pk_lookup_sql
|
|
792
|
+
sql = sql.dup
|
|
793
|
+
dataset.literal_append(sql, pk)
|
|
794
|
+
dataset.fetch_rows(sql){|r| return call(r)}
|
|
795
|
+
nil
|
|
775
796
|
else
|
|
776
797
|
dataset[primary_key_hash(pk)]
|
|
777
798
|
end
|
|
778
799
|
end
|
|
800
|
+
|
|
801
|
+
# Reset the cached fast primary lookup SQL if a simple table and primary key
|
|
802
|
+
# are used, or set it to nil if not used.
|
|
803
|
+
def reset_fast_pk_lookup_sql
|
|
804
|
+
@fast_pk_lookup_sql = if @simple_table && @simple_pk
|
|
805
|
+
"SELECT * FROM #@simple_table WHERE #@simple_pk = ".freeze
|
|
806
|
+
end
|
|
807
|
+
@fast_instance_delete_sql = if @simple_table && @simple_pk
|
|
808
|
+
"DELETE FROM #@simple_table WHERE #@simple_pk = ".freeze
|
|
809
|
+
end
|
|
810
|
+
end
|
|
779
811
|
|
|
780
812
|
# Set the columns for this model and create accessor methods for each column.
|
|
781
813
|
def set_columns(new_columns)
|
|
@@ -784,6 +816,18 @@ module Sequel
|
|
|
784
816
|
@columns
|
|
785
817
|
end
|
|
786
818
|
|
|
819
|
+
# Reset the fast primary key lookup SQL when the simple_pk value changes.
|
|
820
|
+
def simple_pk=(pk)
|
|
821
|
+
@simple_pk = pk
|
|
822
|
+
reset_fast_pk_lookup_sql
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
# Reset the fast primary key lookup SQL when the simple_table value changes.
|
|
826
|
+
def simple_table=(t)
|
|
827
|
+
@simple_table = t
|
|
828
|
+
reset_fast_pk_lookup_sql
|
|
829
|
+
end
|
|
830
|
+
|
|
787
831
|
# Add model methods that call dataset methods
|
|
788
832
|
DATASET_METHODS.each{|arg| class_eval("def #{arg}(*args, &block); dataset.#{arg}(*args, &block) end", __FILE__, __LINE__)}
|
|
789
833
|
|
|
@@ -814,7 +858,7 @@ module Sequel
|
|
|
814
858
|
# same name, caching the result in an instance variable. Define
|
|
815
859
|
# standard attr_writer method for modifying that instance variable.
|
|
816
860
|
def self.class_attr_overridable(*meths) # :nodoc:
|
|
817
|
-
meths.each{|meth| class_eval("def #{meth}; !defined?(@#{meth}) ? (@#{meth} = self.class.#{meth}) : @#{meth} end", __FILE__, __LINE__)}
|
|
861
|
+
meths.each{|meth| class_eval("def #{meth}; !defined?(@#{meth}) ? (frozen? ? self.class.#{meth} : (@#{meth} = self.class.#{meth})) : @#{meth} end", __FILE__, __LINE__)}
|
|
818
862
|
attr_writer(*meths)
|
|
819
863
|
end
|
|
820
864
|
|
|
@@ -823,7 +867,7 @@ module Sequel
|
|
|
823
867
|
#
|
|
824
868
|
# define_method(meth){self.class.send(meth)}
|
|
825
869
|
def self.class_attr_reader(*meths) # :nodoc:
|
|
826
|
-
meths.each{|meth| class_eval("def #{meth};
|
|
870
|
+
meths.each{|meth| class_eval("def #{meth}; self.class.#{meth} end", __FILE__, __LINE__)}
|
|
827
871
|
end
|
|
828
872
|
|
|
829
873
|
private_class_method :class_attr_overridable, :class_attr_reader
|
|
@@ -888,9 +932,10 @@ module Sequel
|
|
|
888
932
|
# If the column isn't in @values, we can't assume it is
|
|
889
933
|
# NULL in the database, so assume it has changed.
|
|
890
934
|
v = typecast_value(column, value)
|
|
891
|
-
|
|
935
|
+
vals = @values
|
|
936
|
+
if new? || !vals.include?(column) || v != (c = vals[column]) || v.class != c.class
|
|
892
937
|
changed_columns << column unless changed_columns.include?(column)
|
|
893
|
-
|
|
938
|
+
vals[column] = v
|
|
894
939
|
end
|
|
895
940
|
end
|
|
896
941
|
|
|
@@ -941,6 +986,7 @@ module Sequel
|
|
|
941
986
|
# Artist[1].delete # DELETE FROM artists WHERE (id = 1)
|
|
942
987
|
# # => #<Artist {:id=>1, ...}>
|
|
943
988
|
def delete
|
|
989
|
+
raise Sequel::Error, "can't delete frozen object" if frozen?
|
|
944
990
|
_delete
|
|
945
991
|
self
|
|
946
992
|
end
|
|
@@ -955,6 +1001,7 @@ module Sequel
|
|
|
955
1001
|
# Artist[1].destroy # BEGIN; DELETE FROM artists WHERE (id = 1); COMMIT;
|
|
956
1002
|
# # => #<Artist {:id=>1, ...}>
|
|
957
1003
|
def destroy(opts = {})
|
|
1004
|
+
raise Sequel::Error, "can't destroy frozen object" if frozen?
|
|
958
1005
|
checked_save_failure(opts){checked_transaction(opts){_destroy(opts)}}
|
|
959
1006
|
end
|
|
960
1007
|
|
|
@@ -1002,6 +1049,19 @@ module Sequel
|
|
|
1002
1049
|
@singleton_setter_added = true
|
|
1003
1050
|
super
|
|
1004
1051
|
end
|
|
1052
|
+
|
|
1053
|
+
# Freeze the object in such a way that it is still usable but not modifiable.
|
|
1054
|
+
# Once an object is frozen, you cannot modify it's values, changed_columns,
|
|
1055
|
+
# errors, or dataset.
|
|
1056
|
+
def freeze
|
|
1057
|
+
values.freeze
|
|
1058
|
+
changed_columns.freeze
|
|
1059
|
+
errors
|
|
1060
|
+
validate
|
|
1061
|
+
errors.freeze
|
|
1062
|
+
this.freeze unless new?
|
|
1063
|
+
super
|
|
1064
|
+
end
|
|
1005
1065
|
|
|
1006
1066
|
# Value that should be unique for objects with the same class and pk (if pk is not nil), or
|
|
1007
1067
|
# the same class and values (if pk is nil).
|
|
@@ -1106,7 +1166,12 @@ module Sequel
|
|
|
1106
1166
|
# Artist[[1, 2]].pk # => [1, 2]
|
|
1107
1167
|
def pk
|
|
1108
1168
|
raise(Error, "No primary key is associated with this model") unless key = primary_key
|
|
1109
|
-
key.is_a?(Array)
|
|
1169
|
+
if key.is_a?(Array)
|
|
1170
|
+
vals = @values
|
|
1171
|
+
key.map{|k| vals[k]}
|
|
1172
|
+
else
|
|
1173
|
+
@values[key]
|
|
1174
|
+
end
|
|
1110
1175
|
end
|
|
1111
1176
|
|
|
1112
1177
|
# Returns a hash identifying mapping the receivers primary key column(s) to their values.
|
|
@@ -1126,6 +1191,7 @@ module Sequel
|
|
|
1126
1191
|
# a.refresh
|
|
1127
1192
|
# a.name # => 'Bob'
|
|
1128
1193
|
def refresh
|
|
1194
|
+
raise Sequel::Error, "can't refresh frozen object" if frozen?
|
|
1129
1195
|
_refresh(this)
|
|
1130
1196
|
end
|
|
1131
1197
|
|
|
@@ -1162,6 +1228,7 @@ module Sequel
|
|
|
1162
1228
|
# +use_transactions+ setting
|
|
1163
1229
|
# :validate :: set to false to skip validation
|
|
1164
1230
|
def save(*columns)
|
|
1231
|
+
raise Sequel::Error, "can't save frozen object" if frozen?
|
|
1165
1232
|
opts = columns.last.is_a?(Hash) ? columns.pop : {}
|
|
1166
1233
|
set_server(opts[:server]) if opts[:server]
|
|
1167
1234
|
if opts[:validate] != false
|
|
@@ -1220,14 +1287,56 @@ module Sequel
|
|
|
1220
1287
|
# For each of the fields in the given array +fields+, call the setter
|
|
1221
1288
|
# method with the value of that +hash+ entry for the field. Returns self.
|
|
1222
1289
|
#
|
|
1290
|
+
# You can provide an options hash, with the following options currently respected:
|
|
1291
|
+
# :missing :: Can be set to :skip to skip missing entries or :raise to raise an
|
|
1292
|
+
# Error for missing entries. The default behavior is not to check for
|
|
1293
|
+
# missing entries, in which case the default value is used. To be
|
|
1294
|
+
# friendly with most web frameworks, the missing check will also check
|
|
1295
|
+
# for the string version of the argument in the hash if given a symbol.
|
|
1296
|
+
#
|
|
1297
|
+
# Examples:
|
|
1298
|
+
#
|
|
1223
1299
|
# artist.set_fields({:name=>'Jim'}, [:name])
|
|
1224
1300
|
# artist.name # => 'Jim'
|
|
1225
1301
|
#
|
|
1226
1302
|
# artist.set_fields({:hometown=>'LA'}, [:name])
|
|
1227
1303
|
# artist.name # => nil
|
|
1228
1304
|
# artist.hometown # => 'Sac'
|
|
1229
|
-
|
|
1230
|
-
|
|
1305
|
+
#
|
|
1306
|
+
# artist.name # => 'Jim'
|
|
1307
|
+
# artist.set_fields({}, [:name], :missing=>:skip)
|
|
1308
|
+
# artist.name # => 'Jim'
|
|
1309
|
+
#
|
|
1310
|
+
# artist.name # => 'Jim'
|
|
1311
|
+
# artist.set_fields({}, [:name], :missing=>:raise)
|
|
1312
|
+
# # Sequel::Error raised
|
|
1313
|
+
def set_fields(hash, fields, opts=nil)
|
|
1314
|
+
if opts
|
|
1315
|
+
case opts[:missing]
|
|
1316
|
+
when :skip
|
|
1317
|
+
fields.each do |f|
|
|
1318
|
+
if hash.has_key?(f)
|
|
1319
|
+
send("#{f}=", hash[f])
|
|
1320
|
+
elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s)
|
|
1321
|
+
send("#{sf}=", hash[sf])
|
|
1322
|
+
end
|
|
1323
|
+
end
|
|
1324
|
+
when :raise
|
|
1325
|
+
fields.each do |f|
|
|
1326
|
+
if hash.has_key?(f)
|
|
1327
|
+
send("#{f}=", hash[f])
|
|
1328
|
+
elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s)
|
|
1329
|
+
send("#{sf}=", hash[sf])
|
|
1330
|
+
else
|
|
1331
|
+
raise(Sequel::Error, "missing field in hash: #{f.inspect} not in #{hash.inspect}")
|
|
1332
|
+
end
|
|
1333
|
+
end
|
|
1334
|
+
else
|
|
1335
|
+
fields.each{|f| send("#{f}=", hash[f])}
|
|
1336
|
+
end
|
|
1337
|
+
else
|
|
1338
|
+
fields.each{|f| send("#{f}=", hash[f])}
|
|
1339
|
+
end
|
|
1231
1340
|
self
|
|
1232
1341
|
end
|
|
1233
1342
|
|
|
@@ -1268,7 +1377,7 @@ module Sequel
|
|
|
1268
1377
|
# Artist[1].this
|
|
1269
1378
|
# # SELECT * FROM artists WHERE (id = 1) LIMIT 1
|
|
1270
1379
|
def this
|
|
1271
|
-
@this ||= use_server(model.
|
|
1380
|
+
@this ||= use_server(model.instance_dataset.filter(pk_hash))
|
|
1272
1381
|
end
|
|
1273
1382
|
|
|
1274
1383
|
# Runs #set with the passed hash and then runs save_changes.
|
|
@@ -1296,16 +1405,16 @@ module Sequel
|
|
|
1296
1405
|
update_restricted(hash, false, except.flatten)
|
|
1297
1406
|
end
|
|
1298
1407
|
|
|
1299
|
-
# Update the instances values by calling +set_fields+ with the
|
|
1300
|
-
#
|
|
1408
|
+
# Update the instances values by calling +set_fields+ with the arguments, then
|
|
1409
|
+
# saves any changes to the record. Returns self.
|
|
1301
1410
|
#
|
|
1302
1411
|
# artist.update_fields({:name=>'Jim'}, [:name])
|
|
1303
1412
|
# # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
1304
1413
|
#
|
|
1305
1414
|
# artist.update_fields({:hometown=>'LA'}, [:name])
|
|
1306
1415
|
# # UPDATE artists SET name = NULL WHERE (id = 1)
|
|
1307
|
-
def update_fields(hash, fields)
|
|
1308
|
-
set_fields(hash, fields)
|
|
1416
|
+
def update_fields(hash, fields, opts=nil)
|
|
1417
|
+
set_fields(hash, fields, opts)
|
|
1309
1418
|
save_changes
|
|
1310
1419
|
end
|
|
1311
1420
|
|
|
@@ -1358,14 +1467,20 @@ module Sequel
|
|
|
1358
1467
|
# Actually do the deletion of the object's dataset. Return the
|
|
1359
1468
|
# number of rows modified.
|
|
1360
1469
|
def _delete_without_checking
|
|
1361
|
-
|
|
1470
|
+
if sql = (m = model).fast_instance_delete_sql
|
|
1471
|
+
sql = sql.dup
|
|
1472
|
+
(ds = m.dataset).literal_append(sql, pk)
|
|
1473
|
+
ds.with_sql_delete(sql)
|
|
1474
|
+
else
|
|
1475
|
+
_delete_dataset.delete
|
|
1476
|
+
end
|
|
1362
1477
|
end
|
|
1363
1478
|
|
|
1364
1479
|
# Internal destroy method, separted from destroy to
|
|
1365
1480
|
# allow running inside a transaction
|
|
1366
1481
|
def _destroy(opts)
|
|
1367
1482
|
sh = {:server=>this_server}
|
|
1368
|
-
db.after_rollback(sh){after_destroy_rollback} if use_after_commit_rollback
|
|
1483
|
+
db.after_rollback(sh){after_destroy_rollback} if uacr = use_after_commit_rollback
|
|
1369
1484
|
called = false
|
|
1370
1485
|
around_destroy do
|
|
1371
1486
|
called = true
|
|
@@ -1375,7 +1490,7 @@ module Sequel
|
|
|
1375
1490
|
true
|
|
1376
1491
|
end
|
|
1377
1492
|
raise_hook_failure(:destroy) unless called
|
|
1378
|
-
db.after_commit(sh){after_destroy_commit} if
|
|
1493
|
+
db.after_commit(sh){after_destroy_commit} if uacr
|
|
1379
1494
|
self
|
|
1380
1495
|
end
|
|
1381
1496
|
|
|
@@ -1391,14 +1506,14 @@ module Sequel
|
|
|
1391
1506
|
def _insert
|
|
1392
1507
|
ds = _insert_dataset
|
|
1393
1508
|
if !ds.opts[:select] and ds.supports_insert_select? and h = _insert_select_raw(ds)
|
|
1394
|
-
|
|
1509
|
+
set_values(h)
|
|
1395
1510
|
nil
|
|
1396
1511
|
else
|
|
1397
1512
|
iid = _insert_raw(ds)
|
|
1398
1513
|
# if we have a regular primary key and it's not set in @values,
|
|
1399
1514
|
# we assume it's the last inserted id
|
|
1400
|
-
if (pk = autoincrementing_primary_key) && pk.is_a?(Symbol) &&
|
|
1401
|
-
|
|
1515
|
+
if (pk = autoincrementing_primary_key) && pk.is_a?(Symbol) && !(vals = @values)[pk]
|
|
1516
|
+
vals[pk] = iid
|
|
1402
1517
|
end
|
|
1403
1518
|
pk
|
|
1404
1519
|
end
|
|
@@ -1407,7 +1522,7 @@ module Sequel
|
|
|
1407
1522
|
# The dataset to use when inserting a new object. The same as the model's
|
|
1408
1523
|
# dataset by default.
|
|
1409
1524
|
def _insert_dataset
|
|
1410
|
-
use_server(model.
|
|
1525
|
+
use_server(model.instance_dataset)
|
|
1411
1526
|
end
|
|
1412
1527
|
|
|
1413
1528
|
# Insert into the given dataset and return the primary key created (if any).
|
|
@@ -1437,7 +1552,7 @@ module Sequel
|
|
|
1437
1552
|
# it's own transaction.
|
|
1438
1553
|
def _save(columns, opts)
|
|
1439
1554
|
sh = {:server=>this_server}
|
|
1440
|
-
db.after_rollback(sh){after_rollback} if use_after_commit_rollback
|
|
1555
|
+
db.after_rollback(sh){after_rollback} if uacr = use_after_commit_rollback
|
|
1441
1556
|
was_new = false
|
|
1442
1557
|
pk = nil
|
|
1443
1558
|
called_save = false
|
|
@@ -1491,7 +1606,7 @@ module Sequel
|
|
|
1491
1606
|
@columns_updated = nil
|
|
1492
1607
|
end
|
|
1493
1608
|
@modified = false
|
|
1494
|
-
db.after_commit(sh){after_commit} if
|
|
1609
|
+
db.after_commit(sh){after_commit} if uacr
|
|
1495
1610
|
self
|
|
1496
1611
|
end
|
|
1497
1612
|
|
|
@@ -1544,6 +1659,7 @@ module Sequel
|
|
|
1544
1659
|
# failures will be raised as HookFailure exceptions. If it is
|
|
1545
1660
|
# +false+, +false+ will be returned instead.
|
|
1546
1661
|
def _valid?(raise_errors, opts)
|
|
1662
|
+
return errors.empty? if frozen?
|
|
1547
1663
|
errors.clear
|
|
1548
1664
|
called = false
|
|
1549
1665
|
error = false
|
|
@@ -1597,7 +1713,7 @@ module Sequel
|
|
|
1597
1713
|
# exists so it can be overridden. This is called only for new records, before
|
|
1598
1714
|
# changed_columns is cleared.
|
|
1599
1715
|
def initialize_set(h)
|
|
1600
|
-
set(h)
|
|
1716
|
+
set(h) unless h.empty?
|
|
1601
1717
|
end
|
|
1602
1718
|
|
|
1603
1719
|
# Default inspection output for the values hash, overwrite to change what #inspect displays.
|
|
@@ -1621,6 +1737,7 @@ module Sequel
|
|
|
1621
1737
|
|
|
1622
1738
|
# Set the columns, filtered by the only and except arrays.
|
|
1623
1739
|
def set_restricted(hash, only, except)
|
|
1740
|
+
return self if hash.empty?
|
|
1624
1741
|
meths = if only.nil? && except.nil? && !@singleton_setter_added
|
|
1625
1742
|
model.setter_methods
|
|
1626
1743
|
else
|
|
@@ -1679,7 +1796,13 @@ module Sequel
|
|
|
1679
1796
|
# The server/shard that the model object's dataset uses, or :default if the
|
|
1680
1797
|
# model object's dataset does not have an associated shard.
|
|
1681
1798
|
def this_server
|
|
1682
|
-
|
|
1799
|
+
if (s = @server)
|
|
1800
|
+
s
|
|
1801
|
+
elsif (t = @this)
|
|
1802
|
+
t.opts[:server] || :default
|
|
1803
|
+
else
|
|
1804
|
+
model.dataset.opts[:server] || :default
|
|
1805
|
+
end
|
|
1683
1806
|
end
|
|
1684
1807
|
|
|
1685
1808
|
# Typecast the value to the column's type if typecasting. Calls the database's
|