sequel 5.83.0 → 5.106.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/MIT-LICENSE +1 -1
- data/lib/sequel/adapters/ado/access.rb +2 -2
- data/lib/sequel/adapters/ado.rb +2 -2
- data/lib/sequel/adapters/amalgalite.rb +16 -1
- data/lib/sequel/adapters/ibmdb.rb +2 -1
- data/lib/sequel/adapters/jdbc/db2.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +4 -2
- data/lib/sequel/adapters/jdbc/h2.rb +4 -4
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -2
- data/lib/sequel/adapters/jdbc/jtds.rb +2 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +3 -3
- data/lib/sequel/adapters/jdbc/oracle.rb +6 -6
- data/lib/sequel/adapters/jdbc/postgresql.rb +5 -5
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +6 -6
- data/lib/sequel/adapters/jdbc/sqlite.rb +3 -3
- data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -3
- data/lib/sequel/adapters/jdbc.rb +29 -15
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +10 -3
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +16 -0
- data/lib/sequel/adapters/postgres.rb +2 -1
- data/lib/sequel/adapters/shared/access.rb +1 -0
- data/lib/sequel/adapters/shared/db2.rb +8 -3
- data/lib/sequel/adapters/shared/mssql.rb +9 -8
- data/lib/sequel/adapters/shared/mysql.rb +16 -11
- data/lib/sequel/adapters/shared/oracle.rb +1 -0
- data/lib/sequel/adapters/shared/postgres.rb +438 -47
- data/lib/sequel/adapters/shared/sqlite.rb +9 -7
- data/lib/sequel/adapters/sqlite.rb +20 -2
- data/lib/sequel/adapters/tinytds.rb +2 -2
- data/lib/sequel/adapters/trilogy.rb +2 -3
- data/lib/sequel/ast_transformer.rb +2 -0
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +42 -11
- data/lib/sequel/connection_pool/timed_queue.rb +33 -10
- data/lib/sequel/connection_pool.rb +8 -2
- data/lib/sequel/core.rb +31 -2
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/dataset_defaults.rb +3 -3
- data/lib/sequel/database/misc.rb +29 -11
- data/lib/sequel/database/query.rb +12 -12
- data/lib/sequel/database/schema_generator.rb +117 -16
- data/lib/sequel/database/schema_methods.rb +85 -30
- data/lib/sequel/dataset/actions.rb +83 -11
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +1 -1
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -0
- data/lib/sequel/dataset/prepared_statements.rb +76 -28
- data/lib/sequel/dataset/query.rb +26 -11
- data/lib/sequel/dataset/sql.rb +40 -17
- data/lib/sequel/extensions/async_thread_pool.rb +1 -1
- data/lib/sequel/extensions/caller_logging.rb +1 -3
- data/lib/sequel/extensions/connection_checkout_event_callback.rb +151 -0
- data/lib/sequel/extensions/connection_expiration.rb +44 -5
- data/lib/sequel/extensions/connection_validator.rb +15 -10
- data/lib/sequel/extensions/constraint_validations.rb +3 -3
- data/lib/sequel/extensions/dataset_run.rb +41 -0
- data/lib/sequel/extensions/date_arithmetic.rb +6 -6
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -0
- data/lib/sequel/extensions/eval_inspect.rb +3 -1
- data/lib/sequel/extensions/inflector.rb +2 -2
- data/lib/sequel/extensions/lit_require_frozen.rb +131 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -12
- data/lib/sequel/extensions/migration.rb +38 -21
- data/lib/sequel/extensions/null_dataset.rb +2 -2
- data/lib/sequel/extensions/pg_array_ops.rb +41 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -3
- data/lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb +191 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +94 -10
- data/lib/sequel/extensions/pg_enum.rb +4 -4
- data/lib/sequel/extensions/pg_hstore.rb +1 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +10 -5
- data/lib/sequel/extensions/pg_json_ops.rb +674 -18
- data/lib/sequel/extensions/pg_multirange.rb +1 -1
- data/lib/sequel/extensions/pg_range.rb +14 -2
- data/lib/sequel/extensions/pg_row.rb +5 -3
- data/lib/sequel/extensions/pg_schema_caching.rb +90 -0
- data/lib/sequel/extensions/provenance.rb +1 -3
- data/lib/sequel/extensions/query_blocker.rb +172 -0
- data/lib/sequel/extensions/schema_caching.rb +24 -9
- data/lib/sequel/extensions/schema_dumper.rb +17 -5
- data/lib/sequel/extensions/set_literalizer.rb +20 -39
- data/lib/sequel/extensions/split_array_nil.rb +12 -2
- data/lib/sequel/extensions/sqlite_json_ops.rb +1 -1
- data/lib/sequel/extensions/string_agg.rb +2 -2
- data/lib/sequel/extensions/to_dot.rb +5 -0
- data/lib/sequel/extensions/virtual_row_method_block.rb +1 -0
- data/lib/sequel/model/associations.rb +215 -15
- data/lib/sequel/model/base.rb +198 -35
- data/lib/sequel/model/plugins.rb +12 -1
- data/lib/sequel/model.rb +1 -0
- data/lib/sequel/plugins/accessed_columns.rb +4 -0
- data/lib/sequel/plugins/active_model.rb +5 -6
- data/lib/sequel/plugins/association_pks.rb +2 -0
- data/lib/sequel/plugins/auto_validations.rb +2 -0
- data/lib/sequel/plugins/class_table_inheritance_constraint_validations.rb +82 -0
- data/lib/sequel/plugins/columns_updated.rb +4 -0
- data/lib/sequel/plugins/composition.rb +3 -1
- data/lib/sequel/plugins/constraint_validations.rb +15 -10
- data/lib/sequel/plugins/dataset_associations.rb +20 -1
- data/lib/sequel/plugins/deprecated_associations.rb +151 -0
- data/lib/sequel/plugins/detect_unnecessary_association_options.rb +164 -0
- data/lib/sequel/plugins/dirty.rb +9 -2
- data/lib/sequel/plugins/enum.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +15 -1
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/insert_returning_select.rb +10 -1
- data/lib/sequel/plugins/inspect_pk.rb +44 -0
- data/lib/sequel/plugins/instance_filters.rb +8 -1
- data/lib/sequel/plugins/instance_hooks.rb +4 -0
- data/lib/sequel/plugins/inverted_subsets.rb +1 -0
- data/lib/sequel/plugins/json_serializer.rb +6 -10
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +21 -0
- data/lib/sequel/plugins/modification_detection.rb +2 -0
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +10 -5
- data/lib/sequel/plugins/paged_operations.rb +5 -2
- data/lib/sequel/plugins/pg_array_associations.rb +2 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +6 -1
- data/lib/sequel/plugins/pg_auto_validate_enums.rb +88 -0
- data/lib/sequel/plugins/pg_eager_any_typed_array.rb +95 -0
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +6 -6
- data/lib/sequel/plugins/serialization.rb +23 -6
- data/lib/sequel/plugins/serialization_modification_detection.rb +4 -0
- data/lib/sequel/plugins/single_statement_dataset_destroy.rb +49 -0
- data/lib/sequel/plugins/split_values.rb +12 -0
- data/lib/sequel/plugins/sql_comments.rb +7 -2
- data/lib/sequel/plugins/static_cache.rb +13 -0
- data/lib/sequel/plugins/static_cache_cache.rb +50 -13
- data/lib/sequel/plugins/subset_conditions.rb +85 -5
- data/lib/sequel/plugins/subset_static_cache.rb +278 -0
- data/lib/sequel/plugins/table_select.rb +7 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +4 -0
- data/lib/sequel/plugins/unused_associations.rb +11 -3
- data/lib/sequel/plugins/update_primary_key.rb +4 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/validation_contexts.rb +4 -0
- data/lib/sequel/sql.rb +27 -12
- data/lib/sequel/version.rb +1 -1
- metadata +17 -240
- data/CHANGELOG +0 -1393
- data/README.rdoc +0 -936
- data/doc/advanced_associations.rdoc +0 -884
- data/doc/association_basics.rdoc +0 -1859
- data/doc/bin_sequel.rdoc +0 -146
- data/doc/cheat_sheet.rdoc +0 -255
- data/doc/code_order.rdoc +0 -104
- data/doc/core_extensions.rdoc +0 -405
- data/doc/dataset_basics.rdoc +0 -96
- data/doc/dataset_filtering.rdoc +0 -222
- data/doc/extensions.rdoc +0 -77
- data/doc/fork_safety.rdoc +0 -84
- data/doc/mass_assignment.rdoc +0 -98
- data/doc/migration.rdoc +0 -660
- data/doc/model_dataset_method_design.rdoc +0 -129
- data/doc/model_hooks.rdoc +0 -254
- data/doc/model_plugins.rdoc +0 -270
- data/doc/mssql_stored_procedures.rdoc +0 -43
- data/doc/object_model.rdoc +0 -563
- data/doc/opening_databases.rdoc +0 -439
- data/doc/postgresql.rdoc +0 -611
- data/doc/prepared_statements.rdoc +0 -144
- data/doc/querying.rdoc +0 -1070
- data/doc/reflection.rdoc +0 -120
- data/doc/release_notes/5.0.0.txt +0 -159
- data/doc/release_notes/5.1.0.txt +0 -31
- data/doc/release_notes/5.10.0.txt +0 -84
- data/doc/release_notes/5.11.0.txt +0 -83
- data/doc/release_notes/5.12.0.txt +0 -141
- data/doc/release_notes/5.13.0.txt +0 -27
- data/doc/release_notes/5.14.0.txt +0 -63
- data/doc/release_notes/5.15.0.txt +0 -39
- data/doc/release_notes/5.16.0.txt +0 -110
- data/doc/release_notes/5.17.0.txt +0 -31
- data/doc/release_notes/5.18.0.txt +0 -69
- data/doc/release_notes/5.19.0.txt +0 -28
- data/doc/release_notes/5.2.0.txt +0 -33
- data/doc/release_notes/5.20.0.txt +0 -89
- data/doc/release_notes/5.21.0.txt +0 -87
- data/doc/release_notes/5.22.0.txt +0 -48
- data/doc/release_notes/5.23.0.txt +0 -56
- data/doc/release_notes/5.24.0.txt +0 -56
- data/doc/release_notes/5.25.0.txt +0 -32
- data/doc/release_notes/5.26.0.txt +0 -35
- data/doc/release_notes/5.27.0.txt +0 -21
- data/doc/release_notes/5.28.0.txt +0 -16
- data/doc/release_notes/5.29.0.txt +0 -22
- data/doc/release_notes/5.3.0.txt +0 -121
- data/doc/release_notes/5.30.0.txt +0 -20
- data/doc/release_notes/5.31.0.txt +0 -148
- data/doc/release_notes/5.32.0.txt +0 -46
- data/doc/release_notes/5.33.0.txt +0 -24
- data/doc/release_notes/5.34.0.txt +0 -40
- data/doc/release_notes/5.35.0.txt +0 -56
- data/doc/release_notes/5.36.0.txt +0 -60
- data/doc/release_notes/5.37.0.txt +0 -30
- data/doc/release_notes/5.38.0.txt +0 -28
- data/doc/release_notes/5.39.0.txt +0 -19
- data/doc/release_notes/5.4.0.txt +0 -80
- data/doc/release_notes/5.40.0.txt +0 -40
- data/doc/release_notes/5.41.0.txt +0 -25
- data/doc/release_notes/5.42.0.txt +0 -136
- data/doc/release_notes/5.43.0.txt +0 -98
- data/doc/release_notes/5.44.0.txt +0 -32
- data/doc/release_notes/5.45.0.txt +0 -34
- data/doc/release_notes/5.46.0.txt +0 -87
- data/doc/release_notes/5.47.0.txt +0 -59
- data/doc/release_notes/5.48.0.txt +0 -14
- data/doc/release_notes/5.49.0.txt +0 -59
- data/doc/release_notes/5.5.0.txt +0 -61
- data/doc/release_notes/5.50.0.txt +0 -78
- data/doc/release_notes/5.51.0.txt +0 -47
- data/doc/release_notes/5.52.0.txt +0 -87
- data/doc/release_notes/5.53.0.txt +0 -23
- data/doc/release_notes/5.54.0.txt +0 -27
- data/doc/release_notes/5.55.0.txt +0 -21
- data/doc/release_notes/5.56.0.txt +0 -51
- data/doc/release_notes/5.57.0.txt +0 -23
- data/doc/release_notes/5.58.0.txt +0 -31
- data/doc/release_notes/5.59.0.txt +0 -73
- data/doc/release_notes/5.6.0.txt +0 -31
- data/doc/release_notes/5.60.0.txt +0 -22
- data/doc/release_notes/5.61.0.txt +0 -43
- data/doc/release_notes/5.62.0.txt +0 -132
- data/doc/release_notes/5.63.0.txt +0 -33
- data/doc/release_notes/5.64.0.txt +0 -50
- data/doc/release_notes/5.65.0.txt +0 -21
- data/doc/release_notes/5.66.0.txt +0 -24
- data/doc/release_notes/5.67.0.txt +0 -32
- data/doc/release_notes/5.68.0.txt +0 -61
- data/doc/release_notes/5.69.0.txt +0 -26
- data/doc/release_notes/5.7.0.txt +0 -108
- data/doc/release_notes/5.70.0.txt +0 -35
- data/doc/release_notes/5.71.0.txt +0 -21
- data/doc/release_notes/5.72.0.txt +0 -33
- data/doc/release_notes/5.73.0.txt +0 -66
- data/doc/release_notes/5.74.0.txt +0 -45
- data/doc/release_notes/5.75.0.txt +0 -35
- data/doc/release_notes/5.76.0.txt +0 -86
- data/doc/release_notes/5.77.0.txt +0 -63
- data/doc/release_notes/5.78.0.txt +0 -67
- data/doc/release_notes/5.79.0.txt +0 -28
- data/doc/release_notes/5.8.0.txt +0 -170
- data/doc/release_notes/5.80.0.txt +0 -40
- data/doc/release_notes/5.81.0.txt +0 -31
- data/doc/release_notes/5.82.0.txt +0 -61
- data/doc/release_notes/5.83.0.txt +0 -56
- data/doc/release_notes/5.9.0.txt +0 -99
- data/doc/schema_modification.rdoc +0 -679
- data/doc/security.rdoc +0 -443
- data/doc/sharding.rdoc +0 -286
- data/doc/sql.rdoc +0 -648
- data/doc/testing.rdoc +0 -204
- data/doc/thread_safety.rdoc +0 -15
- data/doc/transactions.rdoc +0 -250
- data/doc/validations.rdoc +0 -558
- data/doc/virtual_rows.rdoc +0 -265
|
@@ -146,6 +146,27 @@ module Sequel
|
|
|
146
146
|
ds
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
+
def lateral_subquery_filter_limit_strategy_conditions_key
|
|
150
|
+
qualify(reverse_edges.first[:table], reverse_edges.first[:left])
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def lateral_subquery_filter_limit_strategy_filter_lateral_dataset(ds)
|
|
154
|
+
ds.where(Array(qualify(edges.first[:table], edges.first[:right])).zip(Array(qualify(self[:model].table_name, edges.first[:left]))))
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def lateral_subquery_filter_limit_strategy_filter_dataset(ds, obj)
|
|
158
|
+
first_edge, *remaining_edges = edges
|
|
159
|
+
filter_ds = ds.db.from(first_edge[:table]).
|
|
160
|
+
select(*qualify(first_edge[:table], first_edge[:right])).
|
|
161
|
+
where(lateral_subquery_filter_limit_strategy_conditions(obj))
|
|
162
|
+
|
|
163
|
+
remaining_edges.each do |edge|
|
|
164
|
+
filter_ds = filter_ds.join(edge[:table], Array(edge[:right]).zip(Array(edge[:left])))
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
ds.where(qualify(self[:model].table_name, self[:left_primary_key]) => filter_ds)
|
|
168
|
+
end
|
|
169
|
+
|
|
149
170
|
# Make sure to use unique table aliases when lazy loading or eager loading
|
|
150
171
|
def calculate_reverse_edge_aliases(reverse_edges)
|
|
151
172
|
aliases = [associated_class.table_name]
|
|
@@ -34,6 +34,8 @@ module Sequel
|
|
|
34
34
|
# Album.plugin :modification_detection
|
|
35
35
|
module ModificationDetection
|
|
36
36
|
module ClassMethods
|
|
37
|
+
Plugins.model_instance_variables(self, :@values_hashes)
|
|
38
|
+
|
|
37
39
|
# Calculate the hashes for all of the column values, so that they
|
|
38
40
|
# can be compared later to determine if the column value has changed.
|
|
39
41
|
def call(_)
|
|
@@ -55,7 +55,7 @@ module Sequel
|
|
|
55
55
|
def _update_without_checking(columns)
|
|
56
56
|
ds = _update_dataset
|
|
57
57
|
lc = model.lock_column
|
|
58
|
-
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.output(nil, [Sequel[:inserted][lc]]).update_sql(columns))).all
|
|
58
|
+
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.output(nil, [Sequel[:inserted][lc]]).update_sql(columns).freeze)).all
|
|
59
59
|
values[lc] = rows.first[lc] unless rows.empty?
|
|
60
60
|
rows.length
|
|
61
61
|
end
|
|
@@ -129,7 +129,7 @@ module Sequel
|
|
|
129
129
|
#
|
|
130
130
|
# If a block is provided, it is used to set the :reject_if option.
|
|
131
131
|
def nested_attributes(*associations, &block)
|
|
132
|
-
include(@nested_attributes_module ||= Module.new) unless @nested_attributes_module
|
|
132
|
+
include(@nested_attributes_module ||= Sequel.set_temp_name(Module.new){"#{name}::@nested_attributes_module"}) unless @nested_attributes_module
|
|
133
133
|
opts = associations.last.is_a?(Hash) ? associations.pop : OPTS
|
|
134
134
|
reflections = associations.map{|a| association_reflection(a) || raise(Error, "no association named #{a} for #{self}")}
|
|
135
135
|
reflections.each do |r|
|
|
@@ -188,11 +188,10 @@ module Sequel
|
|
|
188
188
|
|
|
189
189
|
# Create a new associated object with the given attributes, validate
|
|
190
190
|
# it when the parent is validated, and save it when the object is saved.
|
|
191
|
-
# Returns the object
|
|
191
|
+
# Returns the new object.
|
|
192
192
|
def nested_attributes_create(meta, attributes)
|
|
193
|
+
obj = nested_attributes_new(meta, attributes)
|
|
193
194
|
reflection = meta[:reflection]
|
|
194
|
-
obj = reflection.associated_class.new
|
|
195
|
-
nested_attributes_set_attributes(meta, obj, attributes)
|
|
196
195
|
delay_validate_associated_object(reflection, obj)
|
|
197
196
|
if reflection.returns_array?
|
|
198
197
|
public_send(reflection[:name]) << obj
|
|
@@ -254,7 +253,13 @@ module Sequel
|
|
|
254
253
|
end
|
|
255
254
|
obj
|
|
256
255
|
end
|
|
257
|
-
|
|
256
|
+
|
|
257
|
+
# Returns a new object of the associated class with the given attributes set.
|
|
258
|
+
def nested_attributes_new(meta, attributes)
|
|
259
|
+
obj = meta[:reflection].associated_class.new
|
|
260
|
+
nested_attributes_set_attributes(meta, obj, attributes)
|
|
261
|
+
end
|
|
262
|
+
|
|
258
263
|
# Set the fields in the obj based on the association, only allowing
|
|
259
264
|
# specific :fields if configured.
|
|
260
265
|
def nested_attributes_set_attributes(meta, obj, attributes)
|
|
@@ -157,13 +157,16 @@ module Sequel
|
|
|
157
157
|
raise Error, "the paged_operations plugin is not supported on DB2 when using emulated offsets, set the :offset_strategy Database option to 'limit_offset' or 'offset_fetch'"
|
|
158
158
|
end
|
|
159
159
|
|
|
160
|
-
case pk =
|
|
160
|
+
case pk = unambiguous_primary_key
|
|
161
161
|
when Symbol
|
|
162
162
|
Sequel.identifier(pk)
|
|
163
163
|
when Array
|
|
164
164
|
raise Error, "cannot use #{meth} on a model with a composite primary key"
|
|
165
|
-
|
|
165
|
+
when nil
|
|
166
166
|
raise Error, "cannot use #{meth} on a model without a primary key"
|
|
167
|
+
else
|
|
168
|
+
# Likely SQL::QualifiedIdentifier, if the dataset is joined.
|
|
169
|
+
pk
|
|
167
170
|
end
|
|
168
171
|
end
|
|
169
172
|
|
|
@@ -541,7 +541,7 @@ module Sequel
|
|
|
541
541
|
if (assoc_pks = obj.get_column_value(key)) && !assoc_pks.empty?
|
|
542
542
|
Sequel[pk=>assoc_pks.to_a]
|
|
543
543
|
end
|
|
544
|
-
when Array
|
|
544
|
+
when Array, Set
|
|
545
545
|
if (assoc_pks = obj.map{|o| o.get_column_value(key)}.flatten.compact.uniq) && !assoc_pks.empty?
|
|
546
546
|
Sequel[pk=>assoc_pks]
|
|
547
547
|
end
|
|
@@ -563,7 +563,7 @@ module Sequel
|
|
|
563
563
|
if pkv = obj.get_column_value(ref.primary_key_method)
|
|
564
564
|
Sequel.pg_array_op(key).contains(Sequel.pg_array([pkv], ref.array_type))
|
|
565
565
|
end
|
|
566
|
-
when Array
|
|
566
|
+
when Array, Set
|
|
567
567
|
if (pkvs = obj.map{|o| o.get_column_value(ref.primary_key_method)}.compact) && !pkvs.empty?
|
|
568
568
|
Sequel.pg_array(key).overlaps(Sequel.pg_array(pkvs, ref.array_type))
|
|
569
569
|
end
|
|
@@ -135,7 +135,12 @@ module Sequel
|
|
|
135
135
|
raise Error, "No pg_auto_constraint_validations setup" unless file = @pg_auto_constraint_validations_cache_file
|
|
136
136
|
pg_auto_constraint_validations_cache = {}
|
|
137
137
|
@pg_auto_constraint_validations_cache.sort.each do |k, v|
|
|
138
|
-
|
|
138
|
+
h = {}
|
|
139
|
+
v.each do |k, entry|
|
|
140
|
+
entry = Hash[entry.sort] if entry.is_a?(Hash)
|
|
141
|
+
h[k] = entry
|
|
142
|
+
end
|
|
143
|
+
pg_auto_constraint_validations_cache[k] = h
|
|
139
144
|
end
|
|
140
145
|
File.open(file, 'wb'){|f| f.write(Marshal.dump(pg_auto_constraint_validations_cache))}
|
|
141
146
|
nil
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module Plugins
|
|
5
|
+
# The pg_auto_validate_enums plugin implements automatic validations for
|
|
6
|
+
# enum columns, ensuring that enum columns have a valid value. With this
|
|
7
|
+
# plugin, trying to save with an invalid enum value results in
|
|
8
|
+
# Sequel::ValidationFailed before saving, instead of Sequel::DatabaseError
|
|
9
|
+
# (wrapping PG::InvalidTextRepresentation or similar exception) during saving.
|
|
10
|
+
#
|
|
11
|
+
# class Person < Sequel::Model
|
|
12
|
+
# # assume state enum column with allowed values active and inactive
|
|
13
|
+
# plugin :pg_auto_validate_enums
|
|
14
|
+
# end
|
|
15
|
+
# p = Person.new(state: "active").valid? # => true
|
|
16
|
+
# p = Person.new(state: "inactive").valid? # => true
|
|
17
|
+
# p = Person.new(state: "other").valid? # => false
|
|
18
|
+
#
|
|
19
|
+
# While you can load this into individual model classes, typical use would
|
|
20
|
+
# be to load it into Sequel::Model or the appropriate model base class,
|
|
21
|
+
# and have all models that inherit from that class automatically pick it up.
|
|
22
|
+
#
|
|
23
|
+
# This plugin depends on the validation_helpers plugin.
|
|
24
|
+
module PgAutoValidateEnums
|
|
25
|
+
# Load the validation_helpers plugin.
|
|
26
|
+
def self.apply(model, opts=OPTS)
|
|
27
|
+
model.plugin(:validation_helpers)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Load the pg_enum extension into the database, and reload the schema
|
|
31
|
+
# if it is already loaded. The opts given are used for the validates_includes
|
|
32
|
+
# validations (with allow_nil: true and from: :values enabled by default,
|
|
33
|
+
# to avoid issues with nullable enum columns and cases where the column
|
|
34
|
+
# method has been overridden.
|
|
35
|
+
def self.configure(model, opts=OPTS)
|
|
36
|
+
model.instance_exec do
|
|
37
|
+
db.extension(:pg_enum) unless @db.instance_variable_get(:@enum_labels)
|
|
38
|
+
if @db_schema
|
|
39
|
+
get_db_schema(true)
|
|
40
|
+
_get_pg_pg_auto_validate_enums_metadata
|
|
41
|
+
end
|
|
42
|
+
@pg_auto_validate_enums_opts = {allow_nil: true, from: :values}.merge!(opts).freeze
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
module ClassMethods
|
|
47
|
+
# Hash with enum column symbol values and arrays of valid string values.
|
|
48
|
+
attr_reader :pg_auto_validate_enums_metadata
|
|
49
|
+
|
|
50
|
+
# Options to pass to the validates_includes calls used by the plugin.
|
|
51
|
+
attr_reader :pg_auto_validate_enums_opts
|
|
52
|
+
|
|
53
|
+
Plugins.after_set_dataset(self, :_get_pg_pg_auto_validate_enums_metadata)
|
|
54
|
+
|
|
55
|
+
Plugins.inherited_instance_variables(self,
|
|
56
|
+
:@pg_auto_validate_enums_metadata=>nil,
|
|
57
|
+
:@pg_auto_validate_enums_opts=>nil)
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
# Parse the column schema to find columns with :enum_values entries,
|
|
62
|
+
# which will be used to setup validations.
|
|
63
|
+
def _get_pg_pg_auto_validate_enums_metadata
|
|
64
|
+
metadata = {}
|
|
65
|
+
@db_schema.each do |key, sch|
|
|
66
|
+
if enum_values = sch[:enum_values]
|
|
67
|
+
metadata[key] = enum_values
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
@pg_auto_validate_enums_metadata = metadata.freeze
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
module InstanceMethods
|
|
75
|
+
# Validate that all of the model's enum columns have valid values.
|
|
76
|
+
def validate
|
|
77
|
+
super
|
|
78
|
+
|
|
79
|
+
klass = self.class
|
|
80
|
+
opts = klass.pg_auto_validate_enums_opts
|
|
81
|
+
klass.pg_auto_validate_enums_metadata.each do |column, values|
|
|
82
|
+
validates_includes(values, column, opts)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module Plugins
|
|
5
|
+
# The pg_eager_any_typed_array plugin automatically converts
|
|
6
|
+
# the predicate expressions used for eager loading from:
|
|
7
|
+
#
|
|
8
|
+
# table.column IN (value_list)
|
|
9
|
+
#
|
|
10
|
+
# to:
|
|
11
|
+
#
|
|
12
|
+
# table.column = ANY(array_expr::type[])
|
|
13
|
+
#
|
|
14
|
+
# This makes it easier to use the pg_auto_parameterize_in_array
|
|
15
|
+
# extension with the :treat_string_list_as_text_array option,
|
|
16
|
+
# when using foreign keys with non-text database types that are represented
|
|
17
|
+
# by Ruby strings, such as enum and uuid types.
|
|
18
|
+
#
|
|
19
|
+
# Most association types that ship with Sequel have their predicate
|
|
20
|
+
# expressions converted by this plugin. Here are the exceptions:
|
|
21
|
+
#
|
|
22
|
+
# * associations using composite predicate keys
|
|
23
|
+
# * many_to_pg_array associations
|
|
24
|
+
# * many_to_many/one_through_one associations using :join_table_db option
|
|
25
|
+
# * many_through_many/one_through_many associations using
|
|
26
|
+
# :separate_table_per_query option
|
|
27
|
+
#
|
|
28
|
+
# To avoid predicate conversion for particular associations, set the
|
|
29
|
+
# :eager_loading_predicate_transform association option to nil/false.
|
|
30
|
+
#
|
|
31
|
+
# This plugin loads the pg_array extension into the model's Database.
|
|
32
|
+
module PgEagerAnyTypedArray
|
|
33
|
+
# Add the pg_array extension to the database
|
|
34
|
+
def self.apply(model)
|
|
35
|
+
model.db.extension(:pg_array)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module ClassMethods
|
|
39
|
+
TRANSFORM = proc do |values, ref|
|
|
40
|
+
type = ref.send(:cached_fetch, :_pg_eager_any_typed_array_type) do
|
|
41
|
+
key = ref.predicate_key
|
|
42
|
+
next if key.is_a?(Array)
|
|
43
|
+
|
|
44
|
+
while key.is_a?(SQL::QualifiedIdentifier)
|
|
45
|
+
key = key.column
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# :nocov:
|
|
49
|
+
# many_to_pg_array association type does not need changes, as it
|
|
50
|
+
# already converts the values to a typed postgres array, it does
|
|
51
|
+
# not call the code that uses :eager_loading_predicate_transform.
|
|
52
|
+
#
|
|
53
|
+
# No association type that ships with Sequel can reach this code
|
|
54
|
+
# unless it is one of these types, but external association types
|
|
55
|
+
# could potentially reach it.
|
|
56
|
+
sch = case ref[:type]
|
|
57
|
+
# :nocov:
|
|
58
|
+
when :many_to_one, :one_to_one, :one_to_many, :pg_array_to_many
|
|
59
|
+
ref.associated_class.db_schema
|
|
60
|
+
when :many_to_many, :one_through_one
|
|
61
|
+
# Not compatible with the :join_table_db option, but that option
|
|
62
|
+
# does not call into this code.
|
|
63
|
+
Hash[ref.associated_class.db.schema(ref.join_table_source)]
|
|
64
|
+
when :many_through_many, :one_through_many
|
|
65
|
+
# Not compatible with the :separate_query_per_table option, but
|
|
66
|
+
# that option does not call into this code.
|
|
67
|
+
Hash[ref.associated_class.db.schema(ref[:through][0][:table])]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if sch && (sch = sch[key])
|
|
71
|
+
sch[:db_type]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
if type
|
|
76
|
+
Sequel.function(:ANY, Sequel.pg_array(values, type))
|
|
77
|
+
else
|
|
78
|
+
values
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Set the :eager_loading_predicate_transform option if not already set
|
|
83
|
+
def associate(type, name, opts = OPTS, &block)
|
|
84
|
+
res = super
|
|
85
|
+
|
|
86
|
+
unless res.has_key?(:eager_loading_predicate_transform)
|
|
87
|
+
res[:eager_loading_predicate_transform] = TRANSFORM
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
res
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -99,7 +99,7 @@ module Sequel
|
|
|
99
99
|
# Add an RETURNING clause to fetch the updated xmin when updating the row.
|
|
100
100
|
def _update_without_checking(columns)
|
|
101
101
|
ds = _update_dataset
|
|
102
|
-
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.returning(:xmin).update_sql(columns))).all
|
|
102
|
+
rows = ds.clone(ds.send(:default_server_opts, :sql=>ds.returning(:xmin).update_sql(columns).freeze)).all
|
|
103
103
|
values[:xmin] = rows.first[:xmin] unless rows.empty?
|
|
104
104
|
rows.length
|
|
105
105
|
end
|
|
@@ -81,7 +81,7 @@ module Sequel
|
|
|
81
81
|
|
|
82
82
|
opts = opts.dup
|
|
83
83
|
opts[:class] = model
|
|
84
|
-
opts[:methods_module] = Module.new
|
|
84
|
+
opts[:methods_module] = Sequel.set_temp_name(Module.new){"#{model.name}::_rcte_tree[:methods_module]"}
|
|
85
85
|
opts[:union_all] = opts[:union_all].nil? ? true : opts[:union_all]
|
|
86
86
|
model.send(:include, opts[:methods_module])
|
|
87
87
|
|
|
@@ -111,7 +111,7 @@ module Sequel
|
|
|
111
111
|
ancestor_base_case_columns = prkey_array.zip(key_aliases).map{|k, ka_| SQL::AliasedExpression.new(k, ka_)} + c_all
|
|
112
112
|
descendant_base_case_columns = key_array.zip(key_aliases).map{|k, ka_| SQL::AliasedExpression.new(k, ka_)} + c_all
|
|
113
113
|
recursive_case_columns = prkey_array.zip(key_aliases).map{|k, ka_| SQL::QualifiedIdentifier.new(t, ka_)} + c_all
|
|
114
|
-
extract_key_alias = lambda{|m| key_aliases.map{|ka_| bd_conv[m.
|
|
114
|
+
extract_key_alias = lambda{|m| key_aliases.map{|ka_| bd_conv[m.remove_key!(ka_)]}}
|
|
115
115
|
else
|
|
116
116
|
key_present = key_conv = lambda{|m| m[key]}
|
|
117
117
|
prkey_conv = lambda{|m| m[prkey]}
|
|
@@ -119,7 +119,7 @@ module Sequel
|
|
|
119
119
|
ancestor_base_case_columns = [SQL::AliasedExpression.new(prkey, ka)] + c_all
|
|
120
120
|
descendant_base_case_columns = [SQL::AliasedExpression.new(key, ka)] + c_all
|
|
121
121
|
recursive_case_columns = [SQL::QualifiedIdentifier.new(t, ka)] + c_all
|
|
122
|
-
extract_key_alias = lambda{|m| bd_conv[m.
|
|
122
|
+
extract_key_alias = lambda{|m| bd_conv[m.remove_key!(ka)]}
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
parent = opts.merge(opts.fetch(:parent, OPTS)).fetch(:name, :parent)
|
|
@@ -200,7 +200,7 @@ module Sequel
|
|
|
200
200
|
model.eager_load_results(r, eo.merge(:loader=>false, :initialize_rows=>false, :dataset=>ds, :id_map=>nil)) do |obj|
|
|
201
201
|
opk = prkey_conv[obj]
|
|
202
202
|
if idm_obj = parent_map[opk]
|
|
203
|
-
key_aliases.each{|ka_| idm_obj
|
|
203
|
+
key_aliases.each{|ka_| idm_obj[ka_] = obj[ka_]}
|
|
204
204
|
obj = idm_obj
|
|
205
205
|
else
|
|
206
206
|
obj.associations[parent] = nil
|
|
@@ -307,12 +307,12 @@ module Sequel
|
|
|
307
307
|
ds = ds.select_append(ka) unless ds.opts[:select] == nil
|
|
308
308
|
model.eager_load_results(r, eo.merge(:loader=>false, :initialize_rows=>false, :dataset=>ds, :id_map=>nil, :associations=>OPTS)) do |obj|
|
|
309
309
|
if level
|
|
310
|
-
no_cache = no_cache_level == obj.
|
|
310
|
+
no_cache = no_cache_level == obj.remove_key!(la)
|
|
311
311
|
end
|
|
312
312
|
|
|
313
313
|
opk = prkey_conv[obj]
|
|
314
314
|
if idm_obj = parent_map[opk]
|
|
315
|
-
key_aliases.each{|ka_| idm_obj
|
|
315
|
+
key_aliases.each{|ka_| idm_obj[ka_] = obj[ka_]}
|
|
316
316
|
obj = idm_obj
|
|
317
317
|
else
|
|
318
318
|
obj.associations[childrena] = [] unless no_cache
|
|
@@ -30,6 +30,15 @@ module Sequel
|
|
|
30
30
|
# Otherwise, it is possible that the default column accessors will take
|
|
31
31
|
# precedence.
|
|
32
32
|
#
|
|
33
|
+
# Note that use of an unsafe serialization method can result in an attack vector
|
|
34
|
+
# (potentially allowing remote code execution) if an attacker has the ability to
|
|
35
|
+
# store data directly in the underlying column. This would affect the marshal
|
|
36
|
+
# serialization format, and on older versions of Ruby, potentially the yaml and
|
|
37
|
+
# json serialization formats as well. It can also affect custom formats. You
|
|
38
|
+
# should ensure that attackers do not have access to store data directly in the
|
|
39
|
+
# underlying column when using this plugin (especially when using an unsafe
|
|
40
|
+
# serialization method).
|
|
41
|
+
#
|
|
33
42
|
# == Example
|
|
34
43
|
#
|
|
35
44
|
# # Require json if you plan to use it, as the plugin doesn't require it for you.
|
|
@@ -37,7 +46,8 @@ module Sequel
|
|
|
37
46
|
#
|
|
38
47
|
# # Register custom serializer/deserializer pair, if desired
|
|
39
48
|
# require 'sequel/plugins/serialization'
|
|
40
|
-
#
|
|
49
|
+
# require 'base64'
|
|
50
|
+
# Sequel::Plugins::Serialization.register_format(:base64, Base64.method(:encode64), Base64.method(:decode64))
|
|
41
51
|
#
|
|
42
52
|
# class User < Sequel::Model
|
|
43
53
|
# # Built-in format support when loading the plugin
|
|
@@ -48,10 +58,10 @@ module Sequel
|
|
|
48
58
|
# serialize_attributes :marshal, :permissions
|
|
49
59
|
#
|
|
50
60
|
# # Use custom registered serialization format just like built-in format
|
|
51
|
-
# serialize_attributes :
|
|
61
|
+
# serialize_attributes :base64, :password
|
|
52
62
|
#
|
|
53
63
|
# # Use a custom serializer/deserializer pair without registering
|
|
54
|
-
# serialize_attributes [:
|
|
64
|
+
# serialize_attributes [ Base64.method(:encode64), Base64.method(:decode64)], :password
|
|
55
65
|
# end
|
|
56
66
|
# user = User.create
|
|
57
67
|
# user.permissions = {global: 'read-only'}
|
|
@@ -96,13 +106,15 @@ module Sequel
|
|
|
96
106
|
register_format(:marshal, lambda{|v| [Marshal.dump(v)].pack('m')},
|
|
97
107
|
lambda do |v|
|
|
98
108
|
# Handle unpacked marshalled data for backwards compat
|
|
99
|
-
v = v.unpack('m')[0] unless v
|
|
109
|
+
v = v.unpack('m')[0] unless v.start_with?("\x04\x08")
|
|
100
110
|
Marshal.load(v)
|
|
101
111
|
end)
|
|
102
112
|
register_format(:yaml, :to_yaml.to_proc, lambda{|s| YAML.load(s)})
|
|
103
113
|
register_format(:json, Sequel.method(:object_to_json), Sequel.method(:parse_json))
|
|
104
114
|
|
|
105
115
|
module ClassMethods
|
|
116
|
+
Plugins.model_instance_variables(self, :@deserialized_values)
|
|
117
|
+
|
|
106
118
|
# A hash with column name symbols and callable values, with the value
|
|
107
119
|
# called to deserialize the column.
|
|
108
120
|
attr_reader :deserialization_map
|
|
@@ -123,7 +135,12 @@ module Sequel
|
|
|
123
135
|
end
|
|
124
136
|
|
|
125
137
|
# Create instance level reader that deserializes column values on request,
|
|
126
|
-
# and instance level writer that stores new deserialized values.
|
|
138
|
+
# and instance level writer that stores new deserialized values. If +format+
|
|
139
|
+
# is a symbol, it should correspond to a previously-registered format using +register_format+.
|
|
140
|
+
# Otherwise, +format+ is expected to be a 2-element array of callables,
|
|
141
|
+
# with the first element being the serializer, used to convert the value used by the application
|
|
142
|
+
# to the value that will be stored in the database, and the second element being the deserializer,
|
|
143
|
+
# used to convert the value stored the database to the value used by the application.
|
|
127
144
|
def serialize_attributes(format, *columns)
|
|
128
145
|
if format.is_a?(Symbol)
|
|
129
146
|
unless format = Sequel.synchronize{REGISTERED_FORMATS[format]}
|
|
@@ -140,7 +157,7 @@ module Sequel
|
|
|
140
157
|
# Add serializated attribute acessor methods to the serialization_module
|
|
141
158
|
def define_serialized_attribute_accessor(serializer, deserializer, *columns)
|
|
142
159
|
m = self
|
|
143
|
-
include(@serialization_module ||= Module.new) unless @serialization_module
|
|
160
|
+
include(@serialization_module ||= Sequel.set_temp_name(Module.new){"#{name}::@serialization_module"}) unless @serialization_module
|
|
144
161
|
@serialization_module.class_eval do
|
|
145
162
|
columns.each do |column|
|
|
146
163
|
m.serialization_map[column] = serializer
|
|
@@ -30,6 +30,10 @@ module Sequel
|
|
|
30
30
|
def self.apply(model)
|
|
31
31
|
model.plugin :serialization
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
module ClassMethods
|
|
35
|
+
Plugins.model_instance_variables(self, :@original_deserialized_values)
|
|
36
|
+
end
|
|
33
37
|
|
|
34
38
|
module InstanceMethods
|
|
35
39
|
# Clear the cache of original deserialized values after saving so that it doesn't
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module Plugins
|
|
5
|
+
# The single_statement_dataset_destroy plugin makes the
|
|
6
|
+
# model dataset.destroy method delete all rows in a
|
|
7
|
+
# single DELETE statement. It runs all before_destroy
|
|
8
|
+
# hooks before the DELETE, and all after_destroy hooks
|
|
9
|
+
# after the delete.
|
|
10
|
+
#
|
|
11
|
+
# This is not compatible with around_destroy hooks,
|
|
12
|
+
# so if the model is using custom around_destroy hooks,
|
|
13
|
+
# dataset.destroy falls back to a separate DELETE statement
|
|
14
|
+
# per row.
|
|
15
|
+
#
|
|
16
|
+
# Usage:
|
|
17
|
+
#
|
|
18
|
+
# # Make all model subclasses use a single DELETE
|
|
19
|
+
# # statement for dataset.destroy
|
|
20
|
+
# Sequel::Model.plugin :single_statement_dataset_destroy
|
|
21
|
+
#
|
|
22
|
+
# # Make the Album class use a single DELETE
|
|
23
|
+
# # statement for dataset.destroy
|
|
24
|
+
# Album.plugin :single_statement_dataset_destroy
|
|
25
|
+
module SingleStatementDatasetDestroy
|
|
26
|
+
module DatasetMethods
|
|
27
|
+
# Destroy all rows in a single DELETE statement. Run the before_destroy
|
|
28
|
+
# hooks for all rows before the DELETE, and all after_destroy hooks
|
|
29
|
+
# for all rows after the DELETE. If the model uses an around_destroy
|
|
30
|
+
# hook, fallback to using a separate DELETE statement per row.
|
|
31
|
+
def destroy
|
|
32
|
+
return super unless model.instance_method(:around_destroy).owner == Sequel::Model::InstanceMethods
|
|
33
|
+
|
|
34
|
+
db.transaction do
|
|
35
|
+
rows = all
|
|
36
|
+
rows.each(&:before_destroy)
|
|
37
|
+
expected_rows = rows.length
|
|
38
|
+
n = delete
|
|
39
|
+
unless n == expected_rows
|
|
40
|
+
raise Error, "dataset changed during destroy, expected rows: #{expected_rows}, actual rows: #{n}"
|
|
41
|
+
end
|
|
42
|
+
rows.each(&:after_destroy)
|
|
43
|
+
n
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -36,6 +36,8 @@ module Sequel
|
|
|
36
36
|
# Album.plugin :split_values
|
|
37
37
|
module SplitValues
|
|
38
38
|
module ClassMethods
|
|
39
|
+
Plugins.model_instance_variables(self, :@noncolumn_values)
|
|
40
|
+
|
|
39
41
|
# Split the noncolumn values when creating a new object retrieved from
|
|
40
42
|
# the database.
|
|
41
43
|
def call(_)
|
|
@@ -54,6 +56,16 @@ module Sequel
|
|
|
54
56
|
end
|
|
55
57
|
end
|
|
56
58
|
|
|
59
|
+
# Remove the key from noncolumn values if it is present there. If it is not
|
|
60
|
+
# present there, then use the default behavior of removing it from values.
|
|
61
|
+
def remove_key!(key)
|
|
62
|
+
if @noncolumn_values && @noncolumn_values.key?(key)
|
|
63
|
+
@noncolumn_values.delete(key)
|
|
64
|
+
else
|
|
65
|
+
super
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
57
69
|
# Check all entries in the values hash. If any of the keys are not columns,
|
|
58
70
|
# move the entry into the noncolumn_values hash.
|
|
59
71
|
def split_noncolumn_values
|
|
@@ -40,7 +40,8 @@ module Sequel
|
|
|
40
40
|
# Album.sql_comments_dataset_methods :to_csv # csv_serializer plugin
|
|
41
41
|
#
|
|
42
42
|
# In order for the sql_comments plugin to work, the sql_comments
|
|
43
|
-
# Database extension must be loaded into the model's database
|
|
43
|
+
# Database extension must be loaded into the model's database, so
|
|
44
|
+
# loading the plugin does this automatically.
|
|
44
45
|
#
|
|
45
46
|
# Note that in order to make sure SQL comments are included, some
|
|
46
47
|
# optimizations are disabled if this plugin is loaded.
|
|
@@ -67,6 +68,10 @@ module Sequel
|
|
|
67
68
|
# :nocov:
|
|
68
69
|
end
|
|
69
70
|
|
|
71
|
+
def self.apply(model)
|
|
72
|
+
model.db.extension(:sql_comments)
|
|
73
|
+
end
|
|
74
|
+
|
|
70
75
|
def self.configure(model)
|
|
71
76
|
model.send(:reset_fast_pk_lookup_sql)
|
|
72
77
|
end
|
|
@@ -85,7 +90,7 @@ module Sequel
|
|
|
85
90
|
# Use automatic SQL comments for the given dataset methods.
|
|
86
91
|
def sql_comments_dataset_methods(*meths)
|
|
87
92
|
unless @_sql_comments_dataset_module
|
|
88
|
-
dataset_module(@_sql_comments_dataset_module = Module.new)
|
|
93
|
+
dataset_module(@_sql_comments_dataset_module = Sequel.set_temp_name(Module.new){"#{name}::@_sql_comments_dataset_module"})
|
|
89
94
|
end
|
|
90
95
|
_sql_comments_methods(@_sql_comments_dataset_module, :dataset, meths)
|
|
91
96
|
end
|
|
@@ -176,6 +176,19 @@ module Sequel
|
|
|
176
176
|
h
|
|
177
177
|
end
|
|
178
178
|
|
|
179
|
+
# Use the cache instead of a query to get the results.
|
|
180
|
+
def as_set(column)
|
|
181
|
+
set = Set.new
|
|
182
|
+
|
|
183
|
+
if column.is_a?(Array)
|
|
184
|
+
@all.each{|r| set.add(r.values.values_at(*column))}
|
|
185
|
+
else
|
|
186
|
+
@all.each{|r| set.add(r[column])}
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
set
|
|
190
|
+
end
|
|
191
|
+
|
|
179
192
|
# Alias of as_hash for backwards compatibility.
|
|
180
193
|
def to_hash(*a)
|
|
181
194
|
as_hash(*a)
|