sequel 3.11.0 → 3.12.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 (136) hide show
  1. data/CHANGELOG +70 -0
  2. data/Rakefile +1 -1
  3. data/doc/active_record.rdoc +896 -0
  4. data/doc/advanced_associations.rdoc +46 -31
  5. data/doc/association_basics.rdoc +14 -9
  6. data/doc/dataset_basics.rdoc +3 -3
  7. data/doc/migration.rdoc +1011 -0
  8. data/doc/model_hooks.rdoc +198 -0
  9. data/doc/querying.rdoc +811 -86
  10. data/doc/release_notes/3.12.0.txt +304 -0
  11. data/doc/sharding.rdoc +17 -0
  12. data/doc/sql.rdoc +537 -0
  13. data/doc/validations.rdoc +501 -0
  14. data/lib/sequel/adapters/jdbc.rb +19 -27
  15. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -7
  16. data/lib/sequel/adapters/mysql.rb +5 -4
  17. data/lib/sequel/adapters/odbc.rb +3 -2
  18. data/lib/sequel/adapters/shared/mssql.rb +7 -6
  19. data/lib/sequel/adapters/shared/mysql.rb +2 -7
  20. data/lib/sequel/adapters/shared/postgres.rb +2 -8
  21. data/lib/sequel/adapters/shared/sqlite.rb +2 -5
  22. data/lib/sequel/adapters/sqlite.rb +4 -4
  23. data/lib/sequel/core.rb +0 -1
  24. data/lib/sequel/database.rb +2 -1060
  25. data/lib/sequel/database/connecting.rb +227 -0
  26. data/lib/sequel/database/dataset.rb +58 -0
  27. data/lib/sequel/database/dataset_defaults.rb +127 -0
  28. data/lib/sequel/database/logging.rb +62 -0
  29. data/lib/sequel/database/misc.rb +246 -0
  30. data/lib/sequel/database/query.rb +390 -0
  31. data/lib/sequel/database/schema_generator.rb +7 -3
  32. data/lib/sequel/database/schema_methods.rb +351 -7
  33. data/lib/sequel/dataset/actions.rb +9 -2
  34. data/lib/sequel/dataset/misc.rb +6 -2
  35. data/lib/sequel/dataset/mutation.rb +3 -11
  36. data/lib/sequel/dataset/query.rb +49 -6
  37. data/lib/sequel/exceptions.rb +3 -0
  38. data/lib/sequel/extensions/migration.rb +395 -113
  39. data/lib/sequel/extensions/schema_dumper.rb +21 -13
  40. data/lib/sequel/model.rb +27 -25
  41. data/lib/sequel/model/associations.rb +72 -34
  42. data/lib/sequel/model/base.rb +74 -18
  43. data/lib/sequel/model/errors.rb +8 -1
  44. data/lib/sequel/plugins/active_model.rb +8 -0
  45. data/lib/sequel/plugins/association_pks.rb +87 -0
  46. data/lib/sequel/plugins/association_proxies.rb +8 -0
  47. data/lib/sequel/plugins/boolean_readers.rb +12 -6
  48. data/lib/sequel/plugins/caching.rb +14 -7
  49. data/lib/sequel/plugins/class_table_inheritance.rb +15 -9
  50. data/lib/sequel/plugins/composition.rb +2 -1
  51. data/lib/sequel/plugins/force_encoding.rb +10 -7
  52. data/lib/sequel/plugins/hook_class_methods.rb +12 -11
  53. data/lib/sequel/plugins/identity_map.rb +9 -0
  54. data/lib/sequel/plugins/instance_hooks.rb +23 -13
  55. data/lib/sequel/plugins/lazy_attributes.rb +4 -1
  56. data/lib/sequel/plugins/many_through_many.rb +18 -4
  57. data/lib/sequel/plugins/nested_attributes.rb +1 -0
  58. data/lib/sequel/plugins/optimistic_locking.rb +1 -1
  59. data/lib/sequel/plugins/rcte_tree.rb +9 -8
  60. data/lib/sequel/plugins/schema.rb +8 -0
  61. data/lib/sequel/plugins/serialization.rb +1 -3
  62. data/lib/sequel/plugins/sharding.rb +135 -0
  63. data/lib/sequel/plugins/single_table_inheritance.rb +117 -25
  64. data/lib/sequel/plugins/skip_create_refresh.rb +35 -0
  65. data/lib/sequel/plugins/string_stripper.rb +26 -0
  66. data/lib/sequel/plugins/tactical_eager_loading.rb +8 -0
  67. data/lib/sequel/plugins/timestamps.rb +15 -2
  68. data/lib/sequel/plugins/touch.rb +13 -0
  69. data/lib/sequel/plugins/update_primary_key.rb +48 -0
  70. data/lib/sequel/plugins/validation_class_methods.rb +8 -0
  71. data/lib/sequel/plugins/validation_helpers.rb +1 -1
  72. data/lib/sequel/sql.rb +17 -20
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/postgres_spec.rb +5 -5
  75. data/spec/core/core_sql_spec.rb +17 -1
  76. data/spec/core/database_spec.rb +17 -5
  77. data/spec/core/dataset_spec.rb +31 -8
  78. data/spec/core/schema_generator_spec.rb +8 -1
  79. data/spec/core/schema_spec.rb +13 -0
  80. data/spec/extensions/association_pks_spec.rb +85 -0
  81. data/spec/extensions/hook_class_methods_spec.rb +9 -9
  82. data/spec/extensions/migration_spec.rb +339 -219
  83. data/spec/extensions/schema_dumper_spec.rb +28 -17
  84. data/spec/extensions/sharding_spec.rb +272 -0
  85. data/spec/extensions/single_table_inheritance_spec.rb +92 -4
  86. data/spec/extensions/skip_create_refresh_spec.rb +17 -0
  87. data/spec/extensions/string_stripper_spec.rb +23 -0
  88. data/spec/extensions/update_primary_key_spec.rb +65 -0
  89. data/spec/extensions/validation_class_methods_spec.rb +5 -5
  90. data/spec/files/bad_down_migration/001_create_alt_basic.rb +4 -0
  91. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +4 -0
  92. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  93. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +9 -0
  94. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +3 -0
  95. data/spec/files/bad_up_migration/001_create_alt_basic.rb +4 -0
  96. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +3 -0
  97. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +9 -0
  98. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +9 -0
  99. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +4 -0
  100. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +9 -0
  101. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +9 -0
  102. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +4 -0
  103. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +4 -0
  104. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  105. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +9 -0
  106. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +4 -0
  107. data/spec/files/integer_migrations/001_create_sessions.rb +9 -0
  108. data/spec/files/integer_migrations/002_create_nodes.rb +9 -0
  109. data/spec/files/integer_migrations/003_3_create_users.rb +4 -0
  110. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  111. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +9 -0
  112. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +9 -0
  113. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +9 -0
  114. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +4 -0
  115. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +4 -0
  116. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +4 -0
  117. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  118. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +4 -0
  119. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +9 -0
  120. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +9 -0
  121. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +4 -0
  122. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +9 -0
  123. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +9 -0
  124. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +4 -0
  125. data/spec/integration/eager_loader_test.rb +20 -20
  126. data/spec/integration/migrator_test.rb +187 -0
  127. data/spec/integration/plugin_test.rb +150 -0
  128. data/spec/integration/schema_test.rb +13 -2
  129. data/spec/model/associations_spec.rb +41 -14
  130. data/spec/model/base_spec.rb +69 -0
  131. data/spec/model/eager_loading_spec.rb +7 -3
  132. data/spec/model/record_spec.rb +79 -4
  133. data/spec/model/validations_spec.rb +21 -9
  134. metadata +66 -5
  135. data/doc/schema.rdoc +0 -36
  136. data/lib/sequel/database/schema_sql.rb +0 -320
@@ -13,7 +13,7 @@ module Sequel
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
- # the {"Schema Modification" guide}[link:files/doc/schema_rdoc.html].
16
+ # the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
17
17
  class Generator
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,
@@ -75,7 +75,7 @@ module Sequel
75
75
  # or not allowing NULL values (if false). If unspecified, will default
76
76
  # to whatever the database default is.
77
77
  # * :on_delete - Specify the behavior of this column when being deleted.
78
- # See Dataset#on_delete_clause for options.
78
+ # See Schema::SQL#on_delete_clause for options.
79
79
  # * :on_update - Specify the behavior of this column when being updated.
80
80
  # See Schema::SQL#on_delete_clause for options.
81
81
  # * :size - The size of the column, generally used with string
@@ -86,6 +86,10 @@ module Sequel
86
86
  # creating a unique index on the column.
87
87
  # * :unsigned - Make the column type unsigned, only useful for integer
88
88
  # columns.
89
+ # * :deferrable - This ensure Referential Integrity will work even if
90
+ # reference table will use for its foreign key a value that does not
91
+ # exists(yet) on referenced table. Basically it adds
92
+ # DEFERRABLE INITIALLY DEFERRED on key creation.
89
93
  def column(name, type, opts = {})
90
94
  columns << {:name => name, :type => type}.merge(opts)
91
95
  index(name) if opts[:index]
@@ -205,7 +209,7 @@ module Sequel
205
209
  # alter a table's description.
206
210
  #
207
211
  # For more information on Sequel's support for schema modification, see
208
- # the {"Schema Modification" guide}[link:files/doc/schema_rdoc.html].
212
+ # the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
209
213
  class AlterTableGenerator
210
214
  # An array of DDL operations to perform
211
215
  attr_reader :operations
@@ -1,5 +1,25 @@
1
1
  module Sequel
2
2
  class Database
3
+ # ---------------------
4
+ # :section: Methods that modify the database schema
5
+ # These methods execute code on the database that modifies the database's schema.
6
+ # ---------------------
7
+
8
+ AUTOINCREMENT = 'AUTOINCREMENT'.freeze
9
+ CASCADE = 'CASCADE'.freeze
10
+ COMMA_SEPARATOR = ', '.freeze
11
+ NO_ACTION = 'NO ACTION'.freeze
12
+ NOT_NULL = ' NOT NULL'.freeze
13
+ NULL = ' NULL'.freeze
14
+ PRIMARY_KEY = ' PRIMARY KEY'.freeze
15
+ RESTRICT = 'RESTRICT'.freeze
16
+ SET_DEFAULT = 'SET DEFAULT'.freeze
17
+ SET_NULL = 'SET NULL'.freeze
18
+ TEMPORARY = 'TEMPORARY '.freeze
19
+ UNDERSCORE = '_'.freeze
20
+ UNIQUE = ' UNIQUE'.freeze
21
+ UNSIGNED = ' UNSIGNED'.freeze
22
+
3
23
  # Adds a column to the specified table. This method expects a column name,
4
24
  # a datatype and optionally a hash with additional constraints and options:
5
25
  #
@@ -46,11 +66,12 @@ module Sequel
46
66
  # definitions using create_table, and #add_index accepts all the options
47
67
  # available for index definition.
48
68
  #
49
- # See Schema::AlterTableGenerator and the {"Schema Modification" guide}[link:files/doc/schema_rdoc.html].
69
+ # See Schema::AlterTableGenerator and the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
50
70
  def alter_table(name, generator=nil, &block)
51
- remove_cached_schema(name)
52
71
  generator ||= Schema::AlterTableGenerator.new(self, &block)
53
72
  alter_table_sql_list(name, generator.operations).flatten.each {|sql| execute_ddl(sql)}
73
+ remove_cached_schema(name)
74
+ nil
54
75
  end
55
76
 
56
77
  # Creates a table with the columns given in the provided block:
@@ -66,12 +87,14 @@ module Sequel
66
87
  # * :temp - Create the table as a temporary table.
67
88
  # * :ignore_index_errors - Ignore any errors when creating indexes.
68
89
  #
69
- # See Schema::Generator and the {"Schema Modification" guide}[link:files/doc/schema_rdoc.html].
90
+ # See Schema::Generator and the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
70
91
  def create_table(name, options={}, &block)
92
+ remove_cached_schema(name)
71
93
  options = {:generator=>options} if options.is_a?(Schema::Generator)
72
94
  generator = options[:generator] || Schema::Generator.new(self, &block)
73
95
  create_table_from_generator(name, generator, options)
74
96
  create_table_indexes_from_generator(name, generator, options)
97
+ nil
75
98
  end
76
99
 
77
100
  # Forcibly creates a table, attempting to drop it unconditionally (and catching any errors), then creating it.
@@ -90,9 +113,10 @@ module Sequel
90
113
  # DB.create_or_replace_view(:cheap_items, "SELECT * FROM items WHERE price < 100")
91
114
  # DB.create_or_replace_view(:ruby_items, DB[:items].filter(:category => 'ruby'))
92
115
  def create_or_replace_view(name, source)
93
- remove_cached_schema(name)
94
116
  source = source.sql if source.is_a?(Dataset)
95
117
  execute_ddl("CREATE OR REPLACE VIEW #{quote_schema_table(name)} AS #{source}")
118
+ remove_cached_schema(name)
119
+ nil
96
120
  end
97
121
 
98
122
  # Creates a view based on a dataset or an SQL string:
@@ -128,9 +152,10 @@ module Sequel
128
152
  # DB.drop_table(:posts, :comments)
129
153
  def drop_table(*names)
130
154
  names.each do |n|
131
- remove_cached_schema(n)
132
155
  execute_ddl(drop_table_sql(n))
156
+ remove_cached_schema(n)
133
157
  end
158
+ nil
134
159
  end
135
160
 
136
161
  # Drops one or more views corresponding to the given names:
@@ -138,9 +163,10 @@ module Sequel
138
163
  # DB.drop_view(:cheap_items)
139
164
  def drop_view(*names)
140
165
  names.each do |n|
141
- remove_cached_schema(n)
142
166
  execute_ddl("DROP VIEW #{quote_schema_table(n)}")
167
+ remove_cached_schema(n)
143
168
  end
169
+ nil
144
170
  end
145
171
 
146
172
  # Renames a table:
@@ -149,8 +175,9 @@ module Sequel
149
175
  # DB.rename_table :items, :old_items
150
176
  # DB.tables #=> [:old_items]
151
177
  def rename_table(name, new_name)
152
- remove_cached_schema(name)
153
178
  execute_ddl(rename_table_sql(name, new_name))
179
+ remove_cached_schema(name)
180
+ nil
154
181
  end
155
182
 
156
183
  # Renames a column in the specified table. This method expects the current
@@ -183,6 +210,108 @@ module Sequel
183
210
 
184
211
  private
185
212
 
213
+ # The SQL to execute to modify the DDL for the given table name. op
214
+ # should be one of the operations returned by the AlterTableGenerator.
215
+ def alter_table_sql(table, op)
216
+ quoted_name = quote_identifier(op[:name]) if op[:name]
217
+ alter_table_op = case op[:op]
218
+ when :add_column
219
+ "ADD COLUMN #{column_definition_sql(op)}"
220
+ when :drop_column
221
+ "DROP COLUMN #{quoted_name}"
222
+ when :rename_column
223
+ "RENAME COLUMN #{quoted_name} TO #{quote_identifier(op[:new_name])}"
224
+ when :set_column_type
225
+ "ALTER COLUMN #{quoted_name} TYPE #{type_literal(op)}"
226
+ when :set_column_default
227
+ "ALTER COLUMN #{quoted_name} SET DEFAULT #{literal(op[:default])}"
228
+ when :set_column_null
229
+ "ALTER COLUMN #{quoted_name} #{op[:null] ? 'DROP' : 'SET'} NOT NULL"
230
+ when :add_index
231
+ return index_definition_sql(table, op)
232
+ when :drop_index
233
+ return drop_index_sql(table, op)
234
+ when :add_constraint
235
+ "ADD #{constraint_definition_sql(op)}"
236
+ when :drop_constraint
237
+ "DROP CONSTRAINT #{quoted_name}"
238
+ else
239
+ raise Error, "Unsupported ALTER TABLE operation"
240
+ end
241
+ "ALTER TABLE #{quote_schema_table(table)} #{alter_table_op}"
242
+ end
243
+
244
+ # Array of SQL DDL modification statements for the given table,
245
+ # corresponding to the DDL changes specified by the operations.
246
+ def alter_table_sql_list(table, operations)
247
+ operations.map{|op| alter_table_sql(table, op)}
248
+ end
249
+
250
+ # The SQL string specify the autoincrement property, generally used by
251
+ # primary keys.
252
+ def auto_increment_sql
253
+ AUTOINCREMENT
254
+ end
255
+
256
+ # SQL DDL fragment containing the column creation SQL for the given column.
257
+ def column_definition_sql(column)
258
+ sql = "#{quote_identifier(column[:name])} #{type_literal(column)}"
259
+ sql << UNIQUE if column[:unique]
260
+ null = column.fetch(:null, column[:allow_null])
261
+ sql << NOT_NULL if null == false
262
+ sql << NULL if null == true
263
+ sql << " DEFAULT #{literal(column[:default])}" if column.include?(:default)
264
+ sql << PRIMARY_KEY if column[:primary_key]
265
+ sql << " #{auto_increment_sql}" if column[:auto_increment]
266
+ sql << column_references_column_constraint_sql(column) if column[:table]
267
+ sql
268
+ end
269
+
270
+ # SQL DDL fragment containing the column creation
271
+ # SQL for all given columns, used inside a CREATE TABLE block.
272
+ def column_list_sql(generator)
273
+ (generator.columns.map{|c| column_definition_sql(c)} + generator.constraints.map{|c| constraint_definition_sql(c)}).join(COMMA_SEPARATOR)
274
+ end
275
+
276
+ # SQL DDL fragment for column foreign key references (column constraints)
277
+ def column_references_column_constraint_sql(column)
278
+ column_references_sql(column)
279
+ end
280
+
281
+ # SQL DDL fragment for column foreign key references
282
+ def column_references_sql(column)
283
+ sql = " REFERENCES #{quote_schema_table(column[:table])}"
284
+ sql << "(#{Array(column[:key]).map{|x| quote_identifier(x)}.join(COMMA_SEPARATOR)})" if column[:key]
285
+ sql << " ON DELETE #{on_delete_clause(column[:on_delete])}" if column[:on_delete]
286
+ sql << " ON UPDATE #{on_delete_clause(column[:on_update])}" if column[:on_update]
287
+ sql << " DEFERRABLE INITIALLY DEFERRED" if column[:deferrable]
288
+ sql
289
+ end
290
+
291
+ # SQL DDL fragment for table foreign key references (table constraints)
292
+ def column_references_table_constraint_sql(constraint)
293
+ "FOREIGN KEY #{literal(constraint[:columns])}#{column_references_sql(constraint)}"
294
+ end
295
+
296
+ # SQL DDL fragment specifying a constraint on a table.
297
+ def constraint_definition_sql(constraint)
298
+ sql = constraint[:name] ? "CONSTRAINT #{quote_identifier(constraint[:name])} " : ""
299
+ case constraint[:type]
300
+ when :check
301
+ check = constraint[:check]
302
+ sql << "CHECK #{filter_expr((check.is_a?(Array) && check.length == 1) ? check.first : check)}"
303
+ when :primary_key
304
+ sql << "PRIMARY KEY #{literal(constraint[:columns])}"
305
+ when :foreign_key
306
+ sql << column_references_table_constraint_sql(constraint)
307
+ when :unique
308
+ sql << "UNIQUE #{literal(constraint[:columns])}"
309
+ else
310
+ raise Error, "Invalid constriant type #{constraint[:type]}, should be :check, :primary_key, :foreign_key, or :unique"
311
+ end
312
+ sql
313
+ end
314
+
186
315
  # Execute the create table statements using the generator.
187
316
  def create_table_from_generator(name, generator, options)
188
317
  execute_ddl(create_table_sql(name, generator, options))
@@ -199,5 +328,220 @@ module Sequel
199
328
  end
200
329
  end
201
330
  end
331
+
332
+ # DDL statement for creating a table with the given name, columns, and options
333
+ def create_table_sql(name, generator, options)
334
+ "CREATE #{temporary_table_sql if options[:temp]}TABLE #{quote_schema_table(name)} (#{column_list_sql(generator)})"
335
+ end
336
+
337
+ # Default index name for the table and columns, may be too long
338
+ # for certain databases.
339
+ def default_index_name(table_name, columns)
340
+ schema, table = schema_and_table(table_name)
341
+ "#{"#{schema}_" if schema and schema != default_schema}#{table}_#{columns.map{|c| [String, Symbol].any?{|cl| c.is_a?(cl)} ? c : literal(c).gsub(/\W/, '_')}.join(UNDERSCORE)}_index"
342
+ end
343
+
344
+ # The SQL to drop an index for the table.
345
+ def drop_index_sql(table, op)
346
+ "DROP INDEX #{quote_identifier(op[:name] || default_index_name(table, op[:columns]))}"
347
+ end
348
+
349
+ # SQL DDL statement to drop the table with the given name.
350
+ def drop_table_sql(name)
351
+ "DROP TABLE #{quote_schema_table(name)}"
352
+ end
353
+
354
+ # Proxy the filter_expr call to the dataset, used for creating constraints.
355
+ def filter_expr(*args, &block)
356
+ schema_utility_dataset.literal(schema_utility_dataset.send(:filter_expr, *args, &block))
357
+ end
358
+
359
+ # SQL DDL statement for creating an index for the table with the given name
360
+ # and index specifications.
361
+ def index_definition_sql(table_name, index)
362
+ index_name = index[:name] || default_index_name(table_name, index[:columns])
363
+ if index[:type]
364
+ raise Error, "Index types are not supported for this database"
365
+ elsif index[:where]
366
+ raise Error, "Partial indexes are not supported for this database"
367
+ else
368
+ "CREATE #{'UNIQUE ' if index[:unique]}INDEX #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{literal(index[:columns])}"
369
+ end
370
+ end
371
+
372
+ # Array of SQL DDL statements, one for each index specification,
373
+ # for the given table.
374
+ def index_sql_list(table_name, indexes)
375
+ indexes.map{|i| index_definition_sql(table_name, i)}
376
+ end
377
+
378
+ # SQL DDL ON DELETE fragment to use, based on the given action.
379
+ # The following actions are recognized:
380
+ #
381
+ # * :cascade - Delete rows referencing this row.
382
+ # * :no_action (default) - Raise an error if other rows reference this
383
+ # row, allow deferring of the integrity check.
384
+ # * :restrict - Raise an error if other rows reference this row,
385
+ # but do not allow deferring the integrity check.
386
+ # * :set_default - Set columns referencing this row to their default value.
387
+ # * :set_null - Set columns referencing this row to NULL.
388
+ def on_delete_clause(action)
389
+ case action
390
+ when :restrict
391
+ RESTRICT
392
+ when :cascade
393
+ CASCADE
394
+ when :set_null
395
+ SET_NULL
396
+ when :set_default
397
+ SET_DEFAULT
398
+ else
399
+ NO_ACTION
400
+ end
401
+ end
402
+
403
+ # Proxy the quote_schema_table method to the dataset
404
+ def quote_schema_table(table)
405
+ schema_utility_dataset.quote_schema_table(table)
406
+ end
407
+
408
+ # Proxy the quote_identifier method to the dataset, used for quoting tables and columns.
409
+ def quote_identifier(v)
410
+ schema_utility_dataset.quote_identifier(v)
411
+ end
412
+
413
+ # SQL DDL statement for renaming a table.
414
+ def rename_table_sql(name, new_name)
415
+ "ALTER TABLE #{quote_schema_table(name)} RENAME TO #{quote_schema_table(new_name)}"
416
+ end
417
+
418
+ # Remove the cached schema_utility_dataset, because the identifier
419
+ # quoting has changed.
420
+ def reset_schema_utility_dataset
421
+ @schema_utility_dataset = nil
422
+ end
423
+
424
+ # Split the schema information from the table
425
+ def schema_and_table(table_name)
426
+ schema_utility_dataset.schema_and_table(table_name)
427
+ end
428
+
429
+ # Return true if the given column schema represents an autoincrementing primary key.
430
+ def schema_autoincrementing_primary_key?(schema)
431
+ !!schema[:primary_key]
432
+ end
433
+
434
+ # The dataset to use for proxying certain schema methods.
435
+ def schema_utility_dataset
436
+ @schema_utility_dataset ||= dataset
437
+ end
438
+
439
+ # SQL DDL fragment for temporary table
440
+ def temporary_table_sql
441
+ self.class.const_get(:TEMPORARY)
442
+ end
443
+
444
+ # SQL fragment specifying the type of a given column.
445
+ def type_literal(column)
446
+ column[:type].is_a?(Class) ? type_literal_generic(column) : type_literal_specific(column)
447
+ end
448
+
449
+ # SQL fragment specifying the full type of a column,
450
+ # consider the type with possible modifiers.
451
+ def type_literal_generic(column)
452
+ meth = "type_literal_generic_#{column[:type].name.to_s.downcase}"
453
+ if respond_to?(meth, true)
454
+ send(meth, column)
455
+ else
456
+ raise Error, "Unsupported ruby class used as database type: #{column[:type]}"
457
+ end
458
+ end
459
+
460
+ # Alias for type_literal_generic_numeric, to make overriding in a subclass easier.
461
+ def type_literal_generic_bigdecimal(column)
462
+ type_literal_generic_numeric(column)
463
+ end
464
+
465
+ # Sequel uses the bigint type by default for Bignums.
466
+ def type_literal_generic_bignum(column)
467
+ :bigint
468
+ end
469
+
470
+ # Sequel uses the date type by default for Dates.
471
+ def type_literal_generic_date(column)
472
+ :date
473
+ end
474
+
475
+ # Sequel uses the timestamp type by default for DateTimes.
476
+ def type_literal_generic_datetime(column)
477
+ :timestamp
478
+ end
479
+
480
+ # Alias for type_literal_generic_trueclass, to make overriding in a subclass easier.
481
+ def type_literal_generic_falseclass(column)
482
+ type_literal_generic_trueclass(column)
483
+ end
484
+
485
+ # Sequel uses the blob type by default for Files.
486
+ def type_literal_generic_file(column)
487
+ :blob
488
+ end
489
+
490
+ # Alias for type_literal_generic_integer, to make overriding in a subclass easier.
491
+ def type_literal_generic_fixnum(column)
492
+ type_literal_generic_integer(column)
493
+ end
494
+
495
+ # Sequel uses the double precision type by default for Floats.
496
+ def type_literal_generic_float(column)
497
+ :"double precision"
498
+ end
499
+
500
+ # Sequel uses the integer type by default for integers
501
+ def type_literal_generic_integer(column)
502
+ :integer
503
+ end
504
+
505
+ # Sequel uses the numeric type by default for Numerics and BigDecimals.
506
+ # If a size is given, it is used, otherwise, it will default to whatever
507
+ # the database default is for an unsized value.
508
+ def type_literal_generic_numeric(column)
509
+ column[:size] ? "numeric(#{Array(column[:size]).join(', ')})" : :numeric
510
+ end
511
+
512
+ # Sequel uses the varchar type by default for Strings. If a
513
+ # size isn't present, Sequel assumes a size of 255. If the
514
+ # :fixed option is used, Sequel uses the char type. If the
515
+ # :text option is used, Sequel uses the :text type.
516
+ def type_literal_generic_string(column)
517
+ if column[:text]
518
+ :text
519
+ elsif column[:fixed]
520
+ "char(#{column[:size]||255})"
521
+ else
522
+ "varchar(#{column[:size]||255})"
523
+ end
524
+ end
525
+
526
+ # Sequel uses the timestamp type by default for Time values.
527
+ # If the :only_time option is used, the time type is used.
528
+ def type_literal_generic_time(column)
529
+ column[:only_time] ? :time : :timestamp
530
+ end
531
+
532
+ # Sequel uses the boolean type by default for TrueClass and FalseClass.
533
+ def type_literal_generic_trueclass(column)
534
+ :boolean
535
+ end
536
+
537
+ # SQL fragment for the given type of a column if the column is not one of the
538
+ # generic types specified with a ruby class.
539
+ def type_literal_specific(column)
540
+ type = column[:type]
541
+ type = "double precision" if type.to_s == 'double'
542
+ column[:size] ||= 255 if type.to_s == 'varchar'
543
+ elements = column[:size] || column[:elements]
544
+ "#{type}#{literal(Array(elements)) if elements}#{UNSIGNED if column[:unsigned]}"
545
+ end
202
546
  end
203
547
  end