sequel 5.80.0 → 5.92.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/bin/sequel +9 -4
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/ibmdb.rb +1 -0
- data/lib/sequel/adapters/jdbc/db2.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +3 -3
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- 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 +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +5 -5
- 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 +2 -2
- data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +8 -8
- data/lib/sequel/adapters/mysql2.rb +8 -1
- data/lib/sequel/adapters/shared/access.rb +1 -0
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +18 -5
- data/lib/sequel/adapters/shared/mysql.rb +8 -4
- data/lib/sequel/adapters/shared/oracle.rb +1 -0
- data/lib/sequel/adapters/shared/postgres.rb +106 -13
- data/lib/sequel/adapters/shared/sqlite.rb +4 -2
- data/lib/sequel/adapters/sqlite.rb +4 -0
- data/lib/sequel/adapters/trilogy.rb +1 -2
- data/lib/sequel/connection_pool/sharded_threaded.rb +26 -10
- data/lib/sequel/connection_pool/threaded.rb +26 -10
- data/lib/sequel/connection_pool.rb +2 -2
- data/lib/sequel/core.rb +15 -0
- data/lib/sequel/database/connecting.rb +20 -26
- data/lib/sequel/database/dataset_defaults.rb +3 -3
- data/lib/sequel/database/misc.rb +46 -10
- data/lib/sequel/database/query.rb +11 -11
- data/lib/sequel/database/schema_generator.rb +8 -0
- data/lib/sequel/database/schema_methods.rb +17 -1
- data/lib/sequel/dataset/actions.rb +9 -1
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +2 -1
- data/lib/sequel/dataset/query.rb +9 -5
- data/lib/sequel/dataset/sql.rb +25 -5
- data/lib/sequel/extensions/caller_logging.rb +2 -0
- data/lib/sequel/extensions/connection_validator.rb +15 -10
- data/lib/sequel/extensions/dataset_run.rb +41 -0
- data/lib/sequel/extensions/migration.rb +23 -3
- data/lib/sequel/extensions/null_dataset.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +93 -10
- data/lib/sequel/extensions/pg_enum.rb +3 -3
- data/lib/sequel/extensions/pg_json_ops.rb +642 -9
- data/lib/sequel/extensions/pg_row.rb +3 -1
- data/lib/sequel/extensions/pg_schema_caching.rb +90 -0
- data/lib/sequel/extensions/provenance.rb +2 -0
- 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 +16 -4
- data/lib/sequel/extensions/sqlite_json_ops.rb +1 -1
- data/lib/sequel/extensions/stdio_logger.rb +48 -0
- data/lib/sequel/extensions/string_agg.rb +17 -4
- data/lib/sequel/extensions/temporarily_release_connection.rb +178 -0
- data/lib/sequel/extensions/virtual_row_method_block.rb +1 -0
- data/lib/sequel/model/associations.rb +28 -3
- data/lib/sequel/model/base.rb +67 -18
- data/lib/sequel/plugins/association_pks.rb +1 -1
- data/lib/sequel/plugins/column_encryption.rb +1 -1
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/defaults_setter.rb +16 -4
- data/lib/sequel/plugins/enum.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +14 -1
- data/lib/sequel/plugins/input_transformer.rb +1 -1
- data/lib/sequel/plugins/inspect_pk.rb +44 -0
- data/lib/sequel/plugins/instance_filters.rb +4 -1
- data/lib/sequel/plugins/inverted_subsets.rb +1 -0
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +10 -5
- data/lib/sequel/plugins/optimistic_locking.rb +2 -0
- data/lib/sequel/plugins/paged_operations.rb +5 -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/rcte_tree.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +11 -5
- data/lib/sequel/plugins/sql_comments.rb +7 -2
- 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 +263 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +6 -2
- data/lib/sequel/plugins/validate_associated.rb +1 -1
- data/lib/sequel/sql.rb +16 -6
- data/lib/sequel/version.rb +1 -1
- metadata +12 -234
- data/CHANGELOG +0 -1355
- 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 -102
- 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 -436
- 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.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 -190
- 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
@@ -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
|
|
@@ -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
|
@@ -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
|
|
@@ -37,7 +37,8 @@ module Sequel
|
|
37
37
|
#
|
38
38
|
# # Register custom serializer/deserializer pair, if desired
|
39
39
|
# require 'sequel/plugins/serialization'
|
40
|
-
#
|
40
|
+
# require 'base64'
|
41
|
+
# Sequel::Plugins::Serialization.register_format(:base64, Base64.method(:encode64), Base64.method(:decode64))
|
41
42
|
#
|
42
43
|
# class User < Sequel::Model
|
43
44
|
# # Built-in format support when loading the plugin
|
@@ -48,10 +49,10 @@ module Sequel
|
|
48
49
|
# serialize_attributes :marshal, :permissions
|
49
50
|
#
|
50
51
|
# # Use custom registered serialization format just like built-in format
|
51
|
-
# serialize_attributes :
|
52
|
+
# serialize_attributes :base64, :password
|
52
53
|
#
|
53
54
|
# # Use a custom serializer/deserializer pair without registering
|
54
|
-
# serialize_attributes [:
|
55
|
+
# serialize_attributes [ Base64.method(:encode64), Base64.method(:decode64)], :password
|
55
56
|
# end
|
56
57
|
# user = User.create
|
57
58
|
# user.permissions = {global: 'read-only'}
|
@@ -123,7 +124,12 @@ module Sequel
|
|
123
124
|
end
|
124
125
|
|
125
126
|
# Create instance level reader that deserializes column values on request,
|
126
|
-
# and instance level writer that stores new deserialized values.
|
127
|
+
# and instance level writer that stores new deserialized values. If +format+
|
128
|
+
# is a symbol, it should correspond to a previously-registered format using +register_format+.
|
129
|
+
# Otherwise, +format+ is expected to be a 2-element array of callables,
|
130
|
+
# with the first element being the serializer, used to convert the value used by the application
|
131
|
+
# to the value that will be stored in the database, and the second element being the deserializer,
|
132
|
+
# used to convert the value stored the database to the value used by the application.
|
127
133
|
def serialize_attributes(format, *columns)
|
128
134
|
if format.is_a?(Symbol)
|
129
135
|
unless format = Sequel.synchronize{REGISTERED_FORMATS[format]}
|
@@ -140,7 +146,7 @@ module Sequel
|
|
140
146
|
# Add serializated attribute acessor methods to the serialization_module
|
141
147
|
def define_serialized_attribute_accessor(serializer, deserializer, *columns)
|
142
148
|
m = self
|
143
|
-
include(@serialization_module ||= Module.new) unless @serialization_module
|
149
|
+
include(@serialization_module ||= Sequel.set_temp_name(Module.new){"#{name}::@serialization_module"}) unless @serialization_module
|
144
150
|
@serialization_module.class_eval do
|
145
151
|
columns.each do |column|
|
146
152
|
m.serialization_map[column] = serializer
|
@@ -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
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module Sequel
|
4
4
|
module Plugins
|
5
|
-
# The static_cache_cache plugin allows for caching the row content for
|
6
|
-
# that use the
|
7
|
-
# can avoid the need to query the database every time loading
|
8
|
-
#
|
9
|
-
# plugin.
|
5
|
+
# The static_cache_cache plugin allows for caching the row content for the current
|
6
|
+
# class and subclasses that use the static_cache or subset_static_cache plugins.
|
7
|
+
# Using this plugin can avoid the need to query the database every time loading
|
8
|
+
# the static_cache plugin into a model (static_cache plugin) or using the
|
9
|
+
# cache_subset method (subset_static_cache plugin).
|
10
10
|
#
|
11
11
|
# Usage:
|
12
12
|
#
|
@@ -26,11 +26,7 @@ module Sequel
|
|
26
26
|
module ClassMethods
|
27
27
|
# Dump the in-memory cached rows to the cache file.
|
28
28
|
def dump_static_cache_cache
|
29
|
-
|
30
|
-
@static_cache_cache.sort.each do |k, v|
|
31
|
-
static_cache_cache[k] = v
|
32
|
-
end
|
33
|
-
File.open(@static_cache_cache_file, 'wb'){|f| f.write(Marshal.dump(static_cache_cache))}
|
29
|
+
File.open(@static_cache_cache_file, 'wb'){|f| f.write(Marshal.dump(sort_static_cache_hash(@static_cache_cache)))}
|
34
30
|
nil
|
35
31
|
end
|
36
32
|
|
@@ -38,16 +34,57 @@ module Sequel
|
|
38
34
|
|
39
35
|
private
|
40
36
|
|
37
|
+
# Sort the given static cache hash in a deterministic way, so that
|
38
|
+
# the same static cache values will result in the same marshal file.
|
39
|
+
def sort_static_cache_hash(cache)
|
40
|
+
cache = cache.sort do |a, b|
|
41
|
+
a, = a
|
42
|
+
b, = b
|
43
|
+
if a.is_a?(Array)
|
44
|
+
if b.is_a?(Array)
|
45
|
+
a_name, a_meth = a
|
46
|
+
b_name, b_meth = b
|
47
|
+
x = a_name <=> b_name
|
48
|
+
if x.zero?
|
49
|
+
x = a_meth <=> b_meth
|
50
|
+
end
|
51
|
+
x
|
52
|
+
else
|
53
|
+
1
|
54
|
+
end
|
55
|
+
elsif b.is_a?(Array)
|
56
|
+
-1
|
57
|
+
else
|
58
|
+
a <=> b
|
59
|
+
end
|
60
|
+
end
|
61
|
+
Hash[cache]
|
62
|
+
end
|
63
|
+
|
41
64
|
# Load the rows for the model from the cache if available.
|
42
65
|
# If not available, load the rows from the database, and
|
43
66
|
# then update the cache with the raw rows.
|
44
67
|
def load_static_cache_rows
|
45
|
-
|
68
|
+
_load_static_cache_rows(dataset, name)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Load the rows for the subset from the cache if available.
|
72
|
+
# If not available, load the rows from the database, and
|
73
|
+
# then update the cache with the raw rows.
|
74
|
+
def load_subset_static_cache_rows(ds, meth)
|
75
|
+
_load_static_cache_rows(ds, [name, meth].freeze)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Check the cache first for the key, and return rows without a database
|
79
|
+
# query if present. Otherwise, get all records in the provided dataset,
|
80
|
+
# and update the cache with them.
|
81
|
+
def _load_static_cache_rows(ds, key)
|
82
|
+
if rows = Sequel.synchronize{@static_cache_cache[key]}
|
46
83
|
rows.map{|row| call(row)}.freeze
|
47
84
|
else
|
48
|
-
rows =
|
85
|
+
rows = ds.all.freeze
|
49
86
|
raw_rows = rows.map(&:values)
|
50
|
-
Sequel.synchronize{@static_cache_cache[
|
87
|
+
Sequel.synchronize{@static_cache_cache[key] = raw_rows}
|
51
88
|
rows
|
52
89
|
end
|
53
90
|
end
|
@@ -3,18 +3,31 @@
|
|
3
3
|
module Sequel
|
4
4
|
module Plugins
|
5
5
|
# The subset_conditions plugin creates an additional *_conditions method
|
6
|
-
# for every subset
|
7
|
-
#
|
8
|
-
# filter or combine them with OR.
|
6
|
+
# for every `subset`, `where`, and `exclude` method call in a dataset_module
|
7
|
+
# block. This method returns the filter conditions, which can be useful if
|
8
|
+
# you want to use the conditions for a separate filter or combine them with OR.
|
9
|
+
# It also supports where_all and where_any dataset_module methods for
|
10
|
+
# combining multiple dataset method filters with AND or OR.
|
9
11
|
#
|
10
12
|
# Usage:
|
11
13
|
#
|
12
14
|
# # Add subset_conditions in the Album class
|
13
15
|
# Album.plugin :subset_conditions
|
14
16
|
#
|
15
|
-
# # This will now create a published_conditions method
|
16
17
|
# Album.dataset_module do
|
17
|
-
#
|
18
|
+
# # This will now create a published_conditions method
|
19
|
+
# where :published, published: true
|
20
|
+
#
|
21
|
+
# # This will now create a not_bad_conditions method
|
22
|
+
# exclude :not_bad, :bad
|
23
|
+
#
|
24
|
+
# # This will create good_and_available and
|
25
|
+
# # good_and_available_conditions methods
|
26
|
+
# where_all :good_and_available, :published, :not_bad
|
27
|
+
#
|
28
|
+
# # This will create good_or_available and
|
29
|
+
# # good_or_available_conditions methods
|
30
|
+
# where_any :good_or_available, :published, :not_bad
|
18
31
|
# end
|
19
32
|
#
|
20
33
|
# Album.where(Album.published_conditions).sql
|
@@ -25,10 +38,17 @@ module Sequel
|
|
25
38
|
#
|
26
39
|
# Album.where(Album.published_conditions | {ready: true}).sql
|
27
40
|
# # SELECT * FROM albums WHERE ((published IS TRUE) OR (ready IS TRUE))
|
41
|
+
#
|
42
|
+
# Album.good_and_available.sql
|
43
|
+
# SELECT * FROM albums WHERE ((published IS TRUE) AND NOT bad)
|
44
|
+
#
|
45
|
+
# Album.good_or_available.sql
|
46
|
+
# SELECT * FROM albums WHERE ((published IS TRUE) OR NOT bad)
|
28
47
|
module SubsetConditions
|
29
48
|
def self.apply(model, &block)
|
30
49
|
model.instance_exec do
|
31
50
|
@dataset_module_class = Class.new(@dataset_module_class) do
|
51
|
+
Sequel.set_temp_name(self){"#{model.name}::@dataset_module_class(SubsetConditions)"}
|
32
52
|
include DatasetModuleMethods
|
33
53
|
end
|
34
54
|
end
|
@@ -42,6 +62,66 @@ module Sequel
|
|
42
62
|
cond = cond.first if cond.size == 1
|
43
63
|
define_method(:"#{name}_conditions"){filter_expr(cond, &block)}
|
44
64
|
end
|
65
|
+
|
66
|
+
# Also create a method that returns the conditions the filter uses.
|
67
|
+
def exclude(name, *args, &block)
|
68
|
+
super
|
69
|
+
cond = args
|
70
|
+
cond = cond.first if cond.size == 1
|
71
|
+
define_method(:"#{name}_conditions"){Sequel.~(filter_expr(cond, &block))}
|
72
|
+
end
|
73
|
+
|
74
|
+
# Create a method that combines filters from already registered
|
75
|
+
# dataset methods, and filters for rows where all of the conditions
|
76
|
+
# are satisfied.
|
77
|
+
#
|
78
|
+
# Employee.dataset_module do
|
79
|
+
# where :active, active: true
|
80
|
+
# where :started, Sequel::CURRENT_DATE <= :start_date
|
81
|
+
# where_all(:active_and_started, :active, :started)
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# Employee.active_and_started.sql
|
85
|
+
# # SELECT * FROM employees WHERE ((active IS TRUE) AND (CURRENT_DATE <= start_date))
|
86
|
+
def where_all(name, *args)
|
87
|
+
_where_any_all(:&, name, args)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Create a method that combines filters from already registered
|
91
|
+
# dataset methods, and filters for rows where any of the conditions
|
92
|
+
# are satisfied.
|
93
|
+
#
|
94
|
+
# Employee.dataset_module do
|
95
|
+
# where :active, active: true
|
96
|
+
# where :started, Sequel::CURRENT_DATE <= :start_date
|
97
|
+
# where_any(:active_or_started, :active, :started)
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# Employee.active_or_started.sql
|
101
|
+
# # SELECT * FROM employees WHERE ((active IS TRUE) OR (CURRENT_DATE <= start_date))
|
102
|
+
def where_any(name, *args)
|
103
|
+
_where_any_all(:|, name, args)
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
if RUBY_VERSION >= '2'
|
109
|
+
# Backbone of #where_any and #where_all
|
110
|
+
def _where_any_all(meth, name, args)
|
111
|
+
ds = model.dataset
|
112
|
+
# #bind used here because the dataset module may not yet be included in the model's dataset
|
113
|
+
where(name, Sequel.send(meth, *args.map{|a| self.instance_method(:"#{a}_conditions").bind(ds).call}))
|
114
|
+
end
|
115
|
+
else
|
116
|
+
# Cannot bind module method to arbitrary objects in Ruby 1.9.
|
117
|
+
# :nocov:
|
118
|
+
def _where_any_all(meth, name, args)
|
119
|
+
ds = model.dataset.clone
|
120
|
+
ds.extend(self)
|
121
|
+
where(name, Sequel.send(meth, *args.map{|a| ds.send(:"#{a}_conditions")}))
|
122
|
+
end
|
123
|
+
# :nocov:
|
124
|
+
end
|
45
125
|
end
|
46
126
|
end
|
47
127
|
end
|