sequel 5.52.0 → 5.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/MIT-LICENSE +1 -1
- data/doc/opening_databases.rdoc +3 -0
- data/doc/querying.rdoc +3 -1
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/sql.rdoc +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +55 -10
- data/lib/sequel/adapters/jdbc.rb +5 -5
- data/lib/sequel/adapters/mysql2.rb +12 -5
- data/lib/sequel/adapters/sqlite.rb +44 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/dataset/sql.rb +3 -2
- data/lib/sequel/extensions/pg_array_ops.rb +1 -1
- data/lib/sequel/extensions/sql_comments.rb +2 -0
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/column_encryption.rb +1 -1
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/subclasses.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfed01eed8d575d13963be4568c8935f82c47a59b2be32d382439d50153f032d
|
4
|
+
data.tar.gz: 9ac182c00cdc1f54c26626005f990c5e0a05eebaae3b3c5b88bac0fcd770cd8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9aceee8528a749c541f74eeb07610b520e4342ac8d11abda3222fd0d760e2ff2a16e1b08b7931f5d24cb0ae9fced020ef695798ffac6c4b4af15508e8927468
|
7
|
+
data.tar.gz: 19e40f6386373bdbba07b5a65faf5ffc99a5693e81b0eaeaf1abffc9b07cc29c2688ea658629f633eb36a3427f74857cab28216d18cfb208cca97a75ea10788e
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
=== 5.55.0 (2022-04-01)
|
2
|
+
|
3
|
+
* Support :setup_regexp_function Database option in the sqlite adapter to allow the use of regexps when querying (jeremyevans)
|
4
|
+
|
5
|
+
* Add auto_restrict_eager_graph plugin for automatically disallow eager_graph with associations needing but lacking graph options (jeremyevans)
|
6
|
+
|
7
|
+
* Fix placeholder literalizer optimization for dataset aggregate methods on a model dataset (belousovAV) (#1847, #1848)
|
8
|
+
|
9
|
+
=== 5.54.0 (2022-03-01)
|
10
|
+
|
11
|
+
* Add enum plugin for treating columns as enums in a model (jeremyevans) (#1839)
|
12
|
+
|
13
|
+
=== 5.53.0 (2022-02-01)
|
14
|
+
|
15
|
+
* Make Dataset#_sql_comment private when using the Database sql_comments extension (jeremyevans)
|
16
|
+
|
17
|
+
* Fix prepared statements in the mysql2 adapter to reuse native prepared statements (jeremyevans) (#1832)
|
18
|
+
|
19
|
+
* Support H2 version 2+ in the jdbc/h2 adapter (jeremyevans) (#1817)
|
20
|
+
|
21
|
+
* Work around active_support breaking subclasses plugin on Ruby <3.1 (jeremyevans) (#1816)
|
22
|
+
|
23
|
+
* Fix error handling if trying to setup column_encryption plugin without keys (jeremyevans) (#1815)
|
24
|
+
|
1
25
|
=== 5.52.0 (2022-01-01)
|
2
26
|
|
3
27
|
* Use Class#subclasses if available in the subclasses plugin, instead of a custom Model.subclasses accessor (jeremyevans)
|
data/MIT-LICENSE
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
Copyright (c) 2007-2008 Sharon Rosner
|
2
|
-
Copyright (c) 2008-
|
2
|
+
Copyright (c) 2008-2022 Jeremy Evans
|
3
3
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
of this software and associated documentation files (the "Software"), to
|
data/doc/opening_databases.rdoc
CHANGED
@@ -383,6 +383,9 @@ The following additional options are supported:
|
|
383
383
|
|
384
384
|
:readonly :: open database in read-only mode
|
385
385
|
:timeout :: the busy timeout to use in milliseconds (default: 5000).
|
386
|
+
:setup_regexp_function :: Whether to setup a REGEXP function in the underlying SQLite3::Database object. Doing so
|
387
|
+
allows you to use regexp support in dataset expressions. Note that this creates a new
|
388
|
+
Regexp object per call to the function, so it is not an efficient implementation.
|
386
389
|
|
387
390
|
Note that SQLite memory databases are restricted to a single connection by
|
388
391
|
default. This is because SQLite does not allow multiple connections to
|
data/doc/querying.rdoc
CHANGED
@@ -357,7 +357,9 @@ For ranges, Sequel uses a pair of inequality statements:
|
|
357
357
|
# SELECT * FROM artists WHERE ((id >= 1) AND (id < 5))
|
358
358
|
|
359
359
|
Finally, for regexps, Sequel uses an SQL regular expression. Note that this
|
360
|
-
is
|
360
|
+
is only supported by default on PostgreSQL and MySQL. It can also be supported
|
361
|
+
on SQLite when using the sqlite adapter with the :setup_regexp_function
|
362
|
+
Database option.
|
361
363
|
|
362
364
|
Artist.where(name: /JM$/)
|
363
365
|
# SELECT * FROM artists WHERE (name ~ 'JM$')
|
@@ -0,0 +1,23 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The jdbc/h2 subadapter now supports H2 version 2.0. It continues to
|
4
|
+
support H2 versions 1.3 and 1.4.
|
5
|
+
|
6
|
+
* The mysql2 adapter's prepared statement support now reuses existing
|
7
|
+
native prepared statements, instead of only binding variables on
|
8
|
+
newly prepared statements. This was the intended behavior
|
9
|
+
previously, and should result in increased performance in cases
|
10
|
+
where preparing a query takes significant time.
|
11
|
+
|
12
|
+
* The subclasses plugin now ignores an existing Class#subclasses
|
13
|
+
method if it is defined in Ruby. This fixes cases where usage of
|
14
|
+
ActiveSupport would break the subclasses plugin.
|
15
|
+
|
16
|
+
* Database#call_sproc in the jdbc adapter will now always close the
|
17
|
+
prepared call it creates. Before, if there was an exception raised
|
18
|
+
when setting the arguments for the prepared call, the prepared call
|
19
|
+
would not be closed.
|
20
|
+
|
21
|
+
* A more appropriate error is now issued if you try to use the
|
22
|
+
column_encryption plugin to encrypt a column without setting up an
|
23
|
+
encryption key.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
= New Feature
|
2
|
+
|
3
|
+
* An enum plugin has been added. This plugin allows you to create
|
4
|
+
model-level enums, giving names to underlying values of a column.
|
5
|
+
For example:
|
6
|
+
|
7
|
+
Album.plugin :enum
|
8
|
+
Album.enum :status_id, good: 1, bad: 2
|
9
|
+
|
10
|
+
Adds Album#good! and Album#bad! for changing the status_id to 1 or
|
11
|
+
2 respectively. It adds Album#good? and Album#bad? for checking
|
12
|
+
whether the status_id is 1 or 2 respectively. It overrides
|
13
|
+
Album#status_id to return :good or :bad instead of 1 or 2,
|
14
|
+
respectively, and overrides Album#status_id= to accept :good or
|
15
|
+
:bad instead of 1 or 2 respectively.
|
16
|
+
|
17
|
+
Additionally, it adds good and bad dataset methods for filtering
|
18
|
+
the model's dataset to records where status_id is 1 or 2
|
19
|
+
respectively. It also adds not_good and not_bad dataset methods
|
20
|
+
for filtering the model's dataset to records where status_id is not
|
21
|
+
1 or not 2 respectively.
|
22
|
+
|
23
|
+
You can use :prefix and :suffix options when calling enum to
|
24
|
+
add a prefix or suffix to the method names created. You can
|
25
|
+
set the :override_accessors option to false to not override
|
26
|
+
the accessor methods for the column, and set the :dataset_methods
|
27
|
+
option to false to not add dataset methods.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* An auto_restrict_eager_graph plugin has been added for automatically
|
4
|
+
disallowing the use of eager_graph with associations using blocks but
|
5
|
+
lacking graph_* options. This can prevent potentionally invalid usage,
|
6
|
+
as the restrictions added by the block are not used by eager_graph.
|
7
|
+
|
8
|
+
* The sqlite adapter now supports the :setup_regexp_function
|
9
|
+
Database option. This option will define a REGEXP function in the
|
10
|
+
database that will allow regexp support in queries, such as:
|
11
|
+
|
12
|
+
DB[:table].where(column: /(some|pattern)/)
|
13
|
+
|
14
|
+
Note that this creates a Ruby Regexp object per column value tested,
|
15
|
+
so it isn't the most optimal approach.
|
16
|
+
|
17
|
+
= Other Improvements
|
18
|
+
|
19
|
+
* Calling dataset aggregate methods such as #max on a model dataset now
|
20
|
+
works correctly. Previously, it could fail if called enough times to
|
21
|
+
optimize using a placeholder literalizer.
|
data/doc/sql.rdoc
CHANGED
@@ -528,7 +528,7 @@ Inverting the LIKE operator works like other inversions:
|
|
528
528
|
|
529
529
|
~Sequel.like(:name, 'A%') # ("name" NOT LIKE 'A%' ESCAPE '\')
|
530
530
|
|
531
|
-
Sequel also supports SQL regular expressions on MySQL and PostgreSQL. You can use these by passing a Ruby regular expression to +like+ or +ilike+, or by making the regular expression a hash value:
|
531
|
+
Sequel also supports SQL regular expressions on MySQL and PostgreSQL (and SQLite when using the sqlite adapter with the :setup_regexp_function Database option). You can use these by passing a Ruby regular expression to +like+ or +ilike+, or by making the regular expression a hash value:
|
532
532
|
|
533
533
|
Sequel.like(:name, /^A/) # ("name" ~ '^A')
|
534
534
|
~Sequel.ilike(:name, /^A/) # ("name" !~* '^A')
|
@@ -24,6 +24,7 @@ module Sequel
|
|
24
24
|
|
25
25
|
def freeze
|
26
26
|
h2_version
|
27
|
+
version2?
|
27
28
|
super
|
28
29
|
end
|
29
30
|
|
@@ -140,13 +141,36 @@ module Sequel
|
|
140
141
|
DATABASE_ERROR_REGEXPS
|
141
142
|
end
|
142
143
|
|
143
|
-
|
144
|
+
def execute_statement_insert(stmt, sql)
|
145
|
+
stmt.executeUpdate(sql, JavaSQL::Statement::RETURN_GENERATED_KEYS)
|
146
|
+
end
|
147
|
+
|
148
|
+
def prepare_jdbc_statement(conn, sql, opts)
|
149
|
+
opts[:type] == :insert ? conn.prepareStatement(sql, JavaSQL::Statement::RETURN_GENERATED_KEYS) : super
|
150
|
+
end
|
151
|
+
|
152
|
+
# Get the last inserted id using getGeneratedKeys, scope_identity, or identity.
|
144
153
|
def last_insert_id(conn, opts=OPTS)
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
154
|
+
if stmt = opts[:stmt]
|
155
|
+
rs = stmt.getGeneratedKeys
|
156
|
+
begin
|
157
|
+
if rs.next
|
158
|
+
begin
|
159
|
+
rs.getLong(1)
|
160
|
+
rescue
|
161
|
+
rs.getObject(1) rescue nil
|
162
|
+
end
|
163
|
+
end
|
164
|
+
ensure
|
165
|
+
rs.close
|
166
|
+
end
|
167
|
+
elsif !version2?
|
168
|
+
statement(conn) do |stmt|
|
169
|
+
sql = 'SELECT IDENTITY()'
|
170
|
+
rs = log_connection_yield(sql, conn){stmt.executeQuery(sql)}
|
171
|
+
rs.next
|
172
|
+
rs.getLong(1)
|
173
|
+
end
|
150
174
|
end
|
151
175
|
end
|
152
176
|
|
@@ -161,7 +185,12 @@ module Sequel
|
|
161
185
|
|
162
186
|
# Use BIGINT IDENTITY for identity columns that use :Bignum type
|
163
187
|
def type_literal_generic_bignum_symbol(column)
|
164
|
-
column[:identity] ? 'BIGINT
|
188
|
+
column[:identity] ? 'BIGINT AUTO_INCREMENT' : super
|
189
|
+
end
|
190
|
+
|
191
|
+
def version2?
|
192
|
+
return @version2 if defined?(@version2)
|
193
|
+
@version2 = h2_version.to_i >= 2
|
165
194
|
end
|
166
195
|
end
|
167
196
|
|
@@ -209,9 +238,21 @@ module Sequel
|
|
209
238
|
|
210
239
|
# H2 expects hexadecimal strings for blob values
|
211
240
|
def literal_blob_append(sql, v)
|
212
|
-
|
241
|
+
if db.send(:version2?)
|
242
|
+
super
|
243
|
+
else
|
244
|
+
sql << "'" << v.unpack("H*").first << "'"
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def literal_false
|
249
|
+
'FALSE'
|
213
250
|
end
|
214
251
|
|
252
|
+
def literal_true
|
253
|
+
'TRUE'
|
254
|
+
end
|
255
|
+
|
215
256
|
# H2 handles fractional seconds in timestamps, but not in times
|
216
257
|
def literal_sqltime(v)
|
217
258
|
v.strftime("'%H:%M:%S'")
|
@@ -223,8 +264,12 @@ module Sequel
|
|
223
264
|
end
|
224
265
|
|
225
266
|
def select_only_offset_sql(sql)
|
226
|
-
|
227
|
-
|
267
|
+
if db.send(:version2?)
|
268
|
+
super
|
269
|
+
else
|
270
|
+
sql << " LIMIT -1 OFFSET "
|
271
|
+
literal_append(sql, @opts[:offset])
|
272
|
+
end
|
228
273
|
end
|
229
274
|
|
230
275
|
# H2 supports quoted function names.
|
data/lib/sequel/adapters/jdbc.rb
CHANGED
@@ -188,12 +188,12 @@ module Sequel
|
|
188
188
|
args = opts[:args] || []
|
189
189
|
sql = "{call #{name}(#{args.map{'?'}.join(',')})}"
|
190
190
|
synchronize(opts[:server]) do |conn|
|
191
|
-
|
191
|
+
begin
|
192
|
+
cps = conn.prepareCall(sql)
|
192
193
|
|
193
|
-
|
194
|
-
|
194
|
+
i = 0
|
195
|
+
args.each{|arg| set_ps_arg(cps, arg, i+=1)}
|
195
196
|
|
196
|
-
begin
|
197
197
|
if defined?(yield)
|
198
198
|
yield log_connection_yield(sql, conn){cps.executeQuery}
|
199
199
|
else
|
@@ -205,7 +205,7 @@ module Sequel
|
|
205
205
|
rescue *DATABASE_ERROR_CLASSES => e
|
206
206
|
raise_error(e)
|
207
207
|
ensure
|
208
|
-
cps.close
|
208
|
+
cps.close if cps
|
209
209
|
end
|
210
210
|
end
|
211
211
|
end
|
@@ -86,20 +86,26 @@ module Sequel
|
|
86
86
|
if NativePreparedStatements
|
87
87
|
# Use a native mysql2 prepared statement to implement prepared statements.
|
88
88
|
def execute_prepared_statement(ps_name, opts, &block)
|
89
|
-
|
89
|
+
if ps_name.is_a?(Sequel::Dataset::ArgumentMapper)
|
90
|
+
ps = ps_name
|
91
|
+
ps_name = ps.prepared_statement_name
|
92
|
+
else
|
93
|
+
ps = prepared_statement(ps_name)
|
94
|
+
end
|
90
95
|
sql = ps.prepared_sql
|
91
96
|
|
92
97
|
synchronize(opts[:server]) do |conn|
|
93
98
|
stmt, ps_sql = conn.prepared_statements[ps_name]
|
94
99
|
unless ps_sql == sql
|
95
100
|
stmt.close if stmt
|
96
|
-
stmt = log_connection_yield(
|
101
|
+
stmt = log_connection_yield("Preparing #{ps_name}: #{sql}", conn){conn.prepare(sql)}
|
97
102
|
conn.prepared_statements[ps_name] = [stmt, sql]
|
98
103
|
end
|
99
104
|
|
100
|
-
|
101
|
-
|
102
|
-
|
105
|
+
opts = Hash[opts]
|
106
|
+
opts[:sql] = "Executing #{ps_name || sql}"
|
107
|
+
if ps_name && ps.log_sql
|
108
|
+
opts[:log_sql] = " (#{sql})"
|
103
109
|
end
|
104
110
|
|
105
111
|
_execute(conn, stmt, opts, &block)
|
@@ -120,6 +126,7 @@ module Sequel
|
|
120
126
|
case sql
|
121
127
|
when ::Mysql2::Statement
|
122
128
|
stmt = sql
|
129
|
+
sql = opts[:sql] || ''
|
123
130
|
when Dataset
|
124
131
|
sql = sql.sql
|
125
132
|
close_stmt = true
|
@@ -98,6 +98,11 @@ module Sequel
|
|
98
98
|
# The conversion procs to use for this database
|
99
99
|
attr_reader :conversion_procs
|
100
100
|
|
101
|
+
def initialize(opts = OPTS)
|
102
|
+
super
|
103
|
+
@allow_regexp = typecast_value_boolean(opts[:setup_regexp_function])
|
104
|
+
end
|
105
|
+
|
101
106
|
# Connect to the database. Since SQLite is a file based database,
|
102
107
|
# available options are limited:
|
103
108
|
#
|
@@ -119,6 +124,12 @@ module Sequel
|
|
119
124
|
end
|
120
125
|
|
121
126
|
connection_pragmas.each{|s| log_connection_yield(s, db){db.execute_batch(s)}}
|
127
|
+
|
128
|
+
if typecast_value_boolean(opts[:setup_regexp_function])
|
129
|
+
db.create_function("regexp", 2) do |func, regexp_str, string|
|
130
|
+
func.result = Regexp.new(regexp_str).match(string) ? 1 : 0
|
131
|
+
end
|
132
|
+
end
|
122
133
|
|
123
134
|
class << db
|
124
135
|
attr_reader :prepared_statements
|
@@ -128,6 +139,12 @@ module Sequel
|
|
128
139
|
db
|
129
140
|
end
|
130
141
|
|
142
|
+
# Whether this Database instance is setup to allow regexp matching.
|
143
|
+
# True if the :setup_regexp_function option was passed when creating the Database.
|
144
|
+
def allow_regexp?
|
145
|
+
@allow_regexp
|
146
|
+
end
|
147
|
+
|
131
148
|
# Disconnect given connections from the database.
|
132
149
|
def disconnect_connection(c)
|
133
150
|
c.prepared_statements.each_value{|v| v.first.close}
|
@@ -321,6 +338,28 @@ module Sequel
|
|
321
338
|
BindArgumentMethods = prepared_statements_module(:bind, ArgumentMapper)
|
322
339
|
PreparedStatementMethods = prepared_statements_module(:prepare, BindArgumentMethods)
|
323
340
|
|
341
|
+
# Support regexp functions if using :setup_regexp_function Database option.
|
342
|
+
def complex_expression_sql_append(sql, op, args)
|
343
|
+
case op
|
344
|
+
when :~, :'!~', :'~*', :'!~*'
|
345
|
+
return super unless supports_regexp?
|
346
|
+
|
347
|
+
case_insensitive = [:'~*', :'!~*'].include?(op)
|
348
|
+
sql << 'NOT ' if [:'!~', :'!~*'].include?(op)
|
349
|
+
sql << '('
|
350
|
+
sql << 'LOWER(' if case_insensitive
|
351
|
+
literal_append(sql, args[0])
|
352
|
+
sql << ')' if case_insensitive
|
353
|
+
sql << ' REGEXP '
|
354
|
+
sql << 'LOWER(' if case_insensitive
|
355
|
+
literal_append(sql, args[1])
|
356
|
+
sql << ')' if case_insensitive
|
357
|
+
sql << ')'
|
358
|
+
else
|
359
|
+
super
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
324
363
|
def fetch_rows(sql)
|
325
364
|
execute(sql) do |result|
|
326
365
|
cps = db.conversion_procs
|
@@ -344,6 +383,11 @@ module Sequel
|
|
344
383
|
end
|
345
384
|
end
|
346
385
|
end
|
386
|
+
|
387
|
+
# Support regexp if using :setup_regexp_function Database option.
|
388
|
+
def supports_regexp?
|
389
|
+
db.allow_regexp?
|
390
|
+
end
|
347
391
|
|
348
392
|
private
|
349
393
|
|
@@ -34,7 +34,7 @@ module Sequel
|
|
34
34
|
def execute(sql, opts=OPTS, &block)
|
35
35
|
if opts[:sproc]
|
36
36
|
call_sproc(sql, opts, &block)
|
37
|
-
elsif sql.is_a?(Symbol)
|
37
|
+
elsif sql.is_a?(Symbol) || sql.is_a?(Sequel::Dataset::ArgumentMapper)
|
38
38
|
execute_prepared_statement(sql, opts, &block)
|
39
39
|
else
|
40
40
|
synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -894,9 +894,10 @@ module Sequel
|
|
894
894
|
# Clone of this dataset usable in aggregate operations. Does
|
895
895
|
# a from_self if dataset contains any parameters that would
|
896
896
|
# affect normal aggregation, or just removes an existing
|
897
|
-
# order if not.
|
897
|
+
# order if not. Also removes the row_proc, which isn't needed
|
898
|
+
# for aggregate calculations.
|
898
899
|
def aggregate_dataset
|
899
|
-
options_overlap(COUNT_FROM_SELF_OPTS) ? from_self : unordered
|
900
|
+
(options_overlap(COUNT_FROM_SELF_OPTS) ? from_self : unordered).naked
|
900
901
|
end
|
901
902
|
|
902
903
|
# Append aliasing expression to SQL string.
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Plugins
|
5
|
+
# The auto_restrict_eager_graph plugin will automatically disallow the use
|
6
|
+
# of eager_graph for associations that have associated blocks but no :graph_*
|
7
|
+
# association options. The reason for this is the block will have an effect
|
8
|
+
# during regular and eager loading, but not loading via eager_graph, and it
|
9
|
+
# is likely that whatever the block is doing should have an equivalent done
|
10
|
+
# when eager_graphing. Most likely, not including a :graph_* option was either
|
11
|
+
# an oversight (and one should be added), or use with eager_graph was never
|
12
|
+
# intended (and usage should be forbidden). Disallowing eager_graph in this
|
13
|
+
# case prevents likely unexpected behavior during eager_graph.
|
14
|
+
#
|
15
|
+
# As an example of this, consider the following code:
|
16
|
+
#
|
17
|
+
# Album.one_to_many :popular_tracks, class: :Track do |ds|
|
18
|
+
# ds = ds.where(popular: true)
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Album.eager(:popular_tracks).all
|
22
|
+
# # SELECT * FROM albums
|
23
|
+
# # SELECT * FROM tracks WHERE ((popular IS TRUE) AND (album_id IN (...)))
|
24
|
+
#
|
25
|
+
# # Notice that no condition for tracks.popular is added.
|
26
|
+
# Album.eager_graph(:popular_tracks).all
|
27
|
+
# # SELECT ... FROM albums LEFT JOIN tracks ON (tracks.album_id = albums.id)
|
28
|
+
#
|
29
|
+
# With the auto_restrict_eager_graph plugin, the eager_graph call above will
|
30
|
+
# raise an error, alerting you to the fact that you either should not be
|
31
|
+
# using eager_graph with the association, or that you should be adding an
|
32
|
+
# appropriate :graph_* option, such as:
|
33
|
+
#
|
34
|
+
# Album.one_to_many :popular_tracks, class: :Track, graph_conditions: {popular: true} do |ds|
|
35
|
+
# ds = ds.where(popular: true)
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Usage:
|
39
|
+
#
|
40
|
+
# # Automatically restrict eager_graph for associations if appropriate for all
|
41
|
+
# # model subclasses (called before loading subclasses)
|
42
|
+
# Sequel::Model.plugin :auto_restrict_eager_graph
|
43
|
+
#
|
44
|
+
# # Automatically restrict eager_graph for associations in Album class
|
45
|
+
# Album.plugin :auto_restrict_eager_graph
|
46
|
+
module AutoRestrictEagerGraph
|
47
|
+
module ClassMethods
|
48
|
+
# When defining an association, if a block is given for the association, but
|
49
|
+
# a :graph_* option is not used, disallow the use of eager_graph.
|
50
|
+
def associate(type, name, opts = OPTS, &block)
|
51
|
+
opts = super
|
52
|
+
|
53
|
+
if opts[:block] && !opts.has_key?(:allow_eager_graph) && !opts[:orig_opts].any?{|k,| /\Agraph_/ =~ k}
|
54
|
+
opts[:allow_eager_graph] = false
|
55
|
+
end
|
56
|
+
|
57
|
+
opts
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -356,7 +356,7 @@ module Sequel
|
|
356
356
|
|
357
357
|
# Keys should be an array of arrays containing key_id, key string, auth_data, and padding.
|
358
358
|
def initialize(keys)
|
359
|
-
if keys.empty?
|
359
|
+
if !keys || keys.empty?
|
360
360
|
raise Error, "Cannot initialize encryptor without encryption key"
|
361
361
|
end
|
362
362
|
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Plugins
|
5
|
+
# The enum plugin allows for easily adding methods to modify the value of
|
6
|
+
# a column. It allows treating the column itself as an enum, returning a
|
7
|
+
# symbol for the related enum value. It also allows for setting up dataset
|
8
|
+
# methods to easily find records having or not having each enum value.
|
9
|
+
#
|
10
|
+
# After loading the plugin, you can call the +enum+ method to define the
|
11
|
+
# methods. The +enum+ method accepts a symbol for the underlying
|
12
|
+
# database column, and a hash with symbol keys for the enum values.
|
13
|
+
# For example, the following call:
|
14
|
+
#
|
15
|
+
# Album.enum :status_id, good: 1, bad: 2
|
16
|
+
#
|
17
|
+
# Will define the following instance methods:
|
18
|
+
#
|
19
|
+
# Album#good! :: Change +status_id+ to +1+ (does not save the receiver)
|
20
|
+
# Album#bad! :: Change +status_id+ to +2+ (does not save the receiver)
|
21
|
+
# Album#good? :: Return whether +status_id+ is +1+
|
22
|
+
# Album#bad? :: Return whether +status_id+ is +2+
|
23
|
+
#
|
24
|
+
# It will override the following instance methods:
|
25
|
+
#
|
26
|
+
# Album#status_id :: Return +:good+/+:bad+ instead of +1+/+2+ (other values returned as-is)
|
27
|
+
# Album#status_id= :: Allow calling with +:good+/+:bad+ to set +status_id+ to +1+/+2+ (other values,
|
28
|
+
# such as <tt>'good'</tt>/<tt>'bad'</tt> set as-is)
|
29
|
+
#
|
30
|
+
# If will define the following dataset methods:
|
31
|
+
#
|
32
|
+
# Album.dataset.good :: Return a dataset filtered to rows where +status_id+ is +1+
|
33
|
+
# Album.dataset.not_good :: Return a dataset filtered to rows where +status_id+ is not +1+
|
34
|
+
# Album.dataset.bad:: Return a dataset filtered to rows where +status_id+ is +2+
|
35
|
+
# Album.dataset.not_bad:: Return a dataset filtered to rows where +status_id+ is not +2+
|
36
|
+
#
|
37
|
+
# When calling +enum+, you can also provide the following options:
|
38
|
+
#
|
39
|
+
# :prefix :: Use a prefix for methods defined for each enum value. If +true+ is provided at the value, use the column name as the prefix.
|
40
|
+
# For example, with <tt>prefix: 'status'</tt>, the instance methods defined above would be +status_good?+, +status_bad?+,
|
41
|
+
# +status_good!+, and +status_bad!+, and the dataset methods defined would be +status_good+, +status_not_good+, +status_bad+,
|
42
|
+
# and +status_not_bad+.
|
43
|
+
# :suffix :: Use a suffix for methods defined for each enum value. If +true+ is provided at the value, use the column name as the suffix.
|
44
|
+
# For example, with <tt>suffix: 'status'</tt>, the instance methods defined above would be +good_status?+, +bad_status?+,
|
45
|
+
# +good_status!+, and +bad_status!+, and the dataset methods defined would be +good_status+, +not_good_status+, +bad_status+,
|
46
|
+
# and +not_bad_status+.
|
47
|
+
# :override_accessors :: Set to +false+ to not override the column accessor methods.
|
48
|
+
# :dataset_methods :: Set to +false+ to not define dataset methods.
|
49
|
+
#
|
50
|
+
# Note that this does not use a true enum column in the database. If you are
|
51
|
+
# looking for enum support in the database, and your are using PostgreSQL,
|
52
|
+
# Sequel supports that via the pg_enum Database extension.
|
53
|
+
#
|
54
|
+
# Usage:
|
55
|
+
#
|
56
|
+
# # Make all model subclasses handle enums
|
57
|
+
# Sequel::Model.plugin :enum
|
58
|
+
#
|
59
|
+
# # Make the Album class handle enums
|
60
|
+
# Album.plugin :enum
|
61
|
+
module Enum
|
62
|
+
module ClassMethods
|
63
|
+
# Define instance and dataset methods in this class to treat column
|
64
|
+
# as a enum. See Enum documentation for usage.
|
65
|
+
def enum(column, values, opts=OPTS)
|
66
|
+
raise Sequel::Error, "enum column must be a symbol" unless column.is_a?(Symbol)
|
67
|
+
raise Sequel::Error, "enum values must be provided as a hash with symbol keys" unless values.is_a?(Hash) && values.all?{|k,| k.is_a?(Symbol)}
|
68
|
+
|
69
|
+
if prefix = opts[:prefix]
|
70
|
+
prefix = column if prefix == true
|
71
|
+
prefix = "#{prefix}_"
|
72
|
+
end
|
73
|
+
|
74
|
+
if suffix = opts[:suffix]
|
75
|
+
suffix = column if suffix == true
|
76
|
+
suffix = "_#{suffix}"
|
77
|
+
end
|
78
|
+
|
79
|
+
values = Hash[values].freeze
|
80
|
+
inverted = values.invert.freeze
|
81
|
+
|
82
|
+
unless @enum_methods
|
83
|
+
@enum_methods = Module.new
|
84
|
+
include @enum_methods
|
85
|
+
end
|
86
|
+
|
87
|
+
@enum_methods.module_eval do
|
88
|
+
unless opts[:override_accessors] == false
|
89
|
+
define_method(column) do
|
90
|
+
v = super()
|
91
|
+
inverted.fetch(v, v)
|
92
|
+
end
|
93
|
+
|
94
|
+
define_method(:"#{column}=") do |v|
|
95
|
+
super(values.fetch(v, v))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
values.each do |key, value|
|
100
|
+
define_method(:"#{prefix}#{key}#{suffix}!") do
|
101
|
+
self[column] = value
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
define_method(:"#{prefix}#{key}#{suffix}?") do
|
106
|
+
self[column] == value
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
unless opts[:dataset_methods] == false
|
112
|
+
dataset_module do
|
113
|
+
values.each do |key, value|
|
114
|
+
cond = Sequel[column=>value]
|
115
|
+
where :"#{prefix}#{key}#{suffix}", cond
|
116
|
+
where :"#{prefix}not_#{key}#{suffix}", ~cond
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -35,7 +35,7 @@ module Sequel
|
|
35
35
|
# class B < Sequel::Model; end
|
36
36
|
# a # => [A, B]
|
37
37
|
module Subclasses
|
38
|
-
NEED_SUBCLASSES = !Object.respond_to?(:subclasses)
|
38
|
+
NEED_SUBCLASSES = !Object.respond_to?(:subclasses) || Object.method(:subclasses).source_location
|
39
39
|
private_constant :NEED_SUBCLASSES
|
40
40
|
|
41
41
|
# Initialize the subclasses instance variable for the model.
|
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 = 55
|
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,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.55.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -197,6 +197,9 @@ extra_rdoc_files:
|
|
197
197
|
- doc/release_notes/5.50.0.txt
|
198
198
|
- doc/release_notes/5.51.0.txt
|
199
199
|
- doc/release_notes/5.52.0.txt
|
200
|
+
- doc/release_notes/5.53.0.txt
|
201
|
+
- doc/release_notes/5.54.0.txt
|
202
|
+
- doc/release_notes/5.55.0.txt
|
200
203
|
- doc/release_notes/5.6.0.txt
|
201
204
|
- doc/release_notes/5.7.0.txt
|
202
205
|
- doc/release_notes/5.8.0.txt
|
@@ -277,6 +280,9 @@ files:
|
|
277
280
|
- doc/release_notes/5.50.0.txt
|
278
281
|
- doc/release_notes/5.51.0.txt
|
279
282
|
- doc/release_notes/5.52.0.txt
|
283
|
+
- doc/release_notes/5.53.0.txt
|
284
|
+
- doc/release_notes/5.54.0.txt
|
285
|
+
- doc/release_notes/5.55.0.txt
|
280
286
|
- doc/release_notes/5.6.0.txt
|
281
287
|
- doc/release_notes/5.7.0.txt
|
282
288
|
- doc/release_notes/5.8.0.txt
|
@@ -475,6 +481,7 @@ files:
|
|
475
481
|
- lib/sequel/plugins/association_pks.rb
|
476
482
|
- lib/sequel/plugins/association_proxies.rb
|
477
483
|
- lib/sequel/plugins/async_thread_pool.rb
|
484
|
+
- lib/sequel/plugins/auto_restrict_eager_graph.rb
|
478
485
|
- lib/sequel/plugins/auto_validations.rb
|
479
486
|
- lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb
|
480
487
|
- lib/sequel/plugins/before_after_save.rb
|
@@ -499,6 +506,7 @@ files:
|
|
499
506
|
- lib/sequel/plugins/eager_each.rb
|
500
507
|
- lib/sequel/plugins/eager_graph_eager.rb
|
501
508
|
- lib/sequel/plugins/empty_failure_backtraces.rb
|
509
|
+
- lib/sequel/plugins/enum.rb
|
502
510
|
- lib/sequel/plugins/error_splitter.rb
|
503
511
|
- lib/sequel/plugins/finder.rb
|
504
512
|
- lib/sequel/plugins/forbid_lazy_load.rb
|
@@ -592,7 +600,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
592
600
|
- !ruby/object:Gem::Version
|
593
601
|
version: '0'
|
594
602
|
requirements: []
|
595
|
-
rubygems_version: 3.3.
|
603
|
+
rubygems_version: 3.3.7
|
596
604
|
signing_key:
|
597
605
|
specification_version: 4
|
598
606
|
summary: The Database Toolkit for Ruby
|