sequel 5.87.0 → 5.88.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sequel/adapters/shared/postgres.rb +19 -0
- data/lib/sequel/dataset/sql.rb +6 -1
- data/lib/sequel/extensions/migration.rb +19 -3
- data/lib/sequel/extensions/null_dataset.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +2 -2
- data/lib/sequel/model/base.rb +22 -9
- data/lib/sequel/plugins/serialization.rb +10 -4
- data/lib/sequel/plugins/static_cache_cache.rb +50 -13
- data/lib/sequel/plugins/subset_static_cache.rb +262 -0
- data/lib/sequel/version.rb +1 -1
- metadata +4 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a4a563fddfd5332195e8b9ba2588aef535f27ea0cee15f43afdc877910775ba
|
4
|
+
data.tar.gz: 47cb743d96f031e4fa7e415708473158b2f564b3faa155335a4787e79bce34bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3dd656f73cdf525bda28a2cb5f136f91ae2935f48cfd94f8dc06f042b7f682c2faf48a48625b7845ae058b92189447433c152ab11eeebb8baae925d5371326d
|
7
|
+
data.tar.gz: 84ae987e64b8c872351d259d88a1e8b63b7926e06f9bda7a0d71dda4826e4e17c83fdc5538bcde63cc0d16f77ffd75c57b504947a692898d552a77e1814a7c44
|
@@ -2388,6 +2388,25 @@ module Sequel
|
|
2388
2388
|
join_from_sql(:USING, sql)
|
2389
2389
|
end
|
2390
2390
|
|
2391
|
+
# Handle column aliases containing data types, useful for selecting from functions
|
2392
|
+
# that return the record data type.
|
2393
|
+
def derived_column_list_sql_append(sql, column_aliases)
|
2394
|
+
c = false
|
2395
|
+
comma = ', '
|
2396
|
+
column_aliases.each do |a|
|
2397
|
+
sql << comma if c
|
2398
|
+
if a.is_a?(Array)
|
2399
|
+
raise Error, "column aliases specified as arrays must have only 2 elements, the first is alias name and the second is data type" unless a.length == 2
|
2400
|
+
a, type = a
|
2401
|
+
identifier_append(sql, a)
|
2402
|
+
sql << " " << db.cast_type_literal(type).to_s
|
2403
|
+
else
|
2404
|
+
identifier_append(sql, a)
|
2405
|
+
end
|
2406
|
+
c ||= true
|
2407
|
+
end
|
2408
|
+
end
|
2409
|
+
|
2391
2410
|
# Add ON CONFLICT clause if it should be used
|
2392
2411
|
def insert_conflict_sql(sql)
|
2393
2412
|
if opts = @opts[:insert_conflict]
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -1032,7 +1032,7 @@ module Sequel
|
|
1032
1032
|
if column_aliases
|
1033
1033
|
raise Error, "#{db.database_type} does not support derived column lists" unless supports_derived_column_lists?
|
1034
1034
|
sql << '('
|
1035
|
-
|
1035
|
+
derived_column_list_sql_append(sql, column_aliases)
|
1036
1036
|
sql << ')'
|
1037
1037
|
end
|
1038
1038
|
end
|
@@ -1165,6 +1165,11 @@ module Sequel
|
|
1165
1165
|
end
|
1166
1166
|
end
|
1167
1167
|
|
1168
|
+
# Append the column aliases to the SQL.
|
1169
|
+
def derived_column_list_sql_append(sql, column_aliases)
|
1170
|
+
identifier_list_append(sql, column_aliases)
|
1171
|
+
end
|
1172
|
+
|
1168
1173
|
# Disable caching of SQL for the current dataset
|
1169
1174
|
def disable_sql_caching!
|
1170
1175
|
cache_set(:_no_cache_sql, true)
|
@@ -223,7 +223,7 @@ module Sequel
|
|
223
223
|
@actions << [:drop_join_table, *args]
|
224
224
|
end
|
225
225
|
|
226
|
-
def create_table(name, opts=OPTS)
|
226
|
+
def create_table(name, opts=OPTS, &_)
|
227
227
|
@actions << [:drop_table, name, opts]
|
228
228
|
end
|
229
229
|
|
@@ -371,7 +371,7 @@ module Sequel
|
|
371
371
|
#
|
372
372
|
# Part of the +migration+ extension.
|
373
373
|
class Migrator
|
374
|
-
MIGRATION_FILE_PATTERN = /\A(\d+)_
|
374
|
+
MIGRATION_FILE_PATTERN = /\A(\d+)_(.+)\.rb\z/i.freeze
|
375
375
|
|
376
376
|
# Mutex used around migration file loading
|
377
377
|
MUTEX = Mutex.new
|
@@ -791,7 +791,23 @@ module Sequel
|
|
791
791
|
next unless MIGRATION_FILE_PATTERN.match(file)
|
792
792
|
files << File.join(directory, file)
|
793
793
|
end
|
794
|
-
files.
|
794
|
+
files.sort! do |a, b|
|
795
|
+
a_ver, a_name = split_migration_filename(a)
|
796
|
+
b_ver, b_name = split_migration_filename(b)
|
797
|
+
x = a_ver <=> b_ver
|
798
|
+
if x.zero?
|
799
|
+
x = a_name <=> b_name
|
800
|
+
end
|
801
|
+
x
|
802
|
+
end
|
803
|
+
files
|
804
|
+
end
|
805
|
+
|
806
|
+
# Return an integer and name (without extension) for the given path.
|
807
|
+
def split_migration_filename(path)
|
808
|
+
version, name = MIGRATION_FILE_PATTERN.match(File.basename(path)).captures
|
809
|
+
version = version.to_i
|
810
|
+
[version, name]
|
795
811
|
end
|
796
812
|
|
797
813
|
# Returns tuples of migration, filename, and direction
|
@@ -63,12 +63,12 @@ module Sequel
|
|
63
63
|
end
|
64
64
|
|
65
65
|
# Return self without sending a database query, never yielding.
|
66
|
-
def each
|
66
|
+
def each(&_)
|
67
67
|
self
|
68
68
|
end
|
69
69
|
|
70
70
|
# Return nil without sending a database query, never yielding.
|
71
|
-
def fetch_rows(sql)
|
71
|
+
def fetch_rows(sql, &_)
|
72
72
|
nil
|
73
73
|
end
|
74
74
|
|
@@ -173,7 +173,7 @@ module Sequel
|
|
173
173
|
# Return a modified StringAgg that uses distinct expressions
|
174
174
|
def distinct
|
175
175
|
self.class.new(@expr, @separator) do |sa|
|
176
|
-
sa.instance_variable_set(:@order_expr, @order_expr)
|
176
|
+
sa.instance_variable_set(:@order_expr, @order_expr)
|
177
177
|
sa.instance_variable_set(:@distinct, true)
|
178
178
|
end
|
179
179
|
end
|
@@ -181,8 +181,8 @@ module Sequel
|
|
181
181
|
# Return a modified StringAgg with the given order
|
182
182
|
def order(*o)
|
183
183
|
self.class.new(@expr, @separator) do |sa|
|
184
|
-
sa.instance_variable_set(:@distinct, @distinct) if @distinct
|
185
184
|
sa.instance_variable_set(:@order_expr, o.empty? ? nil : o.freeze)
|
185
|
+
sa.instance_variable_set(:@distinct, @distinct)
|
186
186
|
end
|
187
187
|
end
|
188
188
|
|
data/lib/sequel/model/base.rb
CHANGED
@@ -762,22 +762,35 @@ module Sequel
|
|
762
762
|
end
|
763
763
|
end
|
764
764
|
end
|
765
|
+
|
766
|
+
# Module that the class methods that call dataset methods are kept in.
|
767
|
+
# This allows the methods to be overridden and call super with the
|
768
|
+
# default behavior.
|
769
|
+
def dataset_methods_module
|
770
|
+
return @dataset_methods_module if defined?(@dataset_methods_module)
|
771
|
+
Sequel.synchronize{@dataset_methods_module ||= Module.new}
|
772
|
+
extend(@dataset_methods_module)
|
773
|
+
@dataset_methods_module
|
774
|
+
end
|
765
775
|
|
766
|
-
# Define a model method that calls the dataset method with the same name
|
767
|
-
# only used for methods with names that can't be represented directly in
|
768
|
-
# ruby code.
|
776
|
+
# Define a model method that calls the dataset method with the same name.
|
769
777
|
def def_model_dataset_method(meth)
|
770
778
|
return if respond_to?(meth, true)
|
771
779
|
|
780
|
+
mod = dataset_methods_module
|
781
|
+
|
772
782
|
if meth.to_s =~ /\A[A-Za-z_][A-Za-z0-9_]*\z/
|
773
|
-
|
783
|
+
mod.module_eval(<<END, __FILE__, __LINE__ + 1)
|
784
|
+
def #{meth}(*args, &block); dataset.#{meth}(*args, &block) end
|
785
|
+
ruby2_keywords :#{meth} if respond_to?(:ruby2_keywords, true)
|
786
|
+
END
|
774
787
|
else
|
775
|
-
|
788
|
+
mod.send(:define_method, meth){|*args, &block| dataset.public_send(meth, *args, &block)}
|
789
|
+
# :nocov:
|
790
|
+
mod.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true)
|
791
|
+
# :nocov:
|
776
792
|
end
|
777
|
-
|
778
|
-
# :nocov:
|
779
|
-
singleton_class.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true)
|
780
|
-
# :nocov:
|
793
|
+
mod.send(:alias_method, meth, meth)
|
781
794
|
end
|
782
795
|
|
783
796
|
# Get the schema from the database, fall back on checking the columns
|
@@ -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]}
|
@@ -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
|
@@ -0,0 +1,262 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Plugins
|
5
|
+
# The subset_static_cache plugin is designed for model subsets that are not modified at all
|
6
|
+
# in production use cases, or at least where modifications to them would usually
|
7
|
+
# coincide with an application restart. When caching a model subset, it
|
8
|
+
# retrieves all rows in the database and statically caches a ruby array and hash
|
9
|
+
# keyed on primary key containing all of the model instances. All of these cached
|
10
|
+
# instances are frozen so they won't be modified unexpectedly.
|
11
|
+
#
|
12
|
+
# With the following code:
|
13
|
+
#
|
14
|
+
# class StatusType < Sequel::Model
|
15
|
+
# dataset_module do
|
16
|
+
# where :available, hidden: false
|
17
|
+
# end
|
18
|
+
# cache_subset :available
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# The following methods will use the cache and not issue a database query:
|
22
|
+
#
|
23
|
+
# * StatusType.available.with_pk
|
24
|
+
# * StatusType.available.all
|
25
|
+
# * StatusType.available.each
|
26
|
+
# * StatusType.available.first (without block, only supporting no arguments or single integer argument)
|
27
|
+
# * StatusType.available.count (without an argument or block)
|
28
|
+
# * StatusType.available.map
|
29
|
+
# * StatusType.available.as_hash
|
30
|
+
# * StatusType.available.to_hash
|
31
|
+
# * StatusType.available.to_hash_groups
|
32
|
+
#
|
33
|
+
# The cache is not used if you chain methods before or after calling the cached
|
34
|
+
# method, as doing so would not be safe:
|
35
|
+
#
|
36
|
+
# StatusType.where{number > 1}.available.all
|
37
|
+
# StatusType.available.where{number > 1}.all
|
38
|
+
#
|
39
|
+
# The cache is also not used if you change the class's dataset after caching
|
40
|
+
# the subset, or in subclasses of the model.
|
41
|
+
#
|
42
|
+
# You should not modify any row that is statically cached when using this plugin,
|
43
|
+
# as otherwise you will get different results for cached and uncached method
|
44
|
+
# calls.
|
45
|
+
module SubsetStaticCache
|
46
|
+
def self.configure(model)
|
47
|
+
model.class_exec do
|
48
|
+
@subset_static_caches ||= ({}.compare_by_identity)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module ClassMethods
|
53
|
+
# Cache the given subset statically, so that calling the subset method on
|
54
|
+
# the model will return a dataset that will return cached results instead
|
55
|
+
# of issuing database queries (assuming the cache has the necessary
|
56
|
+
# information).
|
57
|
+
#
|
58
|
+
# The model must already respond to the given method before cache_subset
|
59
|
+
# is called.
|
60
|
+
def cache_subset(meth)
|
61
|
+
ds = send(meth).with_extend(CachedDatasetMethods)
|
62
|
+
cache = ds.instance_variable_get(:@cache)
|
63
|
+
|
64
|
+
rows, hash = subset_static_cache_rows(ds, meth)
|
65
|
+
cache[:subset_static_cache_all] = rows
|
66
|
+
cache[:subset_static_cache_map] = hash
|
67
|
+
|
68
|
+
caches = @subset_static_caches
|
69
|
+
caches[meth] = ds
|
70
|
+
model = self
|
71
|
+
subset_static_cache_module.send(:define_method, meth) do
|
72
|
+
if (model == self) && (cached_dataset = caches[meth])
|
73
|
+
cached_dataset
|
74
|
+
else
|
75
|
+
super()
|
76
|
+
end
|
77
|
+
end
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
81
|
+
Plugins.after_set_dataset(self, :clear_subset_static_caches)
|
82
|
+
Plugins.inherited_instance_variables(self, :@subset_static_caches=>proc{{}.compare_by_identity})
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Clear the subset_static_caches. This is used if the model dataset
|
87
|
+
# changes, to prevent cached values from being used.
|
88
|
+
def clear_subset_static_caches
|
89
|
+
@subset_static_caches.clear
|
90
|
+
end
|
91
|
+
|
92
|
+
# A module for the subset static cache methods, so that you can define
|
93
|
+
# a singleton method in the class with the same name, and call super
|
94
|
+
# to get default behavior.
|
95
|
+
def subset_static_cache_module
|
96
|
+
return @subset_static_cache_module if @subset_static_cache_module
|
97
|
+
|
98
|
+
# Ensure dataset_methods module is defined and class is extended with
|
99
|
+
# it before calling creating this module.
|
100
|
+
dataset_methods_module
|
101
|
+
|
102
|
+
Sequel.synchronize{@subset_static_cache_module ||= Module.new}
|
103
|
+
extend(@subset_static_cache_module)
|
104
|
+
@subset_static_cache_module
|
105
|
+
end
|
106
|
+
|
107
|
+
# Return the frozen array and hash used for caching the subset
|
108
|
+
# of the given dataset.
|
109
|
+
def subset_static_cache_rows(ds, meth)
|
110
|
+
all = load_subset_static_cache_rows(ds, meth)
|
111
|
+
h = {}
|
112
|
+
all.each do |o|
|
113
|
+
o.errors.freeze
|
114
|
+
h[o.pk.freeze] = o.freeze
|
115
|
+
end
|
116
|
+
[all, h.freeze]
|
117
|
+
end
|
118
|
+
|
119
|
+
# Return a frozen array for all rows in the dataset.
|
120
|
+
def load_subset_static_cache_rows(ds, meth)
|
121
|
+
ret = super if defined?(super)
|
122
|
+
ret || ds.all.freeze
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
module CachedDatasetMethods
|
127
|
+
# An array of all of the dataset's instances, without issuing a database
|
128
|
+
# query. If a block is given, yields each instance to the block.
|
129
|
+
def all(&block)
|
130
|
+
return super unless all = @cache[:subset_static_cache_all]
|
131
|
+
|
132
|
+
array = all.dup
|
133
|
+
array.each(&block) if block
|
134
|
+
array
|
135
|
+
end
|
136
|
+
|
137
|
+
# Get the number of records in the cache, without issuing a database query,
|
138
|
+
# if no arguments or block are provided.
|
139
|
+
def count(*a, &block)
|
140
|
+
if a.empty? && !block && (all = @cache[:subset_static_cache_all])
|
141
|
+
all.size
|
142
|
+
else
|
143
|
+
super
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# If a block is given, multiple arguments are given, or a single
|
148
|
+
# non-Integer argument is given, performs the default behavior of
|
149
|
+
# issuing a database query. Otherwise, uses the cached values
|
150
|
+
# to return either the first cached instance (no arguments) or an
|
151
|
+
# array containing the number of instances specified (single integer
|
152
|
+
# argument).
|
153
|
+
def first(*args)
|
154
|
+
if !defined?(yield) && args.length <= 1 && (args.length == 0 || args[0].is_a?(Integer)) && (all = @cache[:subset_static_cache_all])
|
155
|
+
all.first(*args)
|
156
|
+
else
|
157
|
+
super
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Return the frozen object with the given pk, or nil if no such object exists
|
162
|
+
# in the cache, without issuing a database query.
|
163
|
+
def with_pk(pk)
|
164
|
+
if cache = @cache[:subset_static_cache_map]
|
165
|
+
cache[pk]
|
166
|
+
else
|
167
|
+
super
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Yield each of the dataset's frozen instances to the block, without issuing a database
|
172
|
+
# query.
|
173
|
+
def each(&block)
|
174
|
+
return super unless all = @cache[:subset_static_cache_all]
|
175
|
+
all.each(&block)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Use the cache instead of a query to get the results.
|
179
|
+
def map(column=nil, &block)
|
180
|
+
return super unless all = @cache[:subset_static_cache_all]
|
181
|
+
if column
|
182
|
+
raise(Error, "Cannot provide both column and block to map") if block
|
183
|
+
if column.is_a?(Array)
|
184
|
+
all.map{|r| r.values.values_at(*column)}
|
185
|
+
else
|
186
|
+
all.map{|r| r[column]}
|
187
|
+
end
|
188
|
+
else
|
189
|
+
all.map(&block)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Use the cache instead of a query to get the results if possible
|
194
|
+
def as_hash(key_column = nil, value_column = nil, opts = OPTS)
|
195
|
+
return super unless all = @cache[:subset_static_cache_all]
|
196
|
+
|
197
|
+
if key_column.nil? && value_column.nil?
|
198
|
+
if opts[:hash]
|
199
|
+
key_column = model.primary_key
|
200
|
+
else
|
201
|
+
return Hash[@cache[:subset_static_cache_map]]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
h = opts[:hash] || {}
|
206
|
+
if value_column
|
207
|
+
if value_column.is_a?(Array)
|
208
|
+
if key_column.is_a?(Array)
|
209
|
+
all.each{|r| h[r.values.values_at(*key_column)] = r.values.values_at(*value_column)}
|
210
|
+
else
|
211
|
+
all.each{|r| h[r[key_column]] = r.values.values_at(*value_column)}
|
212
|
+
end
|
213
|
+
else
|
214
|
+
if key_column.is_a?(Array)
|
215
|
+
all.each{|r| h[r.values.values_at(*key_column)] = r[value_column]}
|
216
|
+
else
|
217
|
+
all.each{|r| h[r[key_column]] = r[value_column]}
|
218
|
+
end
|
219
|
+
end
|
220
|
+
elsif key_column.is_a?(Array)
|
221
|
+
all.each{|r| h[r.values.values_at(*key_column)] = r}
|
222
|
+
else
|
223
|
+
all.each{|r| h[r[key_column]] = r}
|
224
|
+
end
|
225
|
+
h
|
226
|
+
end
|
227
|
+
|
228
|
+
# Alias of as_hash for backwards compatibility.
|
229
|
+
def to_hash(*a)
|
230
|
+
as_hash(*a)
|
231
|
+
end
|
232
|
+
|
233
|
+
# Use the cache instead of a query to get the results
|
234
|
+
def to_hash_groups(key_column, value_column = nil, opts = OPTS)
|
235
|
+
return super unless all = @cache[:subset_static_cache_all]
|
236
|
+
|
237
|
+
h = opts[:hash] || {}
|
238
|
+
if value_column
|
239
|
+
if value_column.is_a?(Array)
|
240
|
+
if key_column.is_a?(Array)
|
241
|
+
all.each{|r| (h[r.values.values_at(*key_column)] ||= []) << r.values.values_at(*value_column)}
|
242
|
+
else
|
243
|
+
all.each{|r| (h[r[key_column]] ||= []) << r.values.values_at(*value_column)}
|
244
|
+
end
|
245
|
+
else
|
246
|
+
if key_column.is_a?(Array)
|
247
|
+
all.each{|r| (h[r.values.values_at(*key_column)] ||= []) << r[value_column]}
|
248
|
+
else
|
249
|
+
all.each{|r| (h[r[key_column]] ||= []) << r[value_column]}
|
250
|
+
end
|
251
|
+
end
|
252
|
+
elsif key_column.is_a?(Array)
|
253
|
+
all.each{|r| (h[r.values.values_at(*key_column)] ||= []) << r}
|
254
|
+
else
|
255
|
+
all.each{|r| (h[r[key_column]] ||= []) << r}
|
256
|
+
end
|
257
|
+
h
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
data/lib/sequel/version.rb
CHANGED
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
8
8
|
# release, generally around once a month.
|
9
|
-
MINOR =
|
9
|
+
MINOR = 88
|
10
10
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
12
12
|
# releases that fix regressions from previous versions.
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.88.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-01-01 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: bigdecimal
|
@@ -392,6 +391,7 @@ files:
|
|
392
391
|
- lib/sequel/plugins/string_stripper.rb
|
393
392
|
- lib/sequel/plugins/subclasses.rb
|
394
393
|
- lib/sequel/plugins/subset_conditions.rb
|
394
|
+
- lib/sequel/plugins/subset_static_cache.rb
|
395
395
|
- lib/sequel/plugins/table_select.rb
|
396
396
|
- lib/sequel/plugins/tactical_eager_loading.rb
|
397
397
|
- lib/sequel/plugins/throw_failures.rb
|
@@ -424,7 +424,6 @@ metadata:
|
|
424
424
|
documentation_uri: https://sequel.jeremyevans.net/documentation.html
|
425
425
|
mailing_list_uri: https://github.com/jeremyevans/sequel/discussions
|
426
426
|
source_code_uri: https://github.com/jeremyevans/sequel
|
427
|
-
post_install_message:
|
428
427
|
rdoc_options:
|
429
428
|
- "--quiet"
|
430
429
|
- "--line-numbers"
|
@@ -446,8 +445,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
446
445
|
- !ruby/object:Gem::Version
|
447
446
|
version: '0'
|
448
447
|
requirements: []
|
449
|
-
rubygems_version: 3.
|
450
|
-
signing_key:
|
448
|
+
rubygems_version: 3.6.2
|
451
449
|
specification_version: 4
|
452
450
|
summary: The Database Toolkit for Ruby
|
453
451
|
test_files: []
|