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.
Files changed (108) hide show
  1. data/CHANGELOG +84 -0
  2. data/Rakefile +13 -0
  3. data/bin/sequel +12 -16
  4. data/doc/advanced_associations.rdoc +36 -67
  5. data/doc/association_basics.rdoc +11 -16
  6. data/doc/release_notes/3.37.0.txt +338 -0
  7. data/doc/schema_modification.rdoc +4 -0
  8. data/lib/sequel/adapters/jdbc/h2.rb +1 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +26 -8
  10. data/lib/sequel/adapters/mysql2.rb +4 -3
  11. data/lib/sequel/adapters/odbc/mssql.rb +2 -2
  12. data/lib/sequel/adapters/postgres.rb +4 -60
  13. data/lib/sequel/adapters/shared/mssql.rb +2 -1
  14. data/lib/sequel/adapters/shared/mysql.rb +0 -5
  15. data/lib/sequel/adapters/shared/postgres.rb +68 -2
  16. data/lib/sequel/adapters/shared/sqlite.rb +17 -1
  17. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +12 -1
  18. data/lib/sequel/adapters/utils/pg_types.rb +76 -0
  19. data/lib/sequel/core.rb +13 -0
  20. data/lib/sequel/database/misc.rb +41 -1
  21. data/lib/sequel/database/schema_generator.rb +23 -10
  22. data/lib/sequel/database/schema_methods.rb +26 -4
  23. data/lib/sequel/dataset/graph.rb +2 -1
  24. data/lib/sequel/dataset/query.rb +62 -2
  25. data/lib/sequel/extensions/_pretty_table.rb +7 -3
  26. data/lib/sequel/extensions/arbitrary_servers.rb +5 -4
  27. data/lib/sequel/extensions/blank.rb +4 -0
  28. data/lib/sequel/extensions/columns_introspection.rb +13 -2
  29. data/lib/sequel/extensions/core_extensions.rb +6 -0
  30. data/lib/sequel/extensions/eval_inspect.rb +158 -0
  31. data/lib/sequel/extensions/inflector.rb +4 -0
  32. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  33. data/lib/sequel/extensions/migration.rb +4 -1
  34. data/lib/sequel/extensions/named_timezones.rb +4 -0
  35. data/lib/sequel/extensions/null_dataset.rb +4 -0
  36. data/lib/sequel/extensions/pagination.rb +4 -0
  37. data/lib/sequel/extensions/pg_array.rb +219 -168
  38. data/lib/sequel/extensions/pg_array_ops.rb +7 -2
  39. data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -4
  40. data/lib/sequel/extensions/pg_hstore.rb +3 -1
  41. data/lib/sequel/extensions/pg_hstore_ops.rb +7 -2
  42. data/lib/sequel/extensions/pg_inet.rb +28 -3
  43. data/lib/sequel/extensions/pg_interval.rb +192 -0
  44. data/lib/sequel/extensions/pg_json.rb +21 -9
  45. data/lib/sequel/extensions/pg_range.rb +487 -0
  46. data/lib/sequel/extensions/pg_range_ops.rb +122 -0
  47. data/lib/sequel/extensions/pg_statement_cache.rb +3 -2
  48. data/lib/sequel/extensions/pretty_table.rb +12 -1
  49. data/lib/sequel/extensions/query.rb +4 -0
  50. data/lib/sequel/extensions/query_literals.rb +6 -6
  51. data/lib/sequel/extensions/schema_dumper.rb +39 -38
  52. data/lib/sequel/extensions/select_remove.rb +4 -0
  53. data/lib/sequel/extensions/server_block.rb +3 -2
  54. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  55. data/lib/sequel/extensions/sql_expr.rb +4 -0
  56. data/lib/sequel/extensions/string_date_time.rb +4 -0
  57. data/lib/sequel/extensions/thread_local_timezones.rb +9 -3
  58. data/lib/sequel/extensions/to_dot.rb +4 -0
  59. data/lib/sequel/model/associations.rb +150 -91
  60. data/lib/sequel/plugins/identity_map.rb +2 -2
  61. data/lib/sequel/plugins/list.rb +1 -0
  62. data/lib/sequel/plugins/many_through_many.rb +33 -32
  63. data/lib/sequel/plugins/nested_attributes.rb +11 -3
  64. data/lib/sequel/plugins/rcte_tree.rb +2 -2
  65. data/lib/sequel/plugins/schema.rb +1 -1
  66. data/lib/sequel/sql.rb +14 -14
  67. data/lib/sequel/version.rb +2 -2
  68. data/spec/adapters/mysql_spec.rb +25 -0
  69. data/spec/adapters/postgres_spec.rb +572 -28
  70. data/spec/adapters/sqlite_spec.rb +16 -1
  71. data/spec/core/database_spec.rb +61 -2
  72. data/spec/core/dataset_spec.rb +92 -0
  73. data/spec/core/expression_filters_spec.rb +12 -0
  74. data/spec/extensions/arbitrary_servers_spec.rb +1 -1
  75. data/spec/extensions/boolean_readers_spec.rb +25 -25
  76. data/spec/extensions/eval_inspect_spec.rb +58 -0
  77. data/spec/extensions/json_serializer_spec.rb +0 -6
  78. data/spec/extensions/list_spec.rb +1 -1
  79. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  80. data/spec/extensions/many_through_many_spec.rb +81 -0
  81. data/spec/extensions/nested_attributes_spec.rb +21 -4
  82. data/spec/extensions/pg_array_ops_spec.rb +1 -11
  83. data/spec/extensions/pg_array_spec.rb +181 -90
  84. data/spec/extensions/pg_auto_parameterize_spec.rb +3 -3
  85. data/spec/extensions/pg_hstore_spec.rb +1 -3
  86. data/spec/extensions/pg_inet_spec.rb +6 -1
  87. data/spec/extensions/pg_interval_spec.rb +73 -0
  88. data/spec/extensions/pg_json_spec.rb +5 -9
  89. data/spec/extensions/pg_range_ops_spec.rb +49 -0
  90. data/spec/extensions/pg_range_spec.rb +372 -0
  91. data/spec/extensions/pg_statement_cache_spec.rb +1 -2
  92. data/spec/extensions/query_literals_spec.rb +1 -2
  93. data/spec/extensions/schema_dumper_spec.rb +48 -89
  94. data/spec/extensions/serialization_spec.rb +1 -5
  95. data/spec/extensions/server_block_spec.rb +2 -2
  96. data/spec/extensions/spec_helper.rb +12 -2
  97. data/spec/extensions/split_array_nil_spec.rb +24 -0
  98. data/spec/integration/associations_test.rb +4 -4
  99. data/spec/integration/database_test.rb +2 -2
  100. data/spec/integration/dataset_test.rb +4 -4
  101. data/spec/integration/eager_loader_test.rb +6 -6
  102. data/spec/integration/plugin_test.rb +2 -2
  103. data/spec/integration/spec_helper.rb +2 -2
  104. data/spec/model/association_reflection_spec.rb +5 -0
  105. data/spec/model/associations_spec.rb +156 -49
  106. data/spec/model/eager_loading_spec.rb +137 -2
  107. data/spec/model/model_spec.rb +10 -10
  108. 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.
@@ -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
- SQLTime.create(value.hour, value.min, value.sec, value.respond_to?(:nsec) ? value.nsec/1000.0 : value.usec)
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::Generator is an internal class that the user is not expected
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::Generator has some methods but also includes method_missing,
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 Generator
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 Generator#column for the available options.
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 Generator#constraint.
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 Generator#column for the available options.
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 Generator#index for available options.
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
- # Generator#index for available options.
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 Generator#column
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 Generator#index for available options.
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 ||= Schema::AlterTableGenerator.new(self, &block)
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::Generator)
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] || Schema::Generator.new(self, &block)
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.
@@ -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
@@ -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
- k = qualified_column_name(k, table_name) if k.is_a?(Symbol)
503
- v = qualified_column_name(v, last_alias) if v.is_a?(Symbol)
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
- # The pretty_table extension adds Sequel::Dataset#print and the
2
- # Sequel::PrettyTable class for creating nice-looking plain-text
3
- # tables.
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 extend the Database's connection pool with the
4
- # Sequel::ArbitraryServers module:
3
+ # To use it, you first load the extension into the Database object:
5
4
  #
6
- # Sequel.extension :arbitrary_servers
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
+
@@ -1,4 +1,8 @@
1
1
  # The blank extension adds the blank? method to all objects (e.g. Object#blank?).
2
+ #
3
+ # To load the extension:
4
+ #
5
+ # Sequel.extension :blank
2
6
 
3
7
  class FalseClass
4
8
  # false is always blank
@@ -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 enable this for a single dataset, extend the dataset with
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
+