sequel 3.47.0 → 3.48.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 +230 -0
- data/README.rdoc +31 -40
- data/Rakefile +1 -14
- data/doc/active_record.rdoc +29 -29
- data/doc/association_basics.rdoc +4 -13
- data/doc/cheat_sheet.rdoc +8 -6
- data/doc/code_order.rdoc +89 -0
- data/doc/core_extensions.rdoc +3 -3
- data/doc/dataset_basics.rdoc +7 -8
- data/doc/dataset_filtering.rdoc +7 -2
- data/doc/mass_assignment.rdoc +2 -3
- data/doc/migration.rdoc +8 -8
- data/doc/model_hooks.rdoc +11 -7
- data/doc/object_model.rdoc +2 -2
- data/doc/opening_databases.rdoc +5 -14
- data/doc/prepared_statements.rdoc +5 -9
- data/doc/querying.rdoc +23 -28
- data/doc/reflection.rdoc +11 -0
- data/doc/release_notes/3.48.0.txt +477 -0
- data/doc/schema_modification.rdoc +12 -5
- data/doc/security.rdoc +2 -2
- data/doc/sharding.rdoc +1 -2
- data/doc/sql.rdoc +10 -13
- data/doc/testing.rdoc +8 -4
- data/doc/transactions.rdoc +2 -2
- data/doc/validations.rdoc +40 -17
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado.rb +25 -20
- data/lib/sequel/adapters/ado/access.rb +1 -0
- data/lib/sequel/adapters/ado/mssql.rb +1 -0
- data/lib/sequel/adapters/db2.rb +9 -7
- data/lib/sequel/adapters/dbi.rb +16 -16
- data/lib/sequel/adapters/do.rb +17 -18
- data/lib/sequel/adapters/do/mysql.rb +1 -0
- data/lib/sequel/adapters/do/postgres.rb +2 -0
- data/lib/sequel/adapters/do/sqlite.rb +1 -0
- data/lib/sequel/adapters/firebird.rb +5 -7
- data/lib/sequel/adapters/ibmdb.rb +23 -20
- data/lib/sequel/adapters/informix.rb +8 -2
- data/lib/sequel/adapters/jdbc.rb +39 -35
- data/lib/sequel/adapters/jdbc/as400.rb +1 -0
- data/lib/sequel/adapters/jdbc/cubrid.rb +1 -0
- data/lib/sequel/adapters/jdbc/db2.rb +1 -0
- data/lib/sequel/adapters/jdbc/derby.rb +1 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +1 -0
- data/lib/sequel/adapters/jdbc/h2.rb +1 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -0
- data/lib/sequel/adapters/jdbc/informix.rb +1 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +1 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +2 -0
- data/lib/sequel/adapters/jdbc/progress.rb +1 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -0
- data/lib/sequel/adapters/mock.rb +30 -31
- data/lib/sequel/adapters/mysql.rb +6 -7
- data/lib/sequel/adapters/mysql2.rb +5 -6
- data/lib/sequel/adapters/odbc.rb +22 -20
- data/lib/sequel/adapters/odbc/mssql.rb +1 -0
- data/lib/sequel/adapters/openbase.rb +4 -1
- data/lib/sequel/adapters/oracle.rb +10 -8
- data/lib/sequel/adapters/postgres.rb +12 -10
- data/lib/sequel/adapters/shared/access.rb +6 -0
- data/lib/sequel/adapters/shared/cubrid.rb +2 -0
- data/lib/sequel/adapters/shared/db2.rb +2 -0
- data/lib/sequel/adapters/shared/firebird.rb +2 -0
- data/lib/sequel/adapters/shared/informix.rb +2 -0
- data/lib/sequel/adapters/shared/mssql.rb +14 -8
- data/lib/sequel/adapters/shared/mysql.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +2 -0
- data/lib/sequel/adapters/shared/postgres.rb +14 -4
- data/lib/sequel/adapters/shared/progress.rb +1 -0
- data/lib/sequel/adapters/shared/sqlite.rb +4 -3
- data/lib/sequel/adapters/sqlite.rb +6 -7
- data/lib/sequel/adapters/swift.rb +20 -21
- data/lib/sequel/adapters/swift/mysql.rb +1 -0
- data/lib/sequel/adapters/swift/postgres.rb +2 -0
- data/lib/sequel/adapters/swift/sqlite.rb +1 -0
- data/lib/sequel/adapters/tinytds.rb +5 -6
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +68 -0
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +57 -50
- data/lib/sequel/database/connecting.rb +9 -10
- data/lib/sequel/database/dataset.rb +11 -6
- data/lib/sequel/database/dataset_defaults.rb +61 -69
- data/lib/sequel/database/features.rb +21 -0
- data/lib/sequel/database/misc.rb +23 -3
- data/lib/sequel/database/query.rb +13 -7
- data/lib/sequel/database/schema_methods.rb +6 -6
- data/lib/sequel/database/transactions.rb +1 -0
- data/lib/sequel/dataset/actions.rb +51 -38
- data/lib/sequel/dataset/features.rb +1 -0
- data/lib/sequel/dataset/graph.rb +9 -33
- data/lib/sequel/dataset/misc.rb +30 -5
- data/lib/sequel/dataset/mutation.rb +2 -3
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/query.rb +91 -27
- data/lib/sequel/dataset/sql.rb +40 -6
- data/lib/sequel/deprecated.rb +74 -0
- data/lib/sequel/deprecated_core_extensions.rb +135 -0
- data/lib/sequel/extensions/columns_introspection.rb +1 -5
- data/lib/sequel/extensions/core_extensions.rb +10 -3
- data/lib/sequel/extensions/date_arithmetic.rb +1 -0
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +33 -0
- data/lib/sequel/extensions/filter_having.rb +58 -0
- data/lib/sequel/extensions/graph_each.rb +63 -0
- data/lib/sequel/extensions/hash_aliases.rb +44 -0
- data/lib/sequel/extensions/looser_typecasting.rb +14 -3
- data/lib/sequel/extensions/migration.rb +2 -3
- data/lib/sequel/extensions/named_timezones.rb +14 -1
- data/lib/sequel/extensions/null_dataset.rb +7 -1
- data/lib/sequel/extensions/pagination.rb +15 -5
- data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +48 -14
- data/lib/sequel/extensions/pg_json.rb +7 -7
- data/lib/sequel/extensions/pg_range_ops.rb +8 -2
- data/lib/sequel/extensions/pg_statement_cache.rb +1 -0
- data/lib/sequel/extensions/pretty_table.rb +13 -4
- data/lib/sequel/extensions/query.rb +21 -4
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +22 -0
- data/lib/sequel/extensions/schema_caching.rb +10 -7
- data/lib/sequel/extensions/schema_dumper.rb +35 -48
- data/lib/sequel/extensions/select_remove.rb +13 -4
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +117 -0
- data/lib/sequel/extensions/set_overrides.rb +43 -0
- data/lib/sequel/extensions/to_dot.rb +6 -0
- data/lib/sequel/model.rb +12 -6
- data/lib/sequel/model/associations.rb +80 -38
- data/lib/sequel/model/base.rb +137 -52
- data/lib/sequel/model/errors.rb +7 -2
- data/lib/sequel/plugins/active_model.rb +13 -0
- data/lib/sequel/plugins/after_initialize.rb +43 -0
- data/lib/sequel/plugins/association_proxies.rb +63 -7
- data/lib/sequel/plugins/auto_validations.rb +56 -16
- data/lib/sequel/plugins/blacklist_security.rb +63 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +9 -0
- data/lib/sequel/plugins/constraint_validations.rb +50 -8
- data/lib/sequel/plugins/dataset_associations.rb +2 -0
- data/lib/sequel/plugins/hook_class_methods.rb +7 -1
- data/lib/sequel/plugins/identity_map.rb +4 -0
- data/lib/sequel/plugins/json_serializer.rb +32 -13
- data/lib/sequel/plugins/optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +4 -4
- data/lib/sequel/plugins/scissors.rb +33 -0
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +6 -0
- data/lib/sequel/plugins/tree.rb +5 -1
- data/lib/sequel/plugins/validation_class_methods.rb +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +15 -11
- data/lib/sequel/plugins/xml_serializer.rb +12 -3
- data/lib/sequel/sql.rb +12 -2
- data/lib/sequel/timezones.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/mssql_spec.rb +24 -57
- data/spec/adapters/postgres_spec.rb +27 -55
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/bin_spec.rb +251 -0
- data/spec/core/database_spec.rb +46 -32
- data/spec/core/dataset_spec.rb +233 -181
- data/spec/core/deprecated_spec.rb +78 -0
- data/spec/core/expression_filters_spec.rb +3 -4
- data/spec/core/mock_adapter_spec.rb +9 -9
- data/spec/core/object_graph_spec.rb +9 -19
- data/spec/core/schema_spec.rb +3 -1
- data/spec/core/spec_helper.rb +19 -0
- data/spec/core_extensions_spec.rb +80 -30
- data/spec/extensions/after_initialize_spec.rb +24 -0
- data/spec/extensions/association_proxies_spec.rb +37 -1
- data/spec/extensions/auto_validations_spec.rb +20 -4
- data/spec/extensions/blacklist_security_spec.rb +87 -0
- data/spec/extensions/boolean_readers_spec.rb +2 -1
- data/spec/extensions/class_table_inheritance_spec.rb +7 -0
- data/spec/extensions/columns_introspection_spec.rb +3 -3
- data/spec/extensions/constraint_validations_plugin_spec.rb +83 -5
- data/spec/extensions/core_refinements_spec.rb +7 -7
- data/spec/extensions/dataset_associations_spec.rb +2 -2
- data/spec/extensions/date_arithmetic_spec.rb +1 -1
- data/spec/extensions/defaults_setter_spec.rb +2 -1
- data/spec/extensions/empty_array_ignore_nulls_spec.rb +24 -0
- data/spec/extensions/filter_having_spec.rb +40 -0
- data/spec/extensions/graph_each_spec.rb +109 -0
- data/spec/extensions/hash_aliases_spec.rb +16 -0
- data/spec/extensions/hook_class_methods_spec.rb +2 -2
- data/spec/extensions/identity_map_spec.rb +3 -3
- data/spec/extensions/json_serializer_spec.rb +19 -19
- data/spec/extensions/lazy_attributes_spec.rb +1 -0
- data/spec/extensions/list_spec.rb +13 -13
- data/spec/extensions/looser_typecasting_spec.rb +10 -3
- data/spec/extensions/many_through_many_spec.rb +1 -1
- data/spec/extensions/migration_spec.rb +7 -7
- data/spec/extensions/named_timezones_spec.rb +6 -0
- data/spec/extensions/nested_attributes_spec.rb +2 -2
- data/spec/extensions/null_dataset_spec.rb +1 -1
- data/spec/extensions/pagination_spec.rb +2 -2
- data/spec/extensions/pg_hstore_ops_spec.rb +75 -0
- data/spec/extensions/pg_range_ops_spec.rb +4 -2
- data/spec/extensions/pg_row_plugin_spec.rb +1 -1
- data/spec/extensions/pretty_table_spec.rb +1 -1
- data/spec/extensions/query_literals_spec.rb +1 -1
- data/spec/extensions/query_spec.rb +3 -3
- data/spec/extensions/schema_caching_spec.rb +3 -3
- data/spec/extensions/schema_dumper_spec.rb +27 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/scissors_spec.rb +26 -0
- data/spec/extensions/select_remove_spec.rb +1 -1
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +102 -0
- data/spec/extensions/set_overrides_spec.rb +45 -0
- data/spec/extensions/single_table_inheritance_spec.rb +10 -0
- data/spec/extensions/spec_helper.rb +24 -1
- data/spec/extensions/static_cache_spec.rb +1 -1
- data/spec/extensions/string_stripper_spec.rb +2 -1
- data/spec/extensions/to_dot_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +3 -2
- data/spec/extensions/update_primary_key_spec.rb +2 -2
- data/spec/extensions/validation_class_methods_spec.rb +19 -19
- data/spec/extensions/validation_helpers_spec.rb +30 -21
- data/spec/extensions/xml_serializer_spec.rb +5 -5
- data/spec/integration/associations_test.rb +10 -30
- data/spec/integration/dataset_test.rb +20 -24
- data/spec/integration/eager_loader_test.rb +5 -5
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +7 -39
- data/spec/integration/schema_test.rb +4 -38
- data/spec/integration/spec_helper.rb +2 -1
- data/spec/model/association_reflection_spec.rb +70 -5
- data/spec/model/associations_spec.rb +11 -11
- data/spec/model/base_spec.rb +25 -8
- data/spec/model/class_dataset_methods_spec.rb +143 -0
- data/spec/model/dataset_methods_spec.rb +1 -1
- data/spec/model/eager_loading_spec.rb +25 -25
- data/spec/model/hooks_spec.rb +1 -1
- data/spec/model/model_spec.rb +22 -7
- data/spec/model/plugins_spec.rb +1 -6
- data/spec/model/record_spec.rb +37 -29
- data/spec/model/spec_helper.rb +23 -1
- data/spec/model/validations_spec.rb +15 -17
- metadata +32 -3
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# The set_overrides extension adds the Dataset#set_overrides and
|
|
2
|
+
# Dataset#set_defaults methods which provide a crude way to
|
|
3
|
+
# control the values used in INSERT/UPDATE statements if a hash
|
|
4
|
+
# of values is passed to Dataset#insert or Dataset#update.
|
|
5
|
+
# It is only recommended to use this for backwards compatibility.
|
|
6
|
+
#
|
|
7
|
+
# You can load this extension into specific datasets:
|
|
8
|
+
#
|
|
9
|
+
# ds = DB[:table]
|
|
10
|
+
# ds.extension(:set_overrides)
|
|
11
|
+
#
|
|
12
|
+
# Or you can load it into all of a database's datasets, which
|
|
13
|
+
# is probably the desired behavior if you are using this extension:
|
|
14
|
+
#
|
|
15
|
+
# DB.extension(:set_overrides)
|
|
16
|
+
|
|
17
|
+
module Sequel
|
|
18
|
+
module SetOverrides
|
|
19
|
+
Dataset.def_mutation_method(:set_defaults, :set_overrides, :module=>self)
|
|
20
|
+
|
|
21
|
+
# Set the default values for insert and update statements. The values hash passed
|
|
22
|
+
# to insert or update are merged into this hash, so any values in the hash passed
|
|
23
|
+
# to insert or update will override values passed to this method.
|
|
24
|
+
#
|
|
25
|
+
# DB[:items].set_defaults(:a=>'a', :c=>'c').insert(:a=>'d', :b=>'b')
|
|
26
|
+
# # INSERT INTO items (a, c, b) VALUES ('d', 'c', 'b')
|
|
27
|
+
def set_defaults(hash)
|
|
28
|
+
clone(:defaults=>(@opts[:defaults]||{}).merge(hash))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Set values that override hash arguments given to insert and update statements.
|
|
32
|
+
# This hash is merged into the hash provided to insert or update, so values
|
|
33
|
+
# will override any values given in the insert/update hashes.
|
|
34
|
+
#
|
|
35
|
+
# DB[:items].set_overrides(:a=>'a', :c=>'c').insert(:a=>'d', :b=>'b')
|
|
36
|
+
# # INSERT INTO items (a, c, b) VALUES ('a', 'c', 'b')
|
|
37
|
+
def set_overrides(hash)
|
|
38
|
+
clone(:overrides=>hash.merge(@opts[:overrides]||{}))
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Dataset.register_extension(:set_overrides, SetOverrides)
|
|
43
|
+
end
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
module Sequel
|
|
11
11
|
class ToDot
|
|
12
|
+
module DatasetMethods
|
|
13
|
+
end
|
|
14
|
+
|
|
12
15
|
# The option keys that should be included in the dot output.
|
|
13
16
|
TO_DOT_OPTIONS = [:with, :distinct, :select, :from, :join, :where, :group, :having, :compounds, :order, :limit, :offset, :lock].freeze
|
|
14
17
|
|
|
@@ -147,7 +150,10 @@ module Sequel
|
|
|
147
150
|
# with graphviz) in order to see a visualization of the dataset's
|
|
148
151
|
# abstract syntax tree.
|
|
149
152
|
def to_dot
|
|
153
|
+
Sequel::Deprecation.deprecate('Loading the to_dot extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(ToDot::DatasetMethods)
|
|
150
154
|
ToDot.output(self)
|
|
151
155
|
end
|
|
152
156
|
end
|
|
157
|
+
|
|
158
|
+
Dataset.register_extension(:to_dot, ToDot::DatasetMethods)
|
|
153
159
|
end
|
data/lib/sequel/model.rb
CHANGED
|
@@ -35,7 +35,7 @@ module Sequel
|
|
|
35
35
|
# dataset # => DB1[:comments]
|
|
36
36
|
# end
|
|
37
37
|
def self.Model(source)
|
|
38
|
-
if
|
|
38
|
+
if cache_anonymous_models && (klass = Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source]})
|
|
39
39
|
return klass
|
|
40
40
|
end
|
|
41
41
|
klass = if source.is_a?(Database)
|
|
@@ -45,10 +45,19 @@ module Sequel
|
|
|
45
45
|
else
|
|
46
46
|
Class.new(Model).set_dataset(source)
|
|
47
47
|
end
|
|
48
|
-
Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source] = klass} if
|
|
48
|
+
Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source] = klass} if cache_anonymous_models
|
|
49
49
|
klass
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
@cache_anonymous_models = true
|
|
53
|
+
|
|
54
|
+
class << self
|
|
55
|
+
# Whether to cache the anonymous models created by Sequel::Model(). This is
|
|
56
|
+
# required for reloading them correctly (avoiding the superclass mismatch). True
|
|
57
|
+
# by default for backwards compatibility.
|
|
58
|
+
attr_accessor :cache_anonymous_models
|
|
59
|
+
end
|
|
60
|
+
|
|
52
61
|
# <tt>Sequel::Model</tt> is an object relational mapper built on top of Sequel core. Each
|
|
53
62
|
# model class is backed by a dataset instance, and many dataset methods can be
|
|
54
63
|
# called directly on the class. Model datasets return rows as model instances,
|
|
@@ -63,16 +72,13 @@ module Sequel
|
|
|
63
72
|
# You can set the +SEQUEL_NO_ASSOCIATIONS+ constant or environment variable to
|
|
64
73
|
# make Sequel not load the associations plugin by default.
|
|
65
74
|
class Model
|
|
66
|
-
# Cache anonymous models created by Sequel::Model()
|
|
67
|
-
@cache_anonymous_models = true
|
|
68
|
-
|
|
69
75
|
# Map that stores model classes created with <tt>Sequel::Model()</tt>, to allow the reopening
|
|
70
76
|
# of classes when dealing with code reloading.
|
|
71
77
|
ANONYMOUS_MODEL_CLASSES = {}
|
|
72
78
|
|
|
73
79
|
# Class methods added to model that call the method of the same name on the dataset
|
|
74
80
|
DATASET_METHODS = (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS +
|
|
75
|
-
[:
|
|
81
|
+
[:each_server]) - [:and, :or, :[], :[]=, :columns, :columns!, :delete, :update, :add_graph_aliases]
|
|
76
82
|
|
|
77
83
|
# Class instance variables to set to nil when a subclass is created, for -w compliance
|
|
78
84
|
EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@db]
|
|
@@ -188,20 +188,32 @@ module Sequel
|
|
|
188
188
|
# it sets album.artist to this_artist.
|
|
189
189
|
def reciprocal
|
|
190
190
|
cached_fetch(:reciprocal) do
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
possible_recips = []
|
|
192
|
+
fallback_recips = []
|
|
193
|
+
|
|
194
194
|
associated_class.all_association_reflections.each do |assoc_reflect|
|
|
195
|
-
if
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
if reciprocal_association?(assoc_reflect)
|
|
196
|
+
if deprecated_reciprocal_association?(assoc_reflect)
|
|
197
|
+
fallback_recips << assoc_reflect
|
|
198
|
+
else
|
|
199
|
+
possible_recips << assoc_reflect
|
|
200
|
+
end
|
|
199
201
|
end
|
|
200
202
|
end
|
|
201
|
-
|
|
203
|
+
|
|
204
|
+
Sequel::Deprecation.deprecate("Multiple reciprocal association candidates found for #{self[:name]} association (#{possible_recips.map{|r| r[:name]}.join(', ')}). Choosing the first candidate is", "Please explicitly specify the reciprocal option for the #{self[:name]} association") if possible_recips.size >= 2
|
|
205
|
+
if possible_recips.empty? && !fallback_recips.empty?
|
|
206
|
+
possible_recips = fallback_recips
|
|
207
|
+
Sequel::Deprecation.deprecate("All reciprocal association candidates found for #{self[:name]} association have conditions, blocks, or differing primary keys (#{possible_recips.map{|r| r[:name]}.join(', ')}). Automatic choosing of an reciprocal association with conditions or blocks is", "Please explicitly specify the reciprocal option for the #{self[:name]} association")
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
unless possible_recips.empty?
|
|
211
|
+
cached_set(:reciprocal_type, possible_recips.first[:type]) if reciprocal_type.is_a?(Array)
|
|
212
|
+
possible_recips.first[:name]
|
|
213
|
+
end
|
|
202
214
|
end
|
|
203
215
|
end
|
|
204
|
-
|
|
216
|
+
|
|
205
217
|
# Whether the reciprocal of this association returns an array of objects instead of a single object,
|
|
206
218
|
# true by default.
|
|
207
219
|
def reciprocal_array?
|
|
@@ -288,6 +300,16 @@ module Sequel
|
|
|
288
300
|
end
|
|
289
301
|
end
|
|
290
302
|
|
|
303
|
+
# REMOVE40: merge into reciprocal_association?
|
|
304
|
+
def deprecated_reciprocal_association?(assoc_reflect)
|
|
305
|
+
assoc_reflect[:conditions] || assoc_reflect[:block]
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def reciprocal_association?(assoc_reflect)
|
|
309
|
+
Array(reciprocal_type).include?(assoc_reflect[:type]) &&
|
|
310
|
+
assoc_reflect.associated_class == self[:model]
|
|
311
|
+
end
|
|
312
|
+
|
|
291
313
|
# If +s+ is an array, map +s+ over the block. Otherwise, just call the
|
|
292
314
|
# block with +s+.
|
|
293
315
|
def transform(s)
|
|
@@ -378,6 +400,15 @@ module Sequel
|
|
|
378
400
|
|
|
379
401
|
private
|
|
380
402
|
|
|
403
|
+
# REMOVE40: merge into reciprocal_association?
|
|
404
|
+
def deprecated_reciprocal_association?(assoc_reflect)
|
|
405
|
+
super || primary_key != assoc_reflect.primary_key
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def reciprocal_association?(assoc_reflect)
|
|
409
|
+
super && self[:keys] == assoc_reflect[:keys]
|
|
410
|
+
end
|
|
411
|
+
|
|
381
412
|
# The reciprocal type of a many_to_one association is either
|
|
382
413
|
# a one_to_many or a one_to_one association.
|
|
383
414
|
def reciprocal_type
|
|
@@ -444,6 +475,15 @@ module Sequel
|
|
|
444
475
|
|
|
445
476
|
private
|
|
446
477
|
|
|
478
|
+
# REMOVE40: merge into reciprocal_association?
|
|
479
|
+
def deprecated_reciprocal_association?(assoc_reflect)
|
|
480
|
+
super || primary_key != assoc_reflect.primary_key
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def reciprocal_association?(assoc_reflect)
|
|
484
|
+
super && self[:keys] == assoc_reflect[:keys]
|
|
485
|
+
end
|
|
486
|
+
|
|
447
487
|
# The reciprocal type of a one_to_many association is a many_to_one association.
|
|
448
488
|
def reciprocal_type
|
|
449
489
|
:many_to_one
|
|
@@ -570,25 +610,6 @@ module Sequel
|
|
|
570
610
|
true
|
|
571
611
|
end
|
|
572
612
|
|
|
573
|
-
# Returns the reciprocal association symbol, if one exists.
|
|
574
|
-
def reciprocal
|
|
575
|
-
cached_fetch(:reciprocal) do
|
|
576
|
-
left_keys = self[:left_keys]
|
|
577
|
-
right_keys = self[:right_keys]
|
|
578
|
-
join_table = self[:join_table]
|
|
579
|
-
recip = nil
|
|
580
|
-
associated_class.all_association_reflections.each do |assoc_reflect|
|
|
581
|
-
if assoc_reflect[:type] == :many_to_many && assoc_reflect[:left_keys] == right_keys &&
|
|
582
|
-
assoc_reflect[:right_keys] == left_keys && assoc_reflect[:join_table] == join_table &&
|
|
583
|
-
assoc_reflect.associated_class == self[:model]
|
|
584
|
-
recip = assoc_reflect[:name]
|
|
585
|
-
break
|
|
586
|
-
end
|
|
587
|
-
end
|
|
588
|
-
recip
|
|
589
|
-
end
|
|
590
|
-
end
|
|
591
|
-
|
|
592
613
|
# #right_primary_key qualified by the associated table
|
|
593
614
|
def qualified_right_primary_key
|
|
594
615
|
cached_fetch(:qualified_right_primary_key){qualify_assoc(right_primary_key)}
|
|
@@ -623,6 +644,21 @@ module Sequel
|
|
|
623
644
|
|
|
624
645
|
private
|
|
625
646
|
|
|
647
|
+
# REMOVE40: merge into reciprocal_association?
|
|
648
|
+
def deprecated_reciprocal_association?(assoc_reflect)
|
|
649
|
+
super || right_primary_keys != assoc_reflect[:left_primary_key_columns] || self[:left_primary_key_columns] != assoc_reflect.right_primary_keys
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def reciprocal_association?(assoc_reflect)
|
|
653
|
+
super && assoc_reflect[:left_keys] == self[:right_keys] &&
|
|
654
|
+
assoc_reflect[:right_keys] == self[:left_keys] &&
|
|
655
|
+
assoc_reflect[:join_table] == self[:join_table]
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
def reciprocal_type
|
|
659
|
+
:many_to_many
|
|
660
|
+
end
|
|
661
|
+
|
|
626
662
|
# Split the join table into source and alias parts.
|
|
627
663
|
def split_join_table_alias
|
|
628
664
|
associated_class.dataset.split_alias(self[:join_table])
|
|
@@ -782,12 +818,10 @@ module Sequel
|
|
|
782
818
|
# :eager_graph :: The associations to eagerly load via +eager_graph+ when loading the associated object(s).
|
|
783
819
|
# many_to_many associations with this option cannot be eagerly loaded via +eager+.
|
|
784
820
|
# :eager_grapher :: A proc to use to implement eager loading via +eager_graph+, overriding the default.
|
|
785
|
-
# Takes
|
|
786
|
-
# the
|
|
787
|
-
# (
|
|
788
|
-
#
|
|
789
|
-
# additional key :eager_block, a callback accepting one argument, the associated dataset. This
|
|
790
|
-
# is used to customize the association at query time.
|
|
821
|
+
# Takes an options hash with the entries :self (the receiver of the eager_graph call),
|
|
822
|
+
# :table_alias (the alias to use for table to graph into the association), :implicit_qualifier
|
|
823
|
+
# (the alias that was used for the current table), and possibly :eager_block (a callback
|
|
824
|
+
# proc accepting the associated dataset, for per-call customization).
|
|
791
825
|
# Should return a copy of the dataset with the association graphed into it.
|
|
792
826
|
# :eager_limit_strategy :: Determines the strategy used for enforcing limits when eager loading associations via
|
|
793
827
|
# the +eager+ method. For one_to_one associations, no strategy is used by default, and
|
|
@@ -795,8 +829,8 @@ module Sequel
|
|
|
795
829
|
# all records but slices the resulting array after the association is retrieved. You
|
|
796
830
|
# can pass a +true+ value for this option to have Sequel pick what it thinks is the best
|
|
797
831
|
# choice for the database, or specify a specific symbol to manually select a strategy.
|
|
798
|
-
# one_to_one associations support :distinct_on
|
|
799
|
-
# *_many associations support :ruby,
|
|
832
|
+
# one_to_one associations support :distinct_on and :window_function.
|
|
833
|
+
# *_many associations support :ruby, and :window_function.
|
|
800
834
|
# :eager_loader :: A proc to use to implement eager loading, overriding the default. Takes a single hash argument,
|
|
801
835
|
# with at least the keys: :rows, which is an array of current model instances, :associations,
|
|
802
836
|
# which is a hash of dependent associations, :self, which is the dataset doing the eager loading,
|
|
@@ -922,12 +956,18 @@ module Sequel
|
|
|
922
956
|
# Defaults to :right_primary_key option.
|
|
923
957
|
# :uniq :: Adds a after_load callback that makes the array of objects unique.
|
|
924
958
|
def associate(type, name, opts = {}, &block)
|
|
925
|
-
|
|
959
|
+
if opts[:one_to_one] && type == :one_to_many
|
|
960
|
+
Sequel::Deprecation.deprecate('Raising an Error when the one_to_many type uses the :one_to_one option', "Use the one_to_one associationtype")
|
|
961
|
+
raise(Error, 'one_to_many association type with :one_to_one option removed, used one_to_one association type')
|
|
962
|
+
end
|
|
926
963
|
raise(Error, 'invalid association type') unless assoc_class = ASSOCIATION_TYPES[type]
|
|
927
|
-
raise(Error, 'Model.associate name argument must be a symbol') unless Symbol
|
|
964
|
+
raise(Error, 'Model.associate name argument must be a symbol') unless name.is_a?(Symbol)
|
|
928
965
|
raise(Error, ':eager_loader option must have an arity of 1 or 3') if opts[:eager_loader] && ![1, 3].include?(opts[:eager_loader].arity)
|
|
929
966
|
raise(Error, ':eager_grapher option must have an arity of 1 or 3') if opts[:eager_grapher] && ![1, 3].include?(opts[:eager_grapher].arity)
|
|
930
967
|
|
|
968
|
+
Sequel::Deprecation.deprecate('The :eager_loader association option accepting 3 arguments', "Please switch to accepting a single options hash") if opts[:eager_loader] && opts[:eager_loader].arity == 3
|
|
969
|
+
Sequel::Deprecation.deprecate('The :eager_grapher association option accepting 3 arguments', "Please switch to accepting a single options hash") if opts[:eager_grapher] && opts[:eager_grapher].arity == 3
|
|
970
|
+
|
|
931
971
|
# dup early so we don't modify opts
|
|
932
972
|
orig_opts = opts.dup
|
|
933
973
|
if opts[:clone]
|
|
@@ -1023,6 +1063,7 @@ module Sequel
|
|
|
1023
1063
|
|
|
1024
1064
|
# Use a correlated subquery to limit the results of the eager loading dataset.
|
|
1025
1065
|
def apply_correlated_subquery_eager_limit_strategy(ds, opts)
|
|
1066
|
+
Sequel::Deprecation.deprecate('The correlated_subquery eager limit strategy', 'Switch to another eager limit strategy.')
|
|
1026
1067
|
klass = opts.associated_class
|
|
1027
1068
|
kds = klass.dataset
|
|
1028
1069
|
dsa = ds.send(:dataset_alias, 1)
|
|
@@ -1460,6 +1501,7 @@ module Sequel
|
|
|
1460
1501
|
# Formally used internally by the associations code, like pk but doesn't raise
|
|
1461
1502
|
# an Error if the model has no primary key. Not used any longer, deprecated.
|
|
1462
1503
|
def pk_or_nil
|
|
1504
|
+
Sequel::Deprecation.deprecate('Model#pk_or_nil', 'There is no replacement')
|
|
1463
1505
|
key = primary_key
|
|
1464
1506
|
key.is_a?(Array) ? key.map{|k| @values[k]} : @values[key]
|
|
1465
1507
|
end
|
data/lib/sequel/model/base.rb
CHANGED
|
@@ -12,10 +12,15 @@ module Sequel
|
|
|
12
12
|
# (default: not set, so all columns not otherwise restricted are allowed).
|
|
13
13
|
attr_reader :allowed_columns
|
|
14
14
|
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
# REMOVE40
|
|
16
|
+
def cache_anonymous_models
|
|
17
|
+
Sequel::Deprecation.deprecate('Model.cache_anonymous_models', 'Please switch to Sequel.cache_anonymous_models')
|
|
18
|
+
Sequel.cache_anonymous_models
|
|
19
|
+
end
|
|
20
|
+
def cache_anonymous_models=(v)
|
|
21
|
+
Sequel::Deprecation.deprecate('Model.cache_anonymous_models=', 'Please switch to Sequel.cache_anonymous_models=')
|
|
22
|
+
Sequel.cache_anonymous_models = v
|
|
23
|
+
end
|
|
19
24
|
|
|
20
25
|
# Array of modules that extend this model's dataset. Stored
|
|
21
26
|
# so that if the model's dataset is changed, it will be extended
|
|
@@ -63,10 +68,14 @@ module Sequel
|
|
|
63
68
|
# Sequel will not check the number of rows modified (default: true).
|
|
64
69
|
attr_accessor :require_modification
|
|
65
70
|
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
# REMOVE40
|
|
72
|
+
def restricted_columns
|
|
73
|
+
Sequel::Deprecation.deprecate('Model.restricted_columns', 'Please load the blacklist_security plugin to continue using it')
|
|
74
|
+
@restricted_columns
|
|
75
|
+
end
|
|
76
|
+
def _restricted_columns
|
|
77
|
+
@restricted_columns
|
|
78
|
+
end
|
|
70
79
|
|
|
71
80
|
# Should be the literal primary key column name if this Model's table has a simple primary key, or
|
|
72
81
|
# nil if the model has a compound primary key or no primary key.
|
|
@@ -254,7 +263,7 @@ module Sequel
|
|
|
254
263
|
# sharding support.
|
|
255
264
|
def db=(db)
|
|
256
265
|
@db = db
|
|
257
|
-
set_dataset(db.dataset(@dataset.opts)) if @dataset
|
|
266
|
+
set_dataset(db.dataset.clone(@dataset.opts)) if @dataset
|
|
258
267
|
end
|
|
259
268
|
|
|
260
269
|
# Returns the cached schema information if available or gets it
|
|
@@ -342,9 +351,11 @@ module Sequel
|
|
|
342
351
|
# may contain setter methods.
|
|
343
352
|
def include(mod)
|
|
344
353
|
clear_setter_methods_cache
|
|
354
|
+
check_deprecated_after_initialize(mod.instance_methods) unless allowed_after_initialize_implementation?(mod)
|
|
355
|
+
Sequel::Deprecation.deprecate('Model#set_values', 'Please override Model.call, Model#_refresh_set_values, and/or Model#_create_set_values depending on the type of behavior you want to change') if mod.public_instance_methods.map{|x| x.to_s}.include?('set_values') && mod.name.to_s !~ /\ASequel::(Model|Model::Associations|Plugins::(ForceEncoding|Serialization|TypecastOnLoad|Composition|PreparedStatementsSafe|Dirty|PgTypecastOnLoad))::InstanceMethods\z/
|
|
345
356
|
super
|
|
346
357
|
end
|
|
347
|
-
|
|
358
|
+
|
|
348
359
|
# If possible, set the dataset for the model subclass as soon as it
|
|
349
360
|
# is created. Also, make sure the inherited class instance variables
|
|
350
361
|
# are copied into the subclass.
|
|
@@ -405,6 +416,8 @@ module Sequel
|
|
|
405
416
|
# Clear the setter_methods cache when a setter method is added
|
|
406
417
|
def method_added(meth)
|
|
407
418
|
clear_setter_methods_cache if meth.to_s =~ SETTER_METHOD_REGEXP
|
|
419
|
+
check_deprecated_after_initialize(meth)
|
|
420
|
+
Sequel::Deprecation.deprecate('Model#set_values', 'Please override Model.call, Model#_refresh_set_values, and/or Model#_create_set_values depending on the type of behavior you want to change') if meth.to_s == 'set_values'
|
|
408
421
|
super
|
|
409
422
|
end
|
|
410
423
|
|
|
@@ -431,7 +444,18 @@ module Sequel
|
|
|
431
444
|
m.apply(self, *args, &block) if m.respond_to?(:apply)
|
|
432
445
|
include(m::InstanceMethods) if plugin_module_defined?(m, :InstanceMethods)
|
|
433
446
|
extend(m::ClassMethods)if plugin_module_defined?(m, :ClassMethods)
|
|
434
|
-
|
|
447
|
+
if plugin_module_defined?(m, :DatasetMethods)
|
|
448
|
+
dataset_extend(m::DatasetMethods, :create_class_methods=>false)
|
|
449
|
+
# REMOVE40
|
|
450
|
+
m::DatasetMethods.public_instance_methods.each do |meth|
|
|
451
|
+
unless respond_to?(meth, true)
|
|
452
|
+
(class << self; self; end).send(:define_method, meth) do |*args, &block|
|
|
453
|
+
Sequel::Deprecation.deprecate('Automatically defining Model class methods for plugin public dataset methods', "Please modify the plugin to use Plugins.def_dataset_method for #{meth}")
|
|
454
|
+
dataset.send(meth, *args, &block)
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
end
|
|
435
459
|
end
|
|
436
460
|
m.configure(self, *args, &block) if m.respond_to?(:configure)
|
|
437
461
|
end
|
|
@@ -521,10 +545,10 @@ module Sequel
|
|
|
521
545
|
# sharding support.
|
|
522
546
|
def set_dataset(ds, opts={})
|
|
523
547
|
inherited = opts[:inherited]
|
|
524
|
-
|
|
548
|
+
case ds
|
|
525
549
|
when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, LiteralString
|
|
526
550
|
self.simple_table = db.literal(ds)
|
|
527
|
-
db.from(ds)
|
|
551
|
+
ds = db.from(ds)
|
|
528
552
|
when Dataset
|
|
529
553
|
self.simple_table = if ds.send(:simple_select_all?)
|
|
530
554
|
ds.literal(ds.first_source_table)
|
|
@@ -532,11 +556,11 @@ module Sequel
|
|
|
532
556
|
nil
|
|
533
557
|
end
|
|
534
558
|
@db = ds.db
|
|
535
|
-
ds
|
|
536
559
|
else
|
|
537
560
|
raise(Error, "Model.set_dataset takes one of the following classes as an argument: Symbol, LiteralString, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, Dataset")
|
|
538
561
|
end
|
|
539
|
-
|
|
562
|
+
set_dataset_row_proc(ds)
|
|
563
|
+
@dataset = ds
|
|
540
564
|
@require_modification = Sequel::Model.require_modification.nil? ? @dataset.provides_accurate_rows_matched? : Sequel::Model.require_modification
|
|
541
565
|
if inherited
|
|
542
566
|
self.simple_table = superclass.simple_table
|
|
@@ -565,6 +589,9 @@ module Sequel
|
|
|
565
589
|
# set_primary_key [:taggable_id, :tag_id]
|
|
566
590
|
# end
|
|
567
591
|
def set_primary_key(*key)
|
|
592
|
+
Sequel::Deprecation.deprecate('Calling set_primary_key without arguments is deprecated and will raise an exception in Sequel 4. Please use no_primary_key to mark the model as not having a primary key.') if key.length == 0
|
|
593
|
+
Sequel::Deprecation.deprecate('Calling set_primary_key with multiple arguments is deprecated and will raise an exception in Sequel 4. Please pass an array of keys to setup a composite primary key.') if key.length > 1
|
|
594
|
+
|
|
568
595
|
clear_setter_methods_cache
|
|
569
596
|
key = key.flatten
|
|
570
597
|
self.simple_pk = if key.length == 1
|
|
@@ -590,6 +617,7 @@ module Sequel
|
|
|
590
617
|
# Artist.set(:name=>'Bob', :records_sold=>30000) # Error
|
|
591
618
|
def set_restricted_columns(*cols)
|
|
592
619
|
clear_setter_methods_cache
|
|
620
|
+
Sequel::Deprecation.deprecate('Model.set_restricted_columns', 'Please switch to Model.set_allowed_columns or use the blacklist_security plugin')
|
|
593
621
|
@restricted_columns = cols
|
|
594
622
|
end
|
|
595
623
|
|
|
@@ -600,7 +628,7 @@ module Sequel
|
|
|
600
628
|
else
|
|
601
629
|
meths = instance_methods.collect{|x| x.to_s}.grep(SETTER_METHOD_REGEXP) - RESTRICTED_SETTER_METHODS
|
|
602
630
|
meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && restrict_primary_key?
|
|
603
|
-
meths -=
|
|
631
|
+
meths -= _restricted_columns.map{|x| "#{x}="} if _restricted_columns
|
|
604
632
|
meths
|
|
605
633
|
end
|
|
606
634
|
end
|
|
@@ -651,6 +679,37 @@ module Sequel
|
|
|
651
679
|
clear_setter_methods_cache
|
|
652
680
|
@restrict_primary_key = false
|
|
653
681
|
end
|
|
682
|
+
|
|
683
|
+
# Return the model instance with the primary key, or nil if there is no matching record.
|
|
684
|
+
def with_pk(pk)
|
|
685
|
+
primary_key_lookup(pk)
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
# Return the model instance with the primary key, or raise NoMatchingRow if there is no matching record.
|
|
689
|
+
def with_pk!(pk)
|
|
690
|
+
with_pk(pk) || raise(NoMatchingRow)
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
# Add model methods that call dataset methods
|
|
694
|
+
Plugins.def_dataset_methods(self, DATASET_METHODS)
|
|
695
|
+
|
|
696
|
+
# REMOVE40
|
|
697
|
+
%w'print each_page set add_graph_aliases insert_multiple query set_overrides set_defaults to_csv paginate'.each do |meth|
|
|
698
|
+
class_eval(<<-END, __FILE__, __LINE__+1)
|
|
699
|
+
def #{meth}(*args, &block)
|
|
700
|
+
Sequel::Deprecation.deprecate('Model.#{meth}', 'Please use Model.dataset.#{meth} instead')
|
|
701
|
+
dataset.#{meth}(*args, &block)
|
|
702
|
+
end
|
|
703
|
+
END
|
|
704
|
+
end
|
|
705
|
+
%w'destroy delete update'.each do |meth|
|
|
706
|
+
class_eval(<<-END, __FILE__, __LINE__+1)
|
|
707
|
+
def #{meth}(*args, &block)
|
|
708
|
+
Sequel::Deprecation.deprecate('Model.#{meth}', 'Please use the scissors plugin or Model.dataset.#{meth} instead')
|
|
709
|
+
dataset.#{meth}(*args, &block)
|
|
710
|
+
end
|
|
711
|
+
END
|
|
712
|
+
end
|
|
654
713
|
|
|
655
714
|
private
|
|
656
715
|
|
|
@@ -665,14 +724,28 @@ module Sequel
|
|
|
665
724
|
end
|
|
666
725
|
end
|
|
667
726
|
|
|
727
|
+
# REMOVE40
|
|
728
|
+
def allowed_after_initialize_implementation?(mod)
|
|
729
|
+
mod == InstanceMethods || mod.to_s == 'Sequel::Plugins::HookClassMethods::InstanceMethods'
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
# REMOVE40
|
|
733
|
+
def check_deprecated_after_initialize(meths)
|
|
734
|
+
Array(meths).each do |meth|
|
|
735
|
+
Sequel::Deprecation.deprecate('The Model after_initialize hook', 'Please use the after_initialize plugin to continue using the hook') if meth.to_s == 'after_initialize'
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
|
|
668
739
|
# Add the module to the class's dataset_method_modules. Extend the dataset with the
|
|
669
740
|
# module if the model has a dataset. Add dataset methods to the class for all
|
|
670
741
|
# public dataset methods.
|
|
671
|
-
def dataset_extend(mod)
|
|
672
|
-
@dataset.extend(mod) if
|
|
742
|
+
def dataset_extend(mod, opts={})
|
|
743
|
+
@dataset.extend(mod) if @dataset
|
|
673
744
|
reset_instance_dataset
|
|
674
745
|
dataset_method_modules << mod
|
|
675
|
-
|
|
746
|
+
unless opts[:create_class_methods] == false
|
|
747
|
+
mod.public_instance_methods.each{|meth| def_model_dataset_method(meth)}
|
|
748
|
+
end
|
|
676
749
|
end
|
|
677
750
|
|
|
678
751
|
# Create a column accessor for a column with a method name that is hard to use in ruby code.
|
|
@@ -719,7 +792,7 @@ module Sequel
|
|
|
719
792
|
schema_hash = {}
|
|
720
793
|
ds_opts = dataset.opts
|
|
721
794
|
get_columns = proc{check_non_connection_error{columns} || []}
|
|
722
|
-
schema_array = check_non_connection_error{db.schema(dataset, :reload=>reload)}
|
|
795
|
+
schema_array = check_non_connection_error{db.schema(dataset, :reload=>reload)} if db.supports_schema_parsing?
|
|
723
796
|
if schema_array
|
|
724
797
|
schema_array.each{|k,v| schema_hash[k] = v}
|
|
725
798
|
if ds_opts.include?(:select)
|
|
@@ -739,7 +812,7 @@ module Sequel
|
|
|
739
812
|
# if the schema information includes primary key information
|
|
740
813
|
if schema_array.all?{|k,v| v.has_key?(:primary_key)}
|
|
741
814
|
pks = schema_array.collect{|k,v| k if v[:primary_key]}.compact
|
|
742
|
-
pks.length > 0 ? set_primary_key(
|
|
815
|
+
pks.length > 0 ? set_primary_key(pks) : no_primary_key
|
|
743
816
|
end
|
|
744
817
|
# Also set the columns for the dataset, so the dataset
|
|
745
818
|
# doesn't have to do a query to get them.
|
|
@@ -780,7 +853,7 @@ module Sequel
|
|
|
780
853
|
# Module that the class includes that holds methods the class adds for column accessors and
|
|
781
854
|
# associations so that the methods can be overridden with +super+.
|
|
782
855
|
def overridable_methods_module
|
|
783
|
-
include(@overridable_methods_module = Module.new) unless
|
|
856
|
+
include(@overridable_methods_module = Module.new) unless @overridable_methods_module
|
|
784
857
|
@overridable_methods_module
|
|
785
858
|
end
|
|
786
859
|
|
|
@@ -792,10 +865,10 @@ module Sequel
|
|
|
792
865
|
(Sequel.const_defined?(module_name) &&
|
|
793
866
|
Sequel::Plugins.const_get(module_name) == Sequel.const_get(module_name))
|
|
794
867
|
begin
|
|
795
|
-
|
|
868
|
+
require "sequel/plugins/#{plugin}"
|
|
796
869
|
rescue LoadError => e
|
|
797
870
|
begin
|
|
798
|
-
|
|
871
|
+
require "sequel_#{plugin}"
|
|
799
872
|
rescue LoadError => e2
|
|
800
873
|
e.message << "; #{e2.message}"
|
|
801
874
|
raise e
|
|
@@ -848,7 +921,7 @@ module Sequel
|
|
|
848
921
|
# Reset the instance dataset to a modified copy of the current dataset,
|
|
849
922
|
# should be used whenever the model's dataset is modified.
|
|
850
923
|
def reset_instance_dataset
|
|
851
|
-
@instance_dataset = @dataset.limit(1).naked if
|
|
924
|
+
@instance_dataset = @dataset.limit(1).naked if @dataset
|
|
852
925
|
end
|
|
853
926
|
|
|
854
927
|
# Set the columns for this model and create accessor methods for each column.
|
|
@@ -858,6 +931,11 @@ module Sequel
|
|
|
858
931
|
@columns
|
|
859
932
|
end
|
|
860
933
|
|
|
934
|
+
# Set the dataset's row_proc to the current model.
|
|
935
|
+
def set_dataset_row_proc(ds)
|
|
936
|
+
ds.row_proc = self
|
|
937
|
+
end
|
|
938
|
+
|
|
861
939
|
# Reset the fast primary key lookup SQL when the simple_pk value changes.
|
|
862
940
|
def simple_pk=(pk)
|
|
863
941
|
@simple_pk = pk
|
|
@@ -870,9 +948,6 @@ module Sequel
|
|
|
870
948
|
reset_fast_pk_lookup_sql
|
|
871
949
|
end
|
|
872
950
|
|
|
873
|
-
# Add model methods that call dataset methods
|
|
874
|
-
Plugins.def_dataset_methods(self, DATASET_METHODS)
|
|
875
|
-
|
|
876
951
|
# Returns a copy of the model's dataset with custom SQL
|
|
877
952
|
#
|
|
878
953
|
# Artist.fetch("SELECT * FROM artists WHERE name LIKE 'A%'")
|
|
@@ -896,32 +971,29 @@ module Sequel
|
|
|
896
971
|
HOOKS.each{|h| class_eval("def #{h}; end", __FILE__, __LINE__)}
|
|
897
972
|
AROUND_HOOKS.each{|h| class_eval("def #{h}; yield end", __FILE__, __LINE__)}
|
|
898
973
|
|
|
899
|
-
#
|
|
900
|
-
# same name, caching the result in an instance variable. Define
|
|
901
|
-
# standard attr_writer method for modifying that instance variable.
|
|
902
|
-
#
|
|
903
|
-
# Do not call this method with untrusted input, as that can result in
|
|
904
|
-
# arbitrary code execution.
|
|
974
|
+
# REMOVE40
|
|
905
975
|
def self.class_attr_overridable(*meths) # :nodoc:
|
|
976
|
+
Sequel::Deprecation.deprecate('Model::InstanceMethods.class_attr_overridable', "There is no replacement planned")
|
|
906
977
|
meths.each{|meth| class_eval("def #{meth}; !defined?(@#{meth}) ? (frozen? ? self.class.#{meth} : (@#{meth} = self.class.#{meth})) : @#{meth} end", __FILE__, __LINE__)}
|
|
907
978
|
attr_writer(*meths)
|
|
908
979
|
end
|
|
909
|
-
|
|
910
|
-
# Define instance method(s) that calls class method(s) of the
|
|
911
|
-
# same name. Replaces the construct:
|
|
912
|
-
#
|
|
913
|
-
# define_method(meth){self.class.send(meth)}
|
|
914
|
-
#
|
|
915
|
-
# Do not call this method with untrusted input, as that can result in
|
|
916
|
-
# arbitrary code execution.
|
|
917
980
|
def self.class_attr_reader(*meths) # :nodoc:
|
|
981
|
+
Sequel::Deprecation.deprecate('Model::InstanceMethods.class_attr_reader', "There is no replacement planned")
|
|
918
982
|
meths.each{|meth| class_eval("def #{meth}; self.class.#{meth} end", __FILE__, __LINE__)}
|
|
919
983
|
end
|
|
920
|
-
|
|
921
984
|
private_class_method :class_attr_overridable, :class_attr_reader
|
|
922
985
|
|
|
923
|
-
|
|
924
|
-
|
|
986
|
+
# Define instance method(s) that calls class method(s) of the
|
|
987
|
+
# same name. Replaces the construct:
|
|
988
|
+
#
|
|
989
|
+
# define_method(meth){self.class.send(meth)}
|
|
990
|
+
[:columns, :db, :primary_key, :db_schema].each{|meth| class_eval("def #{meth}; self.class.#{meth} end", __FILE__, __LINE__)}
|
|
991
|
+
|
|
992
|
+
# Define instance method(s) that calls class method(s) of the
|
|
993
|
+
# same name, caching the result in an instance variable. Define
|
|
994
|
+
# standard attr_writer method for modifying that instance variable.
|
|
995
|
+
BOOLEAN_SETTINGS.each{|meth| class_eval("def #{meth}; !defined?(@#{meth}) ? (frozen? ? self.class.#{meth} : (@#{meth} = self.class.#{meth})) : @#{meth} end", __FILE__, __LINE__)}
|
|
996
|
+
attr_writer(*BOOLEAN_SETTINGS)
|
|
925
997
|
|
|
926
998
|
# The hash of attribute values. Keys are symbols with the names of the
|
|
927
999
|
# underlying database columns.
|
|
@@ -948,6 +1020,7 @@ module Sequel
|
|
|
948
1020
|
# end
|
|
949
1021
|
def initialize(values = {}, from_db = false)
|
|
950
1022
|
if from_db
|
|
1023
|
+
Sequel::Deprecation.deprecate('Passing two arguments to Model.new', 'Please use Model.call instead')
|
|
951
1024
|
set_values(values)
|
|
952
1025
|
else
|
|
953
1026
|
@values = {}
|
|
@@ -1074,7 +1147,7 @@ module Sequel
|
|
|
1074
1147
|
# Returns the validation errors associated with this object.
|
|
1075
1148
|
# See +Errors+.
|
|
1076
1149
|
def errors
|
|
1077
|
-
@errors ||=
|
|
1150
|
+
@errors ||= errors_class.new
|
|
1078
1151
|
end
|
|
1079
1152
|
|
|
1080
1153
|
# Returns true when current instance exists, false otherwise.
|
|
@@ -1088,7 +1161,7 @@ module Sequel
|
|
|
1088
1161
|
# Artist.new.exists?
|
|
1089
1162
|
# # => false
|
|
1090
1163
|
def exists?
|
|
1091
|
-
new? ? false : !this.get(1).nil?
|
|
1164
|
+
new? ? false : !this.get(SQL::AliasedExpression.new(1, :one)).nil?
|
|
1092
1165
|
end
|
|
1093
1166
|
|
|
1094
1167
|
# Ignore the model's setter method cache when this instances extends a module, as the
|
|
@@ -1292,6 +1365,7 @@ module Sequel
|
|
|
1292
1365
|
# Takes the following options:
|
|
1293
1366
|
#
|
|
1294
1367
|
# :changed :: save all changed columns, instead of all columns or the columns given
|
|
1368
|
+
# :columns :: array of specific columns that should be saved.
|
|
1295
1369
|
# :raise_on_failure :: set to true or false to override the current
|
|
1296
1370
|
# +raise_on_save_failure+ setting
|
|
1297
1371
|
# :server :: set the server/shard on the object before saving, and use that
|
|
@@ -1302,6 +1376,10 @@ module Sequel
|
|
|
1302
1376
|
def save(*columns)
|
|
1303
1377
|
raise Sequel::Error, "can't save frozen object" if frozen?
|
|
1304
1378
|
opts = columns.last.is_a?(Hash) ? columns.pop : {}
|
|
1379
|
+
|
|
1380
|
+
Sequel::Deprecation.deprecate('Passing columns as separate arguments to Model#save', 'Instead, provide a :columns option with the array of columns to save.') unless columns.empty?
|
|
1381
|
+
columns.concat(Array(opts[:columns])) if opts[:columns]
|
|
1382
|
+
|
|
1305
1383
|
set_server(opts[:server]) if opts[:server]
|
|
1306
1384
|
if opts[:validate] != false
|
|
1307
1385
|
unless checked_save_failure(opts){_valid?(true, opts)}
|
|
@@ -1337,9 +1415,9 @@ module Sequel
|
|
|
1337
1415
|
end
|
|
1338
1416
|
|
|
1339
1417
|
# Set all values using the entries in the hash, ignoring any setting of
|
|
1340
|
-
# allowed_columns
|
|
1418
|
+
# allowed_columns in the model.
|
|
1341
1419
|
#
|
|
1342
|
-
# Artist.
|
|
1420
|
+
# Artist.set_allowed_columns(:num_albums)
|
|
1343
1421
|
# artist.set_all(:name=>'Jim')
|
|
1344
1422
|
# artist.name # => 'Jim'
|
|
1345
1423
|
def set_all(hash)
|
|
@@ -1353,6 +1431,7 @@ module Sequel
|
|
|
1353
1431
|
# artist.set_except({:name=>'Jim'}, :hometown)
|
|
1354
1432
|
# artist.name # => 'Jim'
|
|
1355
1433
|
def set_except(hash, *except)
|
|
1434
|
+
Sequel::Deprecation.deprecate('Model#set_except', 'Please switch to Model#set_only or use the blacklist_security plugin')
|
|
1356
1435
|
set_restricted(hash, false, except.flatten)
|
|
1357
1436
|
end
|
|
1358
1437
|
|
|
@@ -1462,9 +1541,9 @@ module Sequel
|
|
|
1462
1541
|
end
|
|
1463
1542
|
|
|
1464
1543
|
# Update all values using the entries in the hash, ignoring any setting of
|
|
1465
|
-
# +allowed_columns+
|
|
1544
|
+
# +allowed_columns+ in the model.
|
|
1466
1545
|
#
|
|
1467
|
-
# Artist.
|
|
1546
|
+
# Artist.set_allowed_columns(:num_albums)
|
|
1468
1547
|
# artist.update_all(:name=>'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
1469
1548
|
def update_all(hash)
|
|
1470
1549
|
update_restricted(hash, false, false)
|
|
@@ -1476,6 +1555,7 @@ module Sequel
|
|
|
1476
1555
|
#
|
|
1477
1556
|
# artist.update_except({:name=>'Jim'}, :hometown) # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
1478
1557
|
def update_except(hash, *except)
|
|
1558
|
+
Sequel::Deprecation.deprecate('Model#update_except', 'Please switch to Model#update_only or use the blacklist_security plugin')
|
|
1479
1559
|
update_restricted(hash, false, except.flatten)
|
|
1480
1560
|
end
|
|
1481
1561
|
|
|
@@ -1789,6 +1869,11 @@ module Sequel
|
|
|
1789
1869
|
@values[column] = value
|
|
1790
1870
|
end
|
|
1791
1871
|
|
|
1872
|
+
# Default error class used for errors.
|
|
1873
|
+
def errors_class
|
|
1874
|
+
Errors
|
|
1875
|
+
end
|
|
1876
|
+
|
|
1792
1877
|
# Set the columns with the given hash. By default, the same as +set+, but
|
|
1793
1878
|
# exists so it can be overridden. This is called only for new records, before
|
|
1794
1879
|
# changed_columns is cleared.
|
|
@@ -1869,7 +1954,7 @@ module Sequel
|
|
|
1869
1954
|
# well, see Model.unrestrict_primary_key to change this.
|
|
1870
1955
|
def setter_methods(only, except)
|
|
1871
1956
|
only = only.nil? ? model.allowed_columns : only
|
|
1872
|
-
except = except.nil? ? model.
|
|
1957
|
+
except = except.nil? ? model._restricted_columns : except
|
|
1873
1958
|
if only
|
|
1874
1959
|
only.map{|x| "#{x}="}
|
|
1875
1960
|
else
|