sequel 5.53.0 → 5.56.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 +22 -0
- data/doc/opening_databases.rdoc +3 -0
- data/doc/querying.rdoc +3 -1
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/sql.rdoc +1 -1
- data/lib/sequel/adapters/shared/sqlite.rb +6 -0
- data/lib/sequel/adapters/sqlite.rb +44 -0
- data/lib/sequel/database/schema_generator.rb +6 -5
- data/lib/sequel/database/schema_methods.rb +9 -0
- data/lib/sequel/dataset/sql.rb +3 -2
- data/lib/sequel/extensions/pg_json_ops.rb +2 -1
- data/lib/sequel/extensions/schema_dumper.rb +2 -2
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/instance_specific_default.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- metadata +15 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3505371d31fd90d388e3d889117e0dc949e73d41ebd6bee01441be9d061ea33a
|
4
|
+
data.tar.gz: fed52ae3813a0799065e695e90ab95e9633195477d01d1df9de6e6dbddbcaa23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bdd85a8fbd1ba0c0fc871e2e318836e7463d73f9677c0fbba667b6bc86fbe0cb6f0fe09026a39b9b9c79aa783c60f211ffd993b22dff6f9e0d43d3e18754351
|
7
|
+
data.tar.gz: 6ce33f8f9593e7cf73d1322104b7dd362deca59eb6397e7d4ea2705c8bb17d4087453903edd59389181d9829818fd31dc2b990dc77b4c3f3a714b846c8a5db3b
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
=== 5.56.0 (2022-05-01)
|
2
|
+
|
3
|
+
* Make alter_table add_column/add_foreign_key methods support :index option to create an index on the column (jeremyevans)
|
4
|
+
|
5
|
+
* Support creation of STRICT tables on SQLite 3.37.0+ via create_table :strict option (jeremyevans)
|
6
|
+
|
7
|
+
* Add sqlite_json_ops extension for DSL support for JSON functions and operators added in SQLite 3.38.0 (jeremyevans)
|
8
|
+
|
9
|
+
* Recognize "INTEGER" type same as "integer" type in the schema dumper, helpful on SQLite 3.37.0+ (jeremyevans)
|
10
|
+
|
11
|
+
=== 5.55.0 (2022-04-01)
|
12
|
+
|
13
|
+
* Support :setup_regexp_function Database option in the sqlite adapter to allow the use of regexps when querying (jeremyevans)
|
14
|
+
|
15
|
+
* Add auto_restrict_eager_graph plugin for automatically disallow eager_graph with associations needing but lacking graph options (jeremyevans)
|
16
|
+
|
17
|
+
* Fix placeholder literalizer optimization for dataset aggregate methods on a model dataset (belousovAV) (#1847, #1848)
|
18
|
+
|
19
|
+
=== 5.54.0 (2022-03-01)
|
20
|
+
|
21
|
+
* Add enum plugin for treating columns as enums in a model (jeremyevans) (#1839)
|
22
|
+
|
1
23
|
=== 5.53.0 (2022-02-01)
|
2
24
|
|
3
25
|
* Make Dataset#_sql_comment private when using the Database sql_comments extension (jeremyevans)
|
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,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.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* On SQLite, Database#create_table now supports a :strict option to
|
4
|
+
use the STRICT keyword when creating the table. When this option
|
5
|
+
is used, SQLite will enforce the types for each column. When using
|
6
|
+
this option, you are limited to using the following column types:
|
7
|
+
int, integer, real, text, blob, and any (any allows for dynamic
|
8
|
+
types).
|
9
|
+
|
10
|
+
* An sqlite_json_ops extension has been added, providing DSL support
|
11
|
+
for JSON functions and operators supported in SQLite 3.38.0. Usage
|
12
|
+
is similar to the pg_json_ops extension. First, you create an
|
13
|
+
appropriate object:
|
14
|
+
|
15
|
+
j = Sequel.sqlite_json_op(:json_column)
|
16
|
+
# or:
|
17
|
+
j = Sequel[:json_column].sqlite_json_op
|
18
|
+
|
19
|
+
Then, you call methods on that object to create expressions for the
|
20
|
+
JSON functions and operators:
|
21
|
+
|
22
|
+
j[1] # (json_column ->> 1)
|
23
|
+
j.get_text(1) # (json_column -> 1)
|
24
|
+
j.extract('$.a') # json_extract(json_column, '$.a')
|
25
|
+
|
26
|
+
j.array_length # json_array_length(json_column)
|
27
|
+
j.type # json_type(json_column)
|
28
|
+
j.valid # json_valid(json_column)
|
29
|
+
j.json # json(json_column)
|
30
|
+
|
31
|
+
j.insert('$.a', 1) # json_insert(json_column, '$.a', 1)
|
32
|
+
j.set('$.a', 1) # json_set(json_column, '$.a', 1)
|
33
|
+
j.replace('$.a', 1) # json_replace(json_column, '$.a', 1)
|
34
|
+
j.remove('$.a') # json_remove(json_column, '$.a')
|
35
|
+
j.patch('{"a":2}') # json_patch(json_column, '{"a":2}')
|
36
|
+
|
37
|
+
j.each # json_each(json_column)
|
38
|
+
j.tree # json_tree(json_column)
|
39
|
+
|
40
|
+
= Other Improvements
|
41
|
+
|
42
|
+
* The alter_table add_column and add_foreign_key methods now support
|
43
|
+
the :index option to create an index on the added column, for
|
44
|
+
compatibility with the :index option on the create_table column and
|
45
|
+
foreign_key methods.
|
46
|
+
|
47
|
+
* The schema_dumper extension now treats the "INTEGER" type the same
|
48
|
+
as the "integer" type. This fixes some behavior when using SQLite
|
49
|
+
3.37.0+.
|
50
|
+
|
51
|
+
* Sequel's website has a much improved visual design.
|
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')
|
@@ -337,6 +337,11 @@ module Sequel
|
|
337
337
|
ps
|
338
338
|
end
|
339
339
|
|
340
|
+
# Support creating STRICT tables via :strict option
|
341
|
+
def create_table_sql(name, generator, options)
|
342
|
+
"#{super}#{' STRICT' if options[:strict]}"
|
343
|
+
end
|
344
|
+
|
340
345
|
# SQLite support creating temporary views.
|
341
346
|
def create_view_prefix_sql(name, options)
|
342
347
|
create_view_sql_append_columns("CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}", options[:columns])
|
@@ -347,6 +352,7 @@ module Sequel
|
|
347
352
|
/foreign key constraint failed\z/i => ForeignKeyConstraintViolation,
|
348
353
|
/\A(SQLITE ERROR 275 \(CONSTRAINT_CHECK\) : )?CHECK constraint failed/ => CheckConstraintViolation,
|
349
354
|
/\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
|
355
|
+
/\Acannot store [A-Z]+ value in [A-Z]+ column / => ConstraintViolation,
|
350
356
|
/may not be NULL\z|NOT NULL constraint failed: .+\z/ => NotNullConstraintViolation,
|
351
357
|
/\ASQLITE ERROR \d+ \(\) : CHECK constraint failed: / => CheckConstraintViolation
|
352
358
|
}.freeze
|
@@ -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
|
|
@@ -387,8 +387,7 @@ module Sequel
|
|
387
387
|
end
|
388
388
|
|
389
389
|
# Add a column with the given name, type, and opts.
|
390
|
-
# See CreateTableGenerator#column for the available options
|
391
|
-
# separate +add_index+ call to add an index for the column).
|
390
|
+
# See CreateTableGenerator#column for the available options.
|
392
391
|
#
|
393
392
|
# add_column(:name, String) # ADD COLUMN name varchar(255)
|
394
393
|
#
|
@@ -401,7 +400,10 @@ module Sequel
|
|
401
400
|
# :after :: The name of an existing column that the new column should be positioned after
|
402
401
|
# :first :: Create this new column before all other existing columns
|
403
402
|
def add_column(name, type, opts = OPTS)
|
404
|
-
|
403
|
+
op = {:op => :add_column, :name => name, :type => type}.merge!(opts)
|
404
|
+
index_opts = op.delete(:index)
|
405
|
+
@operations << op
|
406
|
+
add_index(name, index_opts.is_a?(Hash) ? index_opts : OPTS) if index_opts
|
405
407
|
nil
|
406
408
|
end
|
407
409
|
|
@@ -430,8 +432,7 @@ module Sequel
|
|
430
432
|
end
|
431
433
|
|
432
434
|
# Add a foreign key with the given name and referencing the given table.
|
433
|
-
# See CreateTableGenerator#column for the available options
|
434
|
-
# separate +add_index+ call to add an index for the column).
|
435
|
+
# See CreateTableGenerator#column for the available options.
|
435
436
|
#
|
436
437
|
# You can also pass an array of column names for creating composite foreign
|
437
438
|
# keys. In this case, it will assume the columns exist and will only add
|
@@ -183,6 +183,15 @@ module Sequel
|
|
183
183
|
# keys.
|
184
184
|
# :tablespace :: The tablespace to use for the table.
|
185
185
|
#
|
186
|
+
# SQLite specific options:
|
187
|
+
# :strict :: Create a STRICT table, which checks that the values for the columns
|
188
|
+
# are the correct type (similar to all other SQL databases). Note that
|
189
|
+
# when using this option, all column types used should be one of the
|
190
|
+
# following: +int+, +integer+, +real+, +text+, +blob+, and +any+.
|
191
|
+
# The +any+ type is treated like a SQLite column in a non-strict table,
|
192
|
+
# allowing any type of data to be stored. This option is supported on
|
193
|
+
# SQLite 3.37.0+.
|
194
|
+
#
|
186
195
|
# See <tt>Schema::CreateTableGenerator</tt> and the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc].
|
187
196
|
def create_table(name, options=OPTS, &block)
|
188
197
|
remove_cached_schema(name)
|
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.
|
@@ -3,7 +3,8 @@
|
|
3
3
|
# The pg_json_ops extension adds support to Sequel's DSL to make
|
4
4
|
# it easier to call PostgreSQL JSON functions and operators (added
|
5
5
|
# first in PostgreSQL 9.3). It also supports the JSONB functions
|
6
|
-
# and operators added in PostgreSQL 9.4
|
6
|
+
# and operators added in PostgreSQL 9.4, as well as additional
|
7
|
+
# functions and operators added in later versions.
|
7
8
|
#
|
8
9
|
# To load the extension:
|
9
10
|
#
|
@@ -183,7 +183,7 @@ END_MIG
|
|
183
183
|
if options[:single_pk] && schema_autoincrementing_primary_key?(schema)
|
184
184
|
type_hash = options[:same_db] ? {:type=>schema[:db_type]} : column_schema_to_ruby_type(schema)
|
185
185
|
[:table, :key, :on_delete, :on_update, :deferrable].each{|f| type_hash[f] = schema[f] if schema[f]}
|
186
|
-
if type_hash == {:type=>Integer} || type_hash == {:type=>"integer"}
|
186
|
+
if type_hash == {:type=>Integer} || type_hash == {:type=>"integer"} || type_hash == {:type=>"INTEGER"}
|
187
187
|
type_hash.delete(:type)
|
188
188
|
elsif options[:same_db] && type_hash == {:type=>type_literal_generic_bignum_symbol(type_hash).to_s}
|
189
189
|
type_hash[:type] = :Bignum
|
@@ -225,7 +225,7 @@ END_MIG
|
|
225
225
|
col_opts[:null] = false if schema[:allow_null] == false
|
226
226
|
if table = schema[:table]
|
227
227
|
[:key, :on_delete, :on_update, :deferrable].each{|f| col_opts[f] = schema[f] if schema[f]}
|
228
|
-
col_opts[:type] = type unless type == Integer || type == 'integer'
|
228
|
+
col_opts[:type] = type unless type == Integer || type == 'integer' || type == 'INTEGER'
|
229
229
|
gen.foreign_key(name, table, col_opts)
|
230
230
|
else
|
231
231
|
gen.column(name, type, col_opts)
|
@@ -0,0 +1,255 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
#
|
3
|
+
# The sqlite_json_ops extension adds support to Sequel's DSL to make
|
4
|
+
# it easier to call SQLite JSON functions and operators (added
|
5
|
+
# first in SQLite 3.38.0).
|
6
|
+
#
|
7
|
+
# To load the extension:
|
8
|
+
#
|
9
|
+
# Sequel.extension :sqlite_json_ops
|
10
|
+
#
|
11
|
+
# This extension works by calling methods on Sequel::SQLite::JSONOp objects,
|
12
|
+
# which you can create via Sequel.sqlite_json_op:
|
13
|
+
#
|
14
|
+
# j = Sequel.sqlite_json_op(:json_column)
|
15
|
+
#
|
16
|
+
# Also, on most Sequel expression objects, you can call the sqlite_json_op method
|
17
|
+
# to create a Sequel::SQLite::JSONOp object:
|
18
|
+
#
|
19
|
+
# j = Sequel[:json_column].sqlite_json_op
|
20
|
+
#
|
21
|
+
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
22
|
+
# or you have loaded the core_refinements extension
|
23
|
+
# and have activated refinements for the file, you can also use Symbol#sqlite_json_op:
|
24
|
+
#
|
25
|
+
# j = :json_column.sqlite_json_op
|
26
|
+
#
|
27
|
+
# The following methods are available for Sequel::SQLite::JSONOp instances:
|
28
|
+
#
|
29
|
+
# j[1] # (json_column ->> 1)
|
30
|
+
# j.get(1) # (json_column ->> 1)
|
31
|
+
# j.get_text(1) # (json_column -> 1)
|
32
|
+
# j.extract('$.a') # json_extract(json_column, '$.a')
|
33
|
+
#
|
34
|
+
# j.array_length # json_array_length(json_column)
|
35
|
+
# j.type # json_type(json_column)
|
36
|
+
# j.valid # json_valid(json_column)
|
37
|
+
# j.json # json(json_column)
|
38
|
+
#
|
39
|
+
# j.insert('$.a', 1) # json_insert(json_column, '$.a', 1)
|
40
|
+
# j.set('$.a', 1) # json_set(json_column, '$.a', 1)
|
41
|
+
# j.replace('$.a', 1) # json_replace(json_column, '$.a', 1)
|
42
|
+
# j.remove('$.a') # json_remove(json_column, '$.a')
|
43
|
+
# j.patch('{"a":2}') # json_patch(json_column, '{"a":2}')
|
44
|
+
#
|
45
|
+
# j.each # json_each(json_column)
|
46
|
+
# j.tree # json_tree(json_column)
|
47
|
+
#
|
48
|
+
# Related modules: Sequel::SQLite::JSONOp
|
49
|
+
|
50
|
+
#
|
51
|
+
module Sequel
|
52
|
+
module SQLite
|
53
|
+
# The JSONOp class is a simple container for a single object that
|
54
|
+
# defines methods that yield Sequel expression objects representing
|
55
|
+
# SQLite json operators and functions.
|
56
|
+
#
|
57
|
+
# In the method documentation examples, assume that:
|
58
|
+
#
|
59
|
+
# json_op = Sequel.sqlite_json_op(:json)
|
60
|
+
class JSONOp < Sequel::SQL::Wrapper
|
61
|
+
GET = ["(".freeze, " ->> ".freeze, ")".freeze].freeze
|
62
|
+
private_constant :GET
|
63
|
+
|
64
|
+
GET_JSON = ["(".freeze, " -> ".freeze, ")".freeze].freeze
|
65
|
+
private_constant :GET_JSON
|
66
|
+
|
67
|
+
# Returns an expression for getting the JSON array element or object field
|
68
|
+
# at the specified path as a SQLite value.
|
69
|
+
#
|
70
|
+
# json_op[1] # (json ->> 1)
|
71
|
+
# json_op['a'] # (json ->> 'a')
|
72
|
+
# json_op['$.a.b'] # (json ->> '$.a.b')
|
73
|
+
# json_op['$[1][2]'] # (json ->> '$[1][2]')
|
74
|
+
def [](key)
|
75
|
+
json_op(GET, key)
|
76
|
+
end
|
77
|
+
alias get []
|
78
|
+
|
79
|
+
# Returns an expression for the length of the JSON array, or the JSON array at
|
80
|
+
# the given path.
|
81
|
+
#
|
82
|
+
# json_op.array_length # json_array_length(json)
|
83
|
+
# json_op.array_length('$[1]') # json_array_length(json, '$[1]')
|
84
|
+
def array_length(*args)
|
85
|
+
Sequel::SQL::NumericExpression.new(:NOOP, function(:array_length, *args))
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns an expression for a set of information extracted from the top-level
|
89
|
+
# members of the JSON array or object, or the top-level members of the JSON array
|
90
|
+
# or object at the given path.
|
91
|
+
#
|
92
|
+
# json_op.each # json_each(json)
|
93
|
+
# json_op.each('$.a') # json_each(json, '$.a')
|
94
|
+
def each(*args)
|
95
|
+
function(:each, *args)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns an expression for the JSON array element or object field at the specified
|
99
|
+
# path as a SQLite value, but only accept paths as arguments, and allow the use of
|
100
|
+
# multiple paths.
|
101
|
+
#
|
102
|
+
# json_op.extract('$.a') # json_extract(json, '$.a')
|
103
|
+
# json_op.extract('$.a', '$.b') # json_extract(json, '$.a', '$.b')
|
104
|
+
def extract(*a)
|
105
|
+
function(:extract, *a)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns an expression for getting the JSON array element or object field at the
|
109
|
+
# specified path as a JSON value.
|
110
|
+
#
|
111
|
+
# json_op.get_json(1) # (json -> 1)
|
112
|
+
# json_op.get_json('a') # (json -> 'a')
|
113
|
+
# json_op.get_json('$.a.b') # (json -> '$.a.b')
|
114
|
+
# json_op.get_json('$[1][2]') # (json -> '$[1][2]')
|
115
|
+
def get_json(key)
|
116
|
+
self.class.new(json_op(GET_JSON, key))
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns an expression for creating new entries at the given paths in the JSON array
|
120
|
+
# or object, but not overwriting existing entries.
|
121
|
+
#
|
122
|
+
# json_op.insert('$.a', 1) # json_insert(json, '$.a', 1)
|
123
|
+
# json_op.insert('$.a', 1, '$.b', 2) # json_insert(json, '$.a', 1, '$.b', 2)
|
124
|
+
def insert(path, value, *args)
|
125
|
+
wrapped_function(:insert, path, value, *args)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns an expression for a minified version of the JSON.
|
129
|
+
#
|
130
|
+
# json_op.json # json(json)
|
131
|
+
def json
|
132
|
+
self.class.new(SQL::Function.new(:json, self))
|
133
|
+
end
|
134
|
+
alias minify json
|
135
|
+
|
136
|
+
# Returns an expression for updating the JSON object using the RFC 7396 MergePatch algorithm
|
137
|
+
#
|
138
|
+
# json_op.patch('{"a": 1, "b": null}') # json_patch(json, '{"a": 1, "b": null}')
|
139
|
+
def patch(json_patch)
|
140
|
+
wrapped_function(:patch, json_patch)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns an expression for removing entries at the given paths from the JSON array or object.
|
144
|
+
#
|
145
|
+
# json_op.remove('$.a') # json_remove(json, '$.a')
|
146
|
+
# json_op.remove('$.a', '$.b') # json_remove(json, '$.a', '$.b')
|
147
|
+
def remove(path, *paths)
|
148
|
+
wrapped_function(:remove, path, *paths)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Returns an expression for replacing entries at the given paths in the JSON array or object,
|
152
|
+
# but not creating new entries.
|
153
|
+
#
|
154
|
+
# json_op.replace('$.a', 1) # json_replace(json, '$.a', 1)
|
155
|
+
# json_op.replace('$.a', 1, '$.b', 2) # json_replace(json, '$.a', 1, '$.b', 2)
|
156
|
+
def replace(path, value, *args)
|
157
|
+
wrapped_function(:replace, path, value, *args)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns an expression for creating or replacing entries at the given paths in the
|
161
|
+
# JSON array or object.
|
162
|
+
#
|
163
|
+
# json_op.set('$.a', 1) # json_set(json, '$.a', 1)
|
164
|
+
# json_op.set('$.a', 1, '$.b', 2) # json_set(json, '$.a', 1, '$.b', 2)
|
165
|
+
def set(path, value, *args)
|
166
|
+
wrapped_function(:set, path, value, *args)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Returns an expression for a set of information extracted from the JSON array or object, or
|
170
|
+
# the JSON array or object at the given path.
|
171
|
+
#
|
172
|
+
# json_op.tree # json_tree(json)
|
173
|
+
# json_op.tree('$.a') # json_tree(json, '$.a')
|
174
|
+
def tree(*args)
|
175
|
+
function(:tree, *args)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns an expression for the type of the JSON value or the JSON value at the given path.
|
179
|
+
#
|
180
|
+
# json_op.type # json_type(json)
|
181
|
+
# json_op.type('$[1]') # json_type(json, '$[1]')
|
182
|
+
def type(*args)
|
183
|
+
Sequel::SQL::StringExpression.new(:NOOP, function(:type, *args))
|
184
|
+
end
|
185
|
+
alias typeof type
|
186
|
+
|
187
|
+
# Returns a boolean expression for whether the JSON is valid or not.
|
188
|
+
def valid
|
189
|
+
Sequel::SQL::BooleanExpression.new(:NOOP, function(:valid))
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
|
194
|
+
# Internals of the [], get, get_json methods, using a placeholder literal string.
|
195
|
+
def json_op(str, args)
|
196
|
+
self.class.new(Sequel::SQL::PlaceholderLiteralString.new(str, [self, args]))
|
197
|
+
end
|
198
|
+
|
199
|
+
# Internals of the methods that return functions prefixed with +json_+.
|
200
|
+
def function(name, *args)
|
201
|
+
SQL::Function.new("json_#{name}", self, *args)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Internals of the methods that return functions prefixed with +json_+, that
|
205
|
+
# return JSON values.
|
206
|
+
def wrapped_function(*args)
|
207
|
+
self.class.new(function(*args))
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
module JSONOpMethods
|
212
|
+
# Wrap the receiver in an JSONOp so you can easily use the SQLite
|
213
|
+
# json functions and operators with it.
|
214
|
+
def sqlite_json_op
|
215
|
+
JSONOp.new(self)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
module SQL::Builders
|
221
|
+
# Return the object wrapped in an SQLite::JSONOp.
|
222
|
+
def sqlite_json_op(v)
|
223
|
+
case v
|
224
|
+
when SQLite::JSONOp
|
225
|
+
v
|
226
|
+
else
|
227
|
+
SQLite::JSONOp.new(v)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
class SQL::GenericExpression
|
233
|
+
include Sequel::SQLite::JSONOpMethods
|
234
|
+
end
|
235
|
+
|
236
|
+
class LiteralString
|
237
|
+
include Sequel::SQLite::JSONOpMethods
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# :nocov:
|
242
|
+
if Sequel.core_extensions?
|
243
|
+
class Symbol
|
244
|
+
include Sequel::SQLite::JSONOpMethods
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
if defined?(Sequel::CoreRefinements)
|
249
|
+
module Sequel::CoreRefinements
|
250
|
+
refine Symbol do
|
251
|
+
send INCLUDE_METH, Sequel::SQLite::JSONOpMethods
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
# :nocov:
|
@@ -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
|
@@ -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
|
@@ -29,7 +29,7 @@ module Sequel
|
|
29
29
|
# end
|
30
30
|
#
|
31
31
|
# +first_track+ is not instance specific, but +last_track+ and +recent_tracks+ are.
|
32
|
-
# +
|
32
|
+
# +last_track+ is because the +num_tracks+ call in the block is calling
|
33
33
|
# <tt>Album#num_tracks</tt>. +recent_tracks+ is because the value will change over
|
34
34
|
# time. This plugin allows you to find these cases, and set the :instance_specific
|
35
35
|
# option appropriately for them:
|
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 = 56
|
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.56.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-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -198,6 +198,9 @@ extra_rdoc_files:
|
|
198
198
|
- doc/release_notes/5.51.0.txt
|
199
199
|
- doc/release_notes/5.52.0.txt
|
200
200
|
- doc/release_notes/5.53.0.txt
|
201
|
+
- doc/release_notes/5.54.0.txt
|
202
|
+
- doc/release_notes/5.55.0.txt
|
203
|
+
- doc/release_notes/5.56.0.txt
|
201
204
|
- doc/release_notes/5.6.0.txt
|
202
205
|
- doc/release_notes/5.7.0.txt
|
203
206
|
- doc/release_notes/5.8.0.txt
|
@@ -279,6 +282,9 @@ files:
|
|
279
282
|
- doc/release_notes/5.51.0.txt
|
280
283
|
- doc/release_notes/5.52.0.txt
|
281
284
|
- doc/release_notes/5.53.0.txt
|
285
|
+
- doc/release_notes/5.54.0.txt
|
286
|
+
- doc/release_notes/5.55.0.txt
|
287
|
+
- doc/release_notes/5.56.0.txt
|
282
288
|
- doc/release_notes/5.6.0.txt
|
283
289
|
- doc/release_notes/5.7.0.txt
|
284
290
|
- doc/release_notes/5.8.0.txt
|
@@ -449,6 +455,7 @@ files:
|
|
449
455
|
- lib/sequel/extensions/sql_comments.rb
|
450
456
|
- lib/sequel/extensions/sql_expr.rb
|
451
457
|
- lib/sequel/extensions/sql_log_normalizer.rb
|
458
|
+
- lib/sequel/extensions/sqlite_json_ops.rb
|
452
459
|
- lib/sequel/extensions/string_agg.rb
|
453
460
|
- lib/sequel/extensions/string_date_time.rb
|
454
461
|
- lib/sequel/extensions/symbol_aref.rb
|
@@ -477,6 +484,7 @@ files:
|
|
477
484
|
- lib/sequel/plugins/association_pks.rb
|
478
485
|
- lib/sequel/plugins/association_proxies.rb
|
479
486
|
- lib/sequel/plugins/async_thread_pool.rb
|
487
|
+
- lib/sequel/plugins/auto_restrict_eager_graph.rb
|
480
488
|
- lib/sequel/plugins/auto_validations.rb
|
481
489
|
- lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb
|
482
490
|
- lib/sequel/plugins/before_after_save.rb
|
@@ -501,6 +509,7 @@ files:
|
|
501
509
|
- lib/sequel/plugins/eager_each.rb
|
502
510
|
- lib/sequel/plugins/eager_graph_eager.rb
|
503
511
|
- lib/sequel/plugins/empty_failure_backtraces.rb
|
512
|
+
- lib/sequel/plugins/enum.rb
|
504
513
|
- lib/sequel/plugins/error_splitter.rb
|
505
514
|
- lib/sequel/plugins/finder.rb
|
506
515
|
- lib/sequel/plugins/forbid_lazy_load.rb
|
@@ -563,13 +572,13 @@ files:
|
|
563
572
|
- lib/sequel/sql.rb
|
564
573
|
- lib/sequel/timezones.rb
|
565
574
|
- lib/sequel/version.rb
|
566
|
-
homepage:
|
575
|
+
homepage: https://sequel.jeremyevans.net
|
567
576
|
licenses:
|
568
577
|
- MIT
|
569
578
|
metadata:
|
570
579
|
bug_tracker_uri: https://github.com/jeremyevans/sequel/issues
|
571
|
-
changelog_uri:
|
572
|
-
documentation_uri:
|
580
|
+
changelog_uri: https://sequel.jeremyevans.net/rdoc/files/CHANGELOG.html
|
581
|
+
documentation_uri: https://sequel.jeremyevans.net/documentation.html
|
573
582
|
mailing_list_uri: https://github.com/jeremyevans/sequel/discussions
|
574
583
|
source_code_uri: https://github.com/jeremyevans/sequel
|
575
584
|
post_install_message:
|
@@ -594,7 +603,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
594
603
|
- !ruby/object:Gem::Version
|
595
604
|
version: '0'
|
596
605
|
requirements: []
|
597
|
-
rubygems_version: 3.3.
|
606
|
+
rubygems_version: 3.3.7
|
598
607
|
signing_key:
|
599
608
|
specification_version: 4
|
600
609
|
summary: The Database Toolkit for Ruby
|