sequel 3.36.1 → 3.37.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.
- data/CHANGELOG +84 -0
- data/Rakefile +13 -0
- data/bin/sequel +12 -16
- data/doc/advanced_associations.rdoc +36 -67
- data/doc/association_basics.rdoc +11 -16
- data/doc/release_notes/3.37.0.txt +338 -0
- data/doc/schema_modification.rdoc +4 -0
- data/lib/sequel/adapters/jdbc/h2.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +26 -8
- data/lib/sequel/adapters/mysql2.rb +4 -3
- data/lib/sequel/adapters/odbc/mssql.rb +2 -2
- data/lib/sequel/adapters/postgres.rb +4 -60
- data/lib/sequel/adapters/shared/mssql.rb +2 -1
- data/lib/sequel/adapters/shared/mysql.rb +0 -5
- data/lib/sequel/adapters/shared/postgres.rb +68 -2
- data/lib/sequel/adapters/shared/sqlite.rb +17 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +12 -1
- data/lib/sequel/adapters/utils/pg_types.rb +76 -0
- data/lib/sequel/core.rb +13 -0
- data/lib/sequel/database/misc.rb +41 -1
- data/lib/sequel/database/schema_generator.rb +23 -10
- data/lib/sequel/database/schema_methods.rb +26 -4
- data/lib/sequel/dataset/graph.rb +2 -1
- data/lib/sequel/dataset/query.rb +62 -2
- data/lib/sequel/extensions/_pretty_table.rb +7 -3
- data/lib/sequel/extensions/arbitrary_servers.rb +5 -4
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +13 -2
- data/lib/sequel/extensions/core_extensions.rb +6 -0
- data/lib/sequel/extensions/eval_inspect.rb +158 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +4 -1
- data/lib/sequel/extensions/named_timezones.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +4 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +219 -168
- data/lib/sequel/extensions/pg_array_ops.rb +7 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -4
- data/lib/sequel/extensions/pg_hstore.rb +3 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +7 -2
- data/lib/sequel/extensions/pg_inet.rb +28 -3
- data/lib/sequel/extensions/pg_interval.rb +192 -0
- data/lib/sequel/extensions/pg_json.rb +21 -9
- data/lib/sequel/extensions/pg_range.rb +487 -0
- data/lib/sequel/extensions/pg_range_ops.rb +122 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +3 -2
- data/lib/sequel/extensions/pretty_table.rb +12 -1
- data/lib/sequel/extensions/query.rb +4 -0
- data/lib/sequel/extensions/query_literals.rb +6 -6
- data/lib/sequel/extensions/schema_dumper.rb +39 -38
- data/lib/sequel/extensions/select_remove.rb +4 -0
- data/lib/sequel/extensions/server_block.rb +3 -2
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -0
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +9 -3
- data/lib/sequel/extensions/to_dot.rb +4 -0
- data/lib/sequel/model/associations.rb +150 -91
- data/lib/sequel/plugins/identity_map.rb +2 -2
- data/lib/sequel/plugins/list.rb +1 -0
- data/lib/sequel/plugins/many_through_many.rb +33 -32
- data/lib/sequel/plugins/nested_attributes.rb +11 -3
- data/lib/sequel/plugins/rcte_tree.rb +2 -2
- data/lib/sequel/plugins/schema.rb +1 -1
- data/lib/sequel/sql.rb +14 -14
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +25 -0
- data/spec/adapters/postgres_spec.rb +572 -28
- data/spec/adapters/sqlite_spec.rb +16 -1
- data/spec/core/database_spec.rb +61 -2
- data/spec/core/dataset_spec.rb +92 -0
- data/spec/core/expression_filters_spec.rb +12 -0
- data/spec/extensions/arbitrary_servers_spec.rb +1 -1
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- data/spec/extensions/eval_inspect_spec.rb +58 -0
- data/spec/extensions/json_serializer_spec.rb +0 -6
- data/spec/extensions/list_spec.rb +1 -1
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +81 -0
- data/spec/extensions/nested_attributes_spec.rb +21 -4
- data/spec/extensions/pg_array_ops_spec.rb +1 -11
- data/spec/extensions/pg_array_spec.rb +181 -90
- data/spec/extensions/pg_auto_parameterize_spec.rb +3 -3
- data/spec/extensions/pg_hstore_spec.rb +1 -3
- data/spec/extensions/pg_inet_spec.rb +6 -1
- data/spec/extensions/pg_interval_spec.rb +73 -0
- data/spec/extensions/pg_json_spec.rb +5 -9
- data/spec/extensions/pg_range_ops_spec.rb +49 -0
- data/spec/extensions/pg_range_spec.rb +372 -0
- data/spec/extensions/pg_statement_cache_spec.rb +1 -2
- data/spec/extensions/query_literals_spec.rb +1 -2
- data/spec/extensions/schema_dumper_spec.rb +48 -89
- data/spec/extensions/serialization_spec.rb +1 -5
- data/spec/extensions/server_block_spec.rb +2 -2
- data/spec/extensions/spec_helper.rb +12 -2
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/integration/associations_test.rb +4 -4
- data/spec/integration/database_test.rb +2 -2
- data/spec/integration/dataset_test.rb +4 -4
- data/spec/integration/eager_loader_test.rb +6 -6
- data/spec/integration/plugin_test.rb +2 -2
- data/spec/integration/spec_helper.rb +2 -2
- data/spec/model/association_reflection_spec.rb +5 -0
- data/spec/model/associations_spec.rb +156 -49
- data/spec/model/eager_loading_spec.rb +137 -2
- data/spec/model/model_spec.rb +10 -10
- metadata +15 -2
data/lib/sequel/core.rb
CHANGED
|
@@ -228,6 +228,19 @@ module Sequel
|
|
|
228
228
|
def self.quote_identifiers=(value)
|
|
229
229
|
Database.quote_identifiers = value
|
|
230
230
|
end
|
|
231
|
+
|
|
232
|
+
# Convert each item in the array to the correct type, handling multi-dimensional
|
|
233
|
+
# arrays. For each element in the array or subarrays, call the converter,
|
|
234
|
+
# unless the value is nil.
|
|
235
|
+
def self.recursive_map(array, converter)
|
|
236
|
+
array.map do |i|
|
|
237
|
+
if i.is_a?(Array)
|
|
238
|
+
recursive_map(i, converter)
|
|
239
|
+
elsif i
|
|
240
|
+
converter.call(i)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
231
244
|
|
|
232
245
|
# Require all given +files+ which should be in the same or a subdirectory of
|
|
233
246
|
# this file. If a +subdir+ is given, assume all +files+ are in that subdir.
|
data/lib/sequel/database/misc.rb
CHANGED
|
@@ -4,6 +4,28 @@ module Sequel
|
|
|
4
4
|
# :section: 7 - Miscellaneous methods
|
|
5
5
|
# These methods don't fit neatly into another category.
|
|
6
6
|
# ---------------------
|
|
7
|
+
|
|
8
|
+
# Hash of extension name symbols to callable objects to load the extension
|
|
9
|
+
# into the Database object (usually by extending it with a module defined
|
|
10
|
+
# in the extension).
|
|
11
|
+
EXTENSIONS = {}
|
|
12
|
+
|
|
13
|
+
# Register an extension callback for Database objects. ext should be the
|
|
14
|
+
# extension name symbol, and mod should either be a Module that the
|
|
15
|
+
# database is extended with, or a callable object called with the database
|
|
16
|
+
# object. If mod is not provided, a block can be provided and is treated
|
|
17
|
+
# as the mod object.
|
|
18
|
+
def self.register_extension(ext, mod=nil, &block)
|
|
19
|
+
if mod
|
|
20
|
+
raise(Error, "cannot provide both mod and block to Database.register_extension") if block
|
|
21
|
+
if mod.is_a?(Module)
|
|
22
|
+
block = proc{|db| db.extend(mod)}
|
|
23
|
+
else
|
|
24
|
+
block = mod
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
Sequel.synchronize{EXTENSIONS[ext] = block}
|
|
28
|
+
end
|
|
7
29
|
|
|
8
30
|
# Converts a uri to an options hash. These options are then passed
|
|
9
31
|
# to a newly created database object.
|
|
@@ -107,6 +129,23 @@ module Sequel
|
|
|
107
129
|
type_literal(:type=>type)
|
|
108
130
|
end
|
|
109
131
|
|
|
132
|
+
# Load an extension into the receiver. In addition to requiring the extension file, this
|
|
133
|
+
# also modifies the database to work with the extension (usually extending it with a
|
|
134
|
+
# module defined in the extension file). If no related extension file exists or the
|
|
135
|
+
# extension does not have specific support for Database objects, an Error will be raised.
|
|
136
|
+
# Returns self.
|
|
137
|
+
def extension(*exts)
|
|
138
|
+
Sequel.extension(*exts)
|
|
139
|
+
exts.each do |ext|
|
|
140
|
+
if pr = Sequel.synchronize{EXTENSIONS[ext]}
|
|
141
|
+
pr.call(self)
|
|
142
|
+
else
|
|
143
|
+
raise(Error, "Extension #{ext} does not have specific support handling individual databases")
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
self
|
|
147
|
+
end
|
|
148
|
+
|
|
110
149
|
# Convert the given timestamp from the application's timezone,
|
|
111
150
|
# to the databases's timezone or the default database timezone if
|
|
112
151
|
# the database does not have a timezone.
|
|
@@ -362,7 +401,8 @@ module Sequel
|
|
|
362
401
|
if value.is_a?(SQLTime)
|
|
363
402
|
value
|
|
364
403
|
else
|
|
365
|
-
|
|
404
|
+
# specifically check for nsec == 0 value to work around JRuby 1.6 ruby 1.9 mode bug
|
|
405
|
+
SQLTime.create(value.hour, value.min, value.sec, (value.respond_to?(:nsec) && value.nsec != 0) ? value.nsec/1000.0 : value.usec)
|
|
366
406
|
end
|
|
367
407
|
when String
|
|
368
408
|
Sequel.string_to_time(value)
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
# The Schema module holds the schema generators.
|
|
3
3
|
module Schema
|
|
4
|
-
# Schema::
|
|
4
|
+
# Schema::CreateTableGenerator is an internal class that the user is not expected
|
|
5
5
|
# to instantiate directly. Instances are created by Database#create_table.
|
|
6
6
|
# It is used to specify table creation parameters. It takes a Database
|
|
7
7
|
# object and a block of column/index/constraint specifications, and
|
|
8
8
|
# gives the Database a table description, which the database uses to
|
|
9
9
|
# create a table.
|
|
10
10
|
#
|
|
11
|
-
# Schema::
|
|
11
|
+
# Schema::CreateTableGenerator has some methods but also includes method_missing,
|
|
12
12
|
# allowing users to specify column type as a method instead of using
|
|
13
13
|
# the column method, which makes for a nicer DSL.
|
|
14
14
|
#
|
|
15
15
|
# For more information on Sequel's support for schema modification, see
|
|
16
16
|
# the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
|
|
17
|
-
class
|
|
17
|
+
class CreateTableGenerator
|
|
18
18
|
# Classes specifying generic types that Sequel will convert to database-specific types.
|
|
19
19
|
GENERIC_TYPES=[String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
|
|
20
20
|
Date, DateTime, Time, File, TrueClass, FalseClass]
|
|
@@ -255,6 +255,9 @@ module Sequel
|
|
|
255
255
|
|
|
256
256
|
add_type_method(*GENERIC_TYPES)
|
|
257
257
|
end
|
|
258
|
+
|
|
259
|
+
# Alias of CreateTableGenerator for backwards compatibility.
|
|
260
|
+
Generator = CreateTableGenerator
|
|
258
261
|
|
|
259
262
|
# Schema::AlterTableGenerator is an internal class that the user is not expected
|
|
260
263
|
# to instantiate directly. Instances are created by Database#alter_table.
|
|
@@ -278,7 +281,7 @@ module Sequel
|
|
|
278
281
|
end
|
|
279
282
|
|
|
280
283
|
# Add a column with the given name, type, and opts to the DDL for the table.
|
|
281
|
-
# See
|
|
284
|
+
# See CreateTableGenerator#column for the available options.
|
|
282
285
|
#
|
|
283
286
|
# add_column(:name, String) # ADD COLUMN name varchar(255)
|
|
284
287
|
def add_column(name, type, opts = {})
|
|
@@ -286,7 +289,7 @@ module Sequel
|
|
|
286
289
|
end
|
|
287
290
|
|
|
288
291
|
# Add a constraint with the given name and args to the DDL for the table.
|
|
289
|
-
# See
|
|
292
|
+
# See CreateTableGenerator#constraint.
|
|
290
293
|
#
|
|
291
294
|
# add_constraint(:valid_name, :name.like('A%'))
|
|
292
295
|
# # ADD CONSTRAINT valid_name CHECK (name LIKE 'A%')
|
|
@@ -303,7 +306,7 @@ module Sequel
|
|
|
303
306
|
end
|
|
304
307
|
|
|
305
308
|
# Add a foreign key with the given name and referencing the given table
|
|
306
|
-
# to the DDL for the table. See
|
|
309
|
+
# to the DDL for the table. See CreateTableGenerator#column for the available options.
|
|
307
310
|
#
|
|
308
311
|
# You can also pass an array of column names for creating composite foreign
|
|
309
312
|
# keys. In this case, it will assume the columns exist and will only add
|
|
@@ -314,26 +317,36 @@ module Sequel
|
|
|
314
317
|
#
|
|
315
318
|
# add_foreign_key(:artist_id, :table) # ADD COLUMN artist_id integer REFERENCES table
|
|
316
319
|
# add_foreign_key([:name], :table) # ADD FOREIGN KEY (name) REFERENCES table
|
|
320
|
+
#
|
|
321
|
+
# PostgreSQL specific options:
|
|
322
|
+
#
|
|
323
|
+
# :not_valid :: Set to true to add the constraint with the NOT VALID syntax.
|
|
324
|
+
# This makes it so that future inserts must respect referential
|
|
325
|
+
# integrity, but allows the constraint to be added even if existing
|
|
326
|
+
# column values reference rows that do not exist. After all the
|
|
327
|
+
# existing data has been cleaned up, validate_constraint can be used
|
|
328
|
+
# to mark the constraint as valid. Note that this option only makes
|
|
329
|
+
# sense when using an array of columns.
|
|
317
330
|
def add_foreign_key(name, table, opts = {})
|
|
318
331
|
return add_composite_foreign_key(name, table, opts) if name.is_a?(Array)
|
|
319
332
|
add_column(name, Integer, {:table=>table}.merge(opts))
|
|
320
333
|
end
|
|
321
334
|
|
|
322
335
|
# Add a full text index on the given columns to the DDL for the table.
|
|
323
|
-
# See
|
|
336
|
+
# See CreateTableGenerator#index for available options.
|
|
324
337
|
def add_full_text_index(columns, opts = {})
|
|
325
338
|
add_index(columns, {:type=>:full_text}.merge(opts))
|
|
326
339
|
end
|
|
327
340
|
|
|
328
341
|
# Add an index on the given columns to the DDL for the table. See
|
|
329
|
-
#
|
|
342
|
+
# CreateTableGenerator#index for available options.
|
|
330
343
|
#
|
|
331
344
|
# add_index(:artist_id) # CREATE INDEX table_artist_id_index ON table (artist_id)
|
|
332
345
|
def add_index(columns, opts = {})
|
|
333
346
|
@operations << {:op => :add_index, :columns => Array(columns)}.merge(opts)
|
|
334
347
|
end
|
|
335
348
|
|
|
336
|
-
# Add a primary key to the DDL for the table. See
|
|
349
|
+
# Add a primary key to the DDL for the table. See CreateTableGenerator#column
|
|
337
350
|
# for the available options. Like +add_foreign_key+, if you specify
|
|
338
351
|
# the column name as an array, it just creates a constraint:
|
|
339
352
|
#
|
|
@@ -346,7 +359,7 @@ module Sequel
|
|
|
346
359
|
end
|
|
347
360
|
|
|
348
361
|
# Add a spatial index on the given columns to the DDL for the table.
|
|
349
|
-
# See
|
|
362
|
+
# See CreateTableGenerator#index for available options.
|
|
350
363
|
def add_spatial_index(columns, opts = {})
|
|
351
364
|
add_index(columns, {:type=>:spatial}.merge(opts))
|
|
352
365
|
end
|
|
@@ -68,12 +68,18 @@ module Sequel
|
|
|
68
68
|
#
|
|
69
69
|
# See <tt>Schema::AlterTableGenerator</tt> and the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
|
|
70
70
|
def alter_table(name, generator=nil, &block)
|
|
71
|
-
generator ||=
|
|
71
|
+
generator ||= alter_table_generator(&block)
|
|
72
72
|
remove_cached_schema(name)
|
|
73
73
|
apply_alter_table(name, generator.operations)
|
|
74
74
|
nil
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
+
# Return a new Schema::AlterTableGenerator instance with the receiver as
|
|
78
|
+
# the database and the given block.
|
|
79
|
+
def alter_table_generator(&block)
|
|
80
|
+
alter_table_generator_class.new(self, &block)
|
|
81
|
+
end
|
|
82
|
+
|
|
77
83
|
# Create a join table using a hash of foreign keys to referenced
|
|
78
84
|
# table names. Example:
|
|
79
85
|
#
|
|
@@ -146,12 +152,12 @@ module Sequel
|
|
|
146
152
|
# See <tt>Schema::Generator</tt> and the {"Schema Modification" guide}[link:files/doc/schema_modification_rdoc.html].
|
|
147
153
|
def create_table(name, options={}, &block)
|
|
148
154
|
remove_cached_schema(name)
|
|
149
|
-
options = {:generator=>options} if options.is_a?(Schema::
|
|
155
|
+
options = {:generator=>options} if options.is_a?(Schema::CreateTableGenerator)
|
|
150
156
|
if sql = options[:as]
|
|
151
157
|
raise(Error, "can't provide both :as option and block to create_table") if block
|
|
152
158
|
create_table_as(name, sql, options)
|
|
153
159
|
else
|
|
154
|
-
generator = options[:generator] ||
|
|
160
|
+
generator = options[:generator] || create_table_generator(&block)
|
|
155
161
|
create_table_from_generator(name, generator, options)
|
|
156
162
|
create_table_indexes_from_generator(name, generator, options)
|
|
157
163
|
nil
|
|
@@ -181,6 +187,12 @@ module Sequel
|
|
|
181
187
|
create_table(name, options, &block)
|
|
182
188
|
end
|
|
183
189
|
end
|
|
190
|
+
|
|
191
|
+
# Return a new Schema::CreateTableGenerator instance with the receiver as
|
|
192
|
+
# the database and the given block.
|
|
193
|
+
def create_table_generator(&block)
|
|
194
|
+
create_table_generator_class.new(self, &block)
|
|
195
|
+
end
|
|
184
196
|
|
|
185
197
|
# Creates a view, replacing it if it already exists:
|
|
186
198
|
#
|
|
@@ -324,6 +336,11 @@ module Sequel
|
|
|
324
336
|
alter_table_sql_list(name, ops).flatten.each{|sql| execute_ddl(sql)}
|
|
325
337
|
end
|
|
326
338
|
|
|
339
|
+
# The class used for alter_table generators.
|
|
340
|
+
def alter_table_generator_class
|
|
341
|
+
Schema::AlterTableGenerator
|
|
342
|
+
end
|
|
343
|
+
|
|
327
344
|
# The SQL to execute to modify the DDL for the given table name. op
|
|
328
345
|
# should be one of the operations returned by the AlterTableGenerator.
|
|
329
346
|
def alter_table_sql(table, op)
|
|
@@ -465,6 +482,11 @@ module Sequel
|
|
|
465
482
|
execute_ddl(create_table_sql(name, generator, options))
|
|
466
483
|
end
|
|
467
484
|
|
|
485
|
+
# The class used for create_table generators.
|
|
486
|
+
def create_table_generator_class
|
|
487
|
+
Schema::CreateTableGenerator
|
|
488
|
+
end
|
|
489
|
+
|
|
468
490
|
# Execute the create index statements using the generator.
|
|
469
491
|
def create_table_indexes_from_generator(name, generator, options)
|
|
470
492
|
e = options[:ignore_index_errors] || options[:if_not_exists]
|
|
@@ -621,7 +643,7 @@ module Sequel
|
|
|
621
643
|
|
|
622
644
|
# Return true if the given column schema represents an autoincrementing primary key.
|
|
623
645
|
def schema_autoincrementing_primary_key?(schema)
|
|
624
|
-
!!schema[:primary_key]
|
|
646
|
+
!!(schema[:primary_key] && schema[:db_type] =~ /int/io)
|
|
625
647
|
end
|
|
626
648
|
|
|
627
649
|
# The dataset to use for proxying certain schema methods.
|
data/lib/sequel/dataset/graph.rb
CHANGED
|
@@ -63,6 +63,7 @@ module Sequel
|
|
|
63
63
|
# determines the alias to use.
|
|
64
64
|
# :implicit_qualifier :: The qualifier of implicit conditions, see #join_table.
|
|
65
65
|
# :join_type :: The type of join to use (passed to +join_table+). Defaults to :left_outer.
|
|
66
|
+
# :qualify:: The type of qualification to do, see #join_table.
|
|
66
67
|
# :select :: An array of columns to select. When not used, selects
|
|
67
68
|
# all columns in the given dataset. When set to false, selects no
|
|
68
69
|
# columns and is like simply joining the tables, though graph keeps
|
|
@@ -106,7 +107,7 @@ module Sequel
|
|
|
106
107
|
ds = (!@opts[:graph] && (@opts[:from].length > 1 || @opts[:join])) ? from_self(:alias=>options[:from_self_alias] || first_source) : self
|
|
107
108
|
|
|
108
109
|
# Join the table early in order to avoid cloning the dataset twice
|
|
109
|
-
ds = ds.join_table(options[:join_type] || :left_outer, table, join_conditions, :table_alias=>table_alias, :implicit_qualifier=>options[:implicit_qualifier], &block)
|
|
110
|
+
ds = ds.join_table(options[:join_type] || :left_outer, table, join_conditions, :table_alias=>table_alias, :implicit_qualifier=>options[:implicit_qualifier], :qualify=>options[:qualify], &block)
|
|
110
111
|
opts = ds.opts
|
|
111
112
|
|
|
112
113
|
# Whether to include the table in the result set
|
data/lib/sequel/dataset/query.rb
CHANGED
|
@@ -5,6 +5,11 @@ module Sequel
|
|
|
5
5
|
# These methods all return modified copies of the receiver.
|
|
6
6
|
# ---------------------
|
|
7
7
|
|
|
8
|
+
# Hash of extension name symbols to callable objects to load the extension
|
|
9
|
+
# into the Dataset object (usually by extending it with a module defined
|
|
10
|
+
# in the extension).
|
|
11
|
+
EXTENSIONS = {}
|
|
12
|
+
|
|
8
13
|
# The dataset options that require the removal of cached columns
|
|
9
14
|
# if changed.
|
|
10
15
|
COLUMN_CHANGE_OPTS = [:select, :sql, :from, :join].freeze
|
|
@@ -37,6 +42,27 @@ module Sequel
|
|
|
37
42
|
unlimited unordered where with with_recursive with_sql
|
|
38
43
|
METHS
|
|
39
44
|
|
|
45
|
+
# Register an extension callback for Dataset objects. ext should be the
|
|
46
|
+
# extension name symbol, and mod should either be a Module that the
|
|
47
|
+
# dataset is extended with, or a callable object called with the database
|
|
48
|
+
# object. If mod is not provided, a block can be provided and is treated
|
|
49
|
+
# as the mod object.
|
|
50
|
+
#
|
|
51
|
+
# If mod is a module, this also registers a Database extension that will
|
|
52
|
+
# extend all of the database's datasets.
|
|
53
|
+
def self.register_extension(ext, mod=nil, &block)
|
|
54
|
+
if mod
|
|
55
|
+
raise(Error, "cannot provide both mod and block to Dataset.register_extension") if block
|
|
56
|
+
if mod.is_a?(Module)
|
|
57
|
+
block = proc{|ds| ds.extend(mod)}
|
|
58
|
+
Sequel::Database.register_extension(ext){|db| db.extend_datasets(mod)}
|
|
59
|
+
else
|
|
60
|
+
block = mod
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
Sequel.synchronize{EXTENSIONS[ext] = block}
|
|
64
|
+
end
|
|
65
|
+
|
|
40
66
|
# Adds an further filter to an existing filter using AND. If no filter
|
|
41
67
|
# exists an error is raised. This method is identical to #filter except
|
|
42
68
|
# it expects an existing filter.
|
|
@@ -130,6 +156,28 @@ module Sequel
|
|
|
130
156
|
_filter_or_exclude(true, :where, *cond, &block)
|
|
131
157
|
end
|
|
132
158
|
|
|
159
|
+
# Return a clone of the dataset loaded with the extensions, see #extension!.
|
|
160
|
+
def extension(*exts)
|
|
161
|
+
clone.extension!(*exts)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Load an extension into the receiver. In addition to requiring the extension file, this
|
|
165
|
+
# also modifies the dataset to work with the extension (usually extending it with a
|
|
166
|
+
# module defined in the extension file). If no related extension file exists or the
|
|
167
|
+
# extension does not have specific support for Database objects, an Error will be raised.
|
|
168
|
+
# Returns self.
|
|
169
|
+
def extension!(*exts)
|
|
170
|
+
Sequel.extension(*exts)
|
|
171
|
+
exts.each do |ext|
|
|
172
|
+
if pr = Sequel.synchronize{EXTENSIONS[ext]}
|
|
173
|
+
pr.call(self)
|
|
174
|
+
else
|
|
175
|
+
raise(Error, "Extension #{ext} does not have specific support handling individual datasets")
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
self
|
|
179
|
+
end
|
|
180
|
+
|
|
133
181
|
# Returns a copy of the dataset with the given conditions imposed upon it.
|
|
134
182
|
# If the query already has a HAVING clause, then the conditions are imposed in the
|
|
135
183
|
# HAVING clause. If not, then they are imposed in the WHERE clause.
|
|
@@ -432,6 +480,9 @@ module Sequel
|
|
|
432
480
|
# to the same table more than once. No alias is used by default.
|
|
433
481
|
# * :implicit_qualifier - The name to use for qualifying implicit conditions. By default,
|
|
434
482
|
# the last joined or primary table is used.
|
|
483
|
+
# * :qualify - Can be set to false to not do any implicit qualification. Can be set
|
|
484
|
+
# to :deep to use the Qualifier AST Transformer, which will attempt to qualify
|
|
485
|
+
# subexpressions of the expression tree.
|
|
435
486
|
# * block - The block argument should only be given if a JOIN with an ON clause is used,
|
|
436
487
|
# in which case it yields the table alias/name for the table currently being joined,
|
|
437
488
|
# the table alias/name for the last joined (or first table), and an array of previous
|
|
@@ -470,6 +521,7 @@ module Sequel
|
|
|
470
521
|
when Hash
|
|
471
522
|
table_alias = options[:table_alias]
|
|
472
523
|
last_alias = options[:implicit_qualifier]
|
|
524
|
+
qualify_type = options[:qualify]
|
|
473
525
|
when Symbol, String, SQL::Identifier
|
|
474
526
|
table_alias = options
|
|
475
527
|
last_alias = nil
|
|
@@ -499,8 +551,16 @@ module Sequel
|
|
|
499
551
|
last_alias ||= @opts[:last_joined_table] || first_source_alias
|
|
500
552
|
if Sequel.condition_specifier?(expr)
|
|
501
553
|
expr = expr.collect do |k, v|
|
|
502
|
-
|
|
503
|
-
|
|
554
|
+
case qualify_type
|
|
555
|
+
when false
|
|
556
|
+
nil # Do no qualification
|
|
557
|
+
when :deep
|
|
558
|
+
k = Sequel::Qualifier.new(self, table_name).transform(k)
|
|
559
|
+
v = Sequel::Qualifier.new(self, last_alias).transform(v)
|
|
560
|
+
else
|
|
561
|
+
k = qualified_column_name(k, table_name) if k.is_a?(Symbol)
|
|
562
|
+
v = qualified_column_name(v, last_alias) if v.is_a?(Symbol)
|
|
563
|
+
end
|
|
504
564
|
[k,v]
|
|
505
565
|
end
|
|
506
566
|
expr = SQL::BooleanExpression.from_value_pairs(expr)
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Sequel::PrettyTable class
|
|
3
|
-
#
|
|
1
|
+
# This _pretty_table extension is only for internal use.
|
|
2
|
+
# It adds the Sequel::PrettyTable class without modifying
|
|
3
|
+
# Sequel::Dataset.
|
|
4
|
+
#
|
|
5
|
+
# To load the extension:
|
|
6
|
+
#
|
|
7
|
+
# Sequel.extension :_pretty_table
|
|
4
8
|
|
|
5
9
|
module Sequel
|
|
6
10
|
module PrettyTable
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# The arbitrary_servers extension allows you to connect to arbitrary
|
|
2
2
|
# servers/shards that were not defined when you created the database.
|
|
3
|
-
# To use it, you first
|
|
4
|
-
# Sequel::ArbitraryServers module:
|
|
3
|
+
# To use it, you first load the extension into the Database object:
|
|
5
4
|
#
|
|
6
|
-
#
|
|
7
|
-
# DB.pool.extend Sequel::ArbitraryServers
|
|
5
|
+
# DB.extension :arbitrary_servers
|
|
8
6
|
#
|
|
9
7
|
# Then you can pass arbitrary connection options for the server/shard
|
|
10
8
|
# to use as a hash:
|
|
@@ -105,4 +103,7 @@ module Sequel
|
|
|
105
103
|
end
|
|
106
104
|
end
|
|
107
105
|
end
|
|
106
|
+
|
|
107
|
+
Database.register_extension(:arbitrary_servers){|db| db.pool.extend(ArbitraryServers)}
|
|
108
108
|
end
|
|
109
|
+
|
|
@@ -5,9 +5,17 @@
|
|
|
5
5
|
# This method is not fool-proof, it's possible that some databases
|
|
6
6
|
# will use column names that Sequel does not expect.
|
|
7
7
|
#
|
|
8
|
-
# To
|
|
9
|
-
# Sequel::ColumnIntrospection. To enable this for all datasets, run:
|
|
8
|
+
# To attempt to introspect columns for a single dataset:
|
|
10
9
|
#
|
|
10
|
+
# ds.extension(:columns_introspection)
|
|
11
|
+
#
|
|
12
|
+
# To attempt to introspect columns for all datasets on a single database:
|
|
13
|
+
#
|
|
14
|
+
# DB.extension(:columns_introspection)
|
|
15
|
+
#
|
|
16
|
+
# To attempt to introspect columns for all datasets on all databases:
|
|
17
|
+
#
|
|
18
|
+
# Sequel.extension :columns_introspection
|
|
11
19
|
# Sequel::Dataset.introspect_all_columns
|
|
12
20
|
|
|
13
21
|
module Sequel
|
|
@@ -58,4 +66,7 @@ module Sequel
|
|
|
58
66
|
remove_method(:columns) if instance_methods(false).map{|x| x.to_s}.include?('columns')
|
|
59
67
|
end
|
|
60
68
|
end
|
|
69
|
+
|
|
70
|
+
Dataset.register_extension(:columns_introspection, Sequel::ColumnsIntrospection)
|
|
61
71
|
end
|
|
72
|
+
|