sequel 3.33.0 → 3.34.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|