sequel 3.26.0 → 3.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG +26 -0
  2. data/Rakefile +2 -3
  3. data/doc/mass_assignment.rdoc +54 -0
  4. data/doc/migration.rdoc +9 -533
  5. data/doc/prepared_statements.rdoc +8 -7
  6. data/doc/release_notes/3.27.0.txt +82 -0
  7. data/doc/schema_modification.rdoc +547 -0
  8. data/doc/testing.rdoc +64 -0
  9. data/lib/sequel/adapters/amalgalite.rb +4 -0
  10. data/lib/sequel/adapters/jdbc.rb +3 -1
  11. data/lib/sequel/adapters/jdbc/h2.rb +11 -5
  12. data/lib/sequel/adapters/mysql.rb +4 -122
  13. data/lib/sequel/adapters/mysql2.rb +4 -13
  14. data/lib/sequel/adapters/odbc.rb +4 -1
  15. data/lib/sequel/adapters/odbc/db2.rb +21 -0
  16. data/lib/sequel/adapters/shared/mysql.rb +12 -0
  17. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +143 -0
  18. data/lib/sequel/adapters/tinytds.rb +122 -3
  19. data/lib/sequel/core.rb +4 -3
  20. data/lib/sequel/database/misc.rb +7 -10
  21. data/lib/sequel/dataset/misc.rb +1 -1
  22. data/lib/sequel/dataset/sql.rb +7 -0
  23. data/lib/sequel/model/associations.rb +2 -2
  24. data/lib/sequel/model/base.rb +60 -10
  25. data/lib/sequel/plugins/prepared_statements_safe.rb +17 -7
  26. data/lib/sequel/sql.rb +5 -0
  27. data/lib/sequel/timezones.rb +12 -3
  28. data/lib/sequel/version.rb +1 -1
  29. data/spec/adapters/mysql_spec.rb +25 -21
  30. data/spec/core/database_spec.rb +200 -0
  31. data/spec/core/dataset_spec.rb +6 -0
  32. data/spec/extensions/prepared_statements_safe_spec.rb +10 -0
  33. data/spec/extensions/schema_dumper_spec.rb +2 -2
  34. data/spec/integration/schema_test.rb +30 -1
  35. data/spec/integration/type_test.rb +10 -3
  36. data/spec/model/base_spec.rb +44 -0
  37. data/spec/model/model_spec.rb +14 -0
  38. data/spec/model/record_spec.rb +131 -12
  39. metadata +14 -4
@@ -3,15 +3,16 @@
3
3
  Sequel has support for prepared statements and bound variables. No matter which
4
4
  database you are using, the Sequel prepared statement/bound variable API remains
5
5
  the same. There is native support for prepared statements/bound variables on
6
- the following databases:
6
+ the following adapters:
7
7
 
8
- * PostgreSQL (using the pg driver, may require type specifiers)
9
- * MySQL (prepared statements only, as the ruby mysql driver doesn't support
10
- bound variables)
11
- * SQLite
12
- * JDBC
8
+ * jdbc
9
+ * mysql (prepared statements only)
10
+ * mysql2 (prepared statements only)
11
+ * postgres (when using the pg driver, may require type specifiers)
12
+ * sqlite
13
+ * tinytds
13
14
 
14
- Support on other databases is emulated via string interpolation.
15
+ Support on other adapters is emulated via string interpolation.
15
16
 
16
17
  You can use the prepared_statements model plugin to automatically use prepared
17
18
  statements for some common model actions such as saving or deleting a model
@@ -0,0 +1,82 @@
1
+ = New Features
2
+
3
+ * Model.dataset_module has been added for easily adding methods to
4
+ a model's dataset:
5
+
6
+ Album.dataset_module do
7
+ def with_name_like(x)
8
+ filter(:name.like(x))
9
+ end
10
+ def selling_at_least(x)
11
+ filter{copies_sold > x}
12
+ end
13
+ end
14
+ Album.with_name_like('Foo%').selling_at_least(100000).all
15
+
16
+ Previously, you could use def_dataset_method to accomplish the
17
+ same thing. dataset_module is generally cleaner, plus you are
18
+ using actual methods instead of blocks, so calling the methods
19
+ is faster on some ruby implementations.
20
+
21
+ * Sequel now uses a Sequel::SQLTime class (a subclass of Time) when
22
+ dealing with values for SQL time columns (which don't have a date
23
+ component). These values are handled correctly when used in
24
+ filters or insert/update statements (using only the time
25
+ component), so Sequel can now successfully round trip values for
26
+ time columns. Not all adapters support returning time column
27
+ values as SQLTime instances, but the most common ones do.
28
+
29
+ * You can now drop foreign key, primary key, and unique constraints
30
+ on MySQL by passing the :type=>(:foreign_key|:primary_key|:unique)
31
+ option to Database#drop_constraint.
32
+
33
+ * The ODBC adapter now has initial support for the DB2 database, use
34
+ the :db_type=>'db2' option to load the support.
35
+
36
+ = Other Improvements
37
+
38
+ * The mysql2 adapter now uses native prepared statements.
39
+
40
+ * The tinytds adapter now uses uses sp_executesql for prepared
41
+ statements.
42
+
43
+ * DateTime and Time objects are now converted to Date objects when
44
+ they are assigned to a date column in a Model instance.
45
+
46
+ * When converting a Date object to a DateTime object, the resulting
47
+ DateTime object now has no fractional day components. Previously,
48
+ depending on your timezone settings, it could have had fractional
49
+ day components.
50
+
51
+ * The mysql2 adapter now supports stored procedures, as long as they
52
+ don't return results.
53
+
54
+ * Mass assignment protection now handles including modules in model
55
+ classes and extending model instances with modules. Previously, if
56
+ you defined a setter method in a module, access to it may have been
57
+ restricted.
58
+
59
+ * The prepared_statements_safe plugin now works on classes without
60
+ datasets, so you can now do the following to load it for all models:
61
+
62
+ Sequel::Model.plugin :prepared_statements_safe
63
+
64
+ * Dataset#hash now works correctly when handling SQL::Expression
65
+ instances.
66
+
67
+ * Model#hash now correctly handles classes with no primary key or with
68
+ a composite primary key.
69
+
70
+ * Model#exists? now always returns false for new model objects.
71
+
72
+ = Backwards Compatibility
73
+
74
+ * If you were previously setting primary key values manually for new
75
+ model objects and then calling exists? to see if the instance is
76
+ already in the database, you need to change your code from:
77
+
78
+ model.exists?
79
+
80
+ to:
81
+
82
+ model.this.get(1).nil?
@@ -0,0 +1,547 @@
1
+ = Schema modification methods
2
+
3
+ Here's a brief description of the most common schema modification methods:
4
+
5
+ == +create_table+
6
+
7
+ +create_table+ is the most common schema modification method, and it's used for adding new tables
8
+ to the schema. You provide it with the name of the table as a symbol, as well a block:
9
+
10
+ create_table(:artists) do
11
+ primary_key :id
12
+ String :name
13
+ end
14
+
15
+ Not that if you want a primary key for the table, you need to specify it, Sequel does not create one
16
+ by default.
17
+
18
+ === Column types
19
+
20
+ Most method calls inside the create_table block will create columns, since +method_missing+ calls +column+.
21
+ Columns are generally created by specifying the column type as the method
22
+ name, followed by the column name symbol to use, and after that any options that should be used.
23
+ If the method is a ruby class name that Sequel recognizes, Sequel will transform it into the appropriate
24
+ type for the given database. So while you specified +String+, Sequel will actually use +varchar+ or
25
+ +text+ depending on the underlying database. Here's a list of all of ruby classes that Sequel will
26
+ convert to database types:
27
+
28
+ create_table(:columns_types) do # common database type used
29
+ Integer :a0 # integer
30
+ String :a1 # varchar(255)
31
+ String :a2, :size=>50 # varchar(50)
32
+ String :a3, :fixed=>true # char(255)
33
+ String :a4, :fixed=>true, :size=>50 # char(50)
34
+ String :a5, :text=>true # text
35
+ File :b, # blob
36
+ Fixnum :c # integer
37
+ Bignum :d # bigint
38
+ Float :e # double precision
39
+ BigDecimal :f # numeric
40
+ BigDecimal :f2, :size=>10 # numeric(10)
41
+ BigDecimal :f3, :size=>[10, 2] # numeric(10, 2)
42
+ Date :g # date
43
+ DateTime :h # timestamp
44
+ Time :i # timestamp
45
+ Time :i2, :only_time=>true # time
46
+ Numeric :j # numeric
47
+ TrueClass :k # boolean
48
+ FalseClass :l # boolean
49
+ end
50
+
51
+ Note that in addition to the ruby class name, Sequel also pays attention to the column options when
52
+ determining which database type to use. Also note that for boolean columns, you can use either
53
+ TrueClass or FalseClass, they are treated the same way (ruby doesn't have a Boolean class).
54
+
55
+ Also note that this conversion is only done if you use a supported ruby class name. In all other
56
+ cases, Sequel uses the type specified verbatim:
57
+
58
+ create_table(:columns_types) do # database type used
59
+ string :a1 # string
60
+ datetime :a2 # datetime
61
+ blob :a3 # blob
62
+ inet :a4 # inet
63
+ end
64
+
65
+ In addition to specifying the types as methods, you can use the +column+ method and specify the types
66
+ as the second argument, either as ruby classes, symbols, or strings:
67
+
68
+ create_table(:columns_types) do # database type used
69
+ column :a1, :string # string
70
+ column :a2, String # varchar(255)
71
+ column :a3, 'string' # string
72
+ column :a4, :datetime # datetime
73
+ column :a5, DateTime # timestamp
74
+ column :a6, 'timestamp(6)' # timestamp(6)
75
+ end
76
+
77
+ === Column options
78
+
79
+ When using the type name as method, the third argument is an options hash, and when using the +column+
80
+ method, the fourth argument is the options hash. The following options are supported:
81
+
82
+ :default :: The default value for the column.
83
+ :index :: Create an index on this column.
84
+ :null :: Mark the column as allowing NULL values (if true),
85
+ or not allowing NULL values (if false). If unspecified, will default
86
+ to whatever the database default is.
87
+ :size :: The size of the column, generally used with string
88
+ columns to specify the maximum number of characters the column will hold.
89
+ An array of two integers can be provided to set the size and the
90
+ precision, respectively, of decimal columns.
91
+ :unique :: Mark the column as unique, generally has the same effect as
92
+ creating a unique index on the column.
93
+ :unsigned :: Make the column type unsigned, only useful for integer
94
+ columns.
95
+
96
+ === Other methods
97
+
98
+ In addition to the +column+ method and other methods that create columns, there are a other methods that can be used:
99
+
100
+ ==== +primary_key+
101
+
102
+ You've seen this one used already. It's used to create an autoincrementing integer primary key column.
103
+
104
+ create_table(:a0){primary_key :id}
105
+
106
+ If you want to create a primary key column that doesn't use an autoincrementing integer, you should
107
+ not use this method. Instead, you should use the :primary_key option to the +column+ method or type
108
+ method:
109
+
110
+ create_table(:a1){Integer :id, :primary_key=>true} # Non autoincrementing integer primary key
111
+ create_table(:a2){String :name, :primary_key=>true} # varchar(255) primary key
112
+
113
+ If you want to create a composite primary key, you should call the +primary_key+ method with an
114
+ array of column symbols:
115
+
116
+ create_table(:items) do
117
+ Integer :group_id
118
+ Integer :position
119
+ primary_key [:group_id, :position]
120
+ end
121
+
122
+ If provided with an array, +primary_key+ does not create a column, it just sets up the primary key constraint.
123
+
124
+ ==== +foreign_key+
125
+
126
+ +foreign_key+ is used to create a foreign key column that references a column in another table (or the same table).
127
+ It takes the column name as the first argument, the table it references as the second argument, and an options hash
128
+ as it's third argument. A simple example is:
129
+
130
+ create_table(:albums) do
131
+ primary_key :id
132
+ foreign_key :artist_id, :artists
133
+ String :name
134
+ end
135
+
136
+ +foreign_key+ accepts some specific options:
137
+
138
+ :deferrable :: Makes the foreign key constraint checks deferrable, so they aren't checked
139
+ until the end of the transaction.
140
+ :key :: For foreign key columns, the column in the associated table
141
+ that this column references. Unnecessary if this column
142
+ references the primary key of the associated table, at least
143
+ on most databases.
144
+ :on_delete :: Specify the behavior of this foreign key column when the row with the primary key
145
+ it references is deleted , can be :restrict, :cascade, :set_null, or :set_default.
146
+ :on_update :: Specify the behavior of this foreign key column when the row with the primary key
147
+ it references modifies the value of the primary key, can be
148
+ :restrict, :cascade, :set_null, or :set_default.
149
+
150
+ Like +primary_key+, if you provide +foreign_key+ with an array of symbols, it will not create a
151
+ column, but create a foreign key constraint:
152
+
153
+ create_table(:artists) do
154
+ String :name
155
+ String :location
156
+ primary_key [:name, :location]
157
+ end
158
+ create_table(:albums) do
159
+ String :artist_name
160
+ String :artist_location
161
+ String :name
162
+ foreign_key [:artist_name, :artist_location], :artists
163
+ end
164
+
165
+ ==== +index+
166
+
167
+ +index+ creates indexes on the table. For single columns, calling index is the same as using the
168
+ <tt>:index</tt> option when creating the column:
169
+
170
+ create_table(:a){Integer :id, :index=>true}
171
+ # Same as:
172
+ create_table(:a) do
173
+ Integer :id
174
+ index :id
175
+ end
176
+
177
+ Similar to the +primary_key+ and +foreign_key+ methods, calling +index+ with an array of symbols
178
+ will create a multiple column index:
179
+
180
+ create_table(:albums) do
181
+ primary_key :id
182
+ foreign_key :artist_id, :artists
183
+ Integer :position
184
+ index [:artist_id, :position]
185
+ end
186
+
187
+ The +index+ method also accepts some options:
188
+
189
+ :name :: The name of the index (generated based on the table and column names if not provided).
190
+ :type :: The type of index to use (only supported by some databases)
191
+ :unique :: Make the index unique, so duplicate values are not allowed.
192
+ :where :: Create a partial index (only supported by some databases)
193
+
194
+ ==== +unique+
195
+
196
+ The +unique+ method creates a unique constraint on the table. A unique constraint generally
197
+ operates identically to a unique index, so the following three +create_table+ blocks are
198
+ pretty much identical:
199
+
200
+ create_table(:a){Integer :a, :unique=>true}
201
+
202
+ create_table(:a) do
203
+ Integer :a
204
+ index :a, :unique=>true
205
+ end
206
+
207
+ create_table(:a) do
208
+ Integer :a
209
+ unique :a
210
+ end
211
+
212
+ Just like +index+, +unique+ can set up a multiple column unique constraint, where the
213
+ combination of the columns must be unique:
214
+
215
+ create_table(:a) do
216
+ Integer :a
217
+ Integer :b
218
+ unique [:a, :b]
219
+ end
220
+
221
+ ==== +full_text_index+ and +spatial_index+
222
+
223
+ Both of these create specialized index types supported by some databases. They
224
+ both take the same options as +index+.
225
+
226
+ ==== +constraint+
227
+
228
+ +constraint+ creates a named table constraint:
229
+
230
+ create_table(:artists) do
231
+ primary_key :id
232
+ String :name
233
+ constraint(:name_min_length){char_length(name) > 2}
234
+ end
235
+
236
+ Instead of using a block, you can use arguments that will be handled similarly
237
+ to <tt>Dataset#filter</tt>:
238
+
239
+ create_table(:artists) do
240
+ primary_key :id
241
+ String :name
242
+ constraint(:name_length_range, :char_length.sql_function(:name)=>3..50)
243
+ end
244
+
245
+ ==== +check+
246
+
247
+ +check+ operates just like +constraint+, except that it doesn't take a name
248
+ and it creates an unnamed constraint
249
+
250
+ create_table(:artists) do
251
+ primary_key :id
252
+ String :name
253
+ check{char_length(name) > 2}
254
+ end
255
+
256
+ == +alter_table+
257
+
258
+ +alter_table+ is used to alter existing tables, changing their columns, indexes,
259
+ or constraints. It it used just like +create_table+, accepting a block which
260
+ is instance_evaled, and providing its own methods:
261
+
262
+ === +add_column+
263
+
264
+ One of the most common methods, +add_column+ is used to add a column to the table.
265
+ Its API is similar to that of +create_table+'s +column+ method, where the first
266
+ argument is the column name, the second is the type, and the third is an options
267
+ hash:
268
+
269
+ alter_table(:albums) do
270
+ add_column :copies_sold, Integer, :default=>0
271
+ end
272
+
273
+ When adding a column, it's a good idea to provide a default value, unless you
274
+ want the value for all rows to be set to NULL.
275
+
276
+ === +drop_column+
277
+
278
+ As you may expect, +drop_column+ takes a column name and drops the column. It's
279
+ often used in the +down+ block of a migration to drop a column added in an +up+ block:
280
+
281
+ alter_table(:albums) do
282
+ drop_column :copies_sold
283
+ end
284
+
285
+ === +rename_column+
286
+
287
+ +rename_column+ is used to rename a column. It takes the old column name as the first
288
+ argument, and the new column name as the second argument:
289
+
290
+ alter_table(:albums) do
291
+ rename_column :copies_sold, :total_sales
292
+ end
293
+
294
+ === +add_primary_key+
295
+
296
+ If you forgot to include a primary key on the table, and want to add one later, you
297
+ can use +add_primary_key+. A common use of this is to make many_to_many association
298
+ join tables into real models:
299
+
300
+ alter_table(:albums_artists) do
301
+ add_primary_key :id
302
+ end
303
+
304
+ Just like +create_table+'s +primary_key+ method, if you provide an array of symbols,
305
+ Sequel will not add a column, but will add a composite primary key constraint:
306
+
307
+ alter_table(:albums_artists) do
308
+ add_primary_key [:album_id, :artist_id]
309
+ end
310
+
311
+ If you just want to take an existing single column and make it a primary key, call
312
+ +add_primary_key+ with an array with a single symbol:
313
+
314
+ alter_table(:artists) do
315
+ add_primary_key [:id]
316
+ end
317
+
318
+ === +add_foreign_key+
319
+
320
+ +add_foreign_key+ can be used to add a new foreign key column or constraint to a table.
321
+ Like +add_primary_key+, if you provide it with a symbol as the first argument, it
322
+ creates a new column:
323
+
324
+ alter_table(:albums) do
325
+ add_foreign_key :artist_id, :artists
326
+ end
327
+
328
+ If you want to add a new foreign key constraint to an existing column, you provide an
329
+ array with a single element:
330
+
331
+ alter_table(:albums) do
332
+ add_foreign_key [:artist_id], :artists
333
+ end
334
+
335
+ To set up a multiple column foreign key constraint, use an array with multiple column
336
+ symbols:
337
+
338
+ alter_table(:albums) do
339
+ add_foreign_key [:artist_name, :artist_location], :artists
340
+ end
341
+
342
+ === +add_index+
343
+
344
+ +add_index+ works just like +create_table+'s +index+ method, creating a new index on
345
+ the table:
346
+
347
+ alter_table(:albums) do
348
+ add_index :artist_id
349
+ end
350
+
351
+ It accepts the same options as +create_table+'s +index+ method, and you can set up
352
+ a multiple column index using an array:
353
+
354
+ alter_table(:albums_artists) do
355
+ add_index [:album_id, :artist_id], :unique=>true
356
+ end
357
+
358
+ === +drop_index+
359
+
360
+ As you may expect, +drop_index+ drops an existing index:
361
+
362
+ alter_table(:albums) do
363
+ drop_index :artist_id
364
+ end
365
+
366
+ Just like +drop_column+, it is often used in the +down+ block of a migration.
367
+
368
+ To drop an index with a specific name, use the <tt>:name</tt> option:
369
+
370
+ alter_table(:albums) do
371
+ drop_index :artist_id, :name=>:artists_id_index
372
+ end
373
+
374
+ === +add_full_text_index+, +add_spatial_index+
375
+
376
+ Corresponding to +create_table+'s +full_text_index+ and +spatial_index+ methods,
377
+ these two methods create new indexes on the table.
378
+
379
+ === +add_constraint+
380
+
381
+ This adds a named constraint to the table, similar to +create_table+'s +constraint+
382
+ method:
383
+
384
+ alter_table(:albums) do
385
+ add_constraint(:name_min_length){char_length(name) > 2}
386
+ end
387
+
388
+ There is no method to add an unnamed constraint, but you can pass nil as the first
389
+ argument of +add_constraint+ to do so. However, it's not recommend to do that
390
+ as it is difficult to drop such a constraint.
391
+
392
+ === +add_unique_constraint+
393
+
394
+ This adds a unique constraint to the table, similar to +create_table+'s +unique+
395
+ method. This usually has the same effect as adding a unique index.
396
+
397
+ alter_table(:albums) do
398
+ add_unique_constraint [:artist_id, :name]
399
+ end
400
+
401
+ === +drop_constraint+
402
+
403
+ This method drops an existing named constraint:
404
+
405
+ alter_table(:albums) do
406
+ drop_constraint(:name_min_length)
407
+ end
408
+
409
+ There is no database independent method to drop an unnamed constraint. Generally, the
410
+ database will give it a name automatically, and you will have to figure out what it is.
411
+ For that reason, you should not add unnamed constraints that you ever might need to remove.
412
+
413
+ On MySQL, you must specify the type of constraint via a <tt>:type</tt> option:
414
+
415
+ alter_table(:albums) do
416
+ drop_constraint(:albums_pk, :type=>:primary_key)
417
+ drop_constraint(:albums_fk, :type=>:foreign_key)
418
+ drop_constraint(:albums_uk, :type=>:unique)
419
+ end
420
+
421
+ === +set_column_default+
422
+
423
+ This modifies the default value of a column:
424
+
425
+ alter_table(:albums) do
426
+ set_column_default :copies_sold, 0
427
+ end
428
+
429
+ === +set_column_type+
430
+
431
+ This modifies a column's type. Most databases will attempt to convert existing values in
432
+ the columns to the new type:
433
+
434
+ alter_table(:albums) do
435
+ set_column_type :copies_sold, Bignum
436
+ end
437
+
438
+ You can specify the type as a string or symbol, in which case it is used verbatim, or as a supported
439
+ ruby class, in which case it gets converted to an appropriate database type.
440
+
441
+ === +set_column_allow_null+
442
+
443
+ This changes the NULL or NOT NULL setting of a column:
444
+
445
+ alter_table(:albums) do
446
+ set_column_allow_null :artist_id, true # NULL
447
+ set_column_allow_null :copies_sold, false # NOT NULL
448
+ end
449
+
450
+ == Other +Database+ schema modification methods
451
+
452
+ <tt>Sequel::Database</tt> has many schema modification instance methods,
453
+ most of which are shortcuts to the same methods in +alter_table+. The
454
+ following +Database+ instance methods just call +alter_table+ with a
455
+ block that calls the method with the same name inside the +alter_table+
456
+ block with all arguments after the first argument (which is used as
457
+ the table name):
458
+
459
+ * +add_column+
460
+ * +drop_column+
461
+ * +rename_column+
462
+ * +add_index+
463
+ * +drop_index+
464
+ * +set_column_default+
465
+ * +set_column_type+
466
+
467
+ For example, the following two method calls do the same thing:
468
+
469
+ alter_table(:artists){add_column :copies_sold, Integer}
470
+ add_column :artists, :copies_sold, Integer
471
+
472
+ There are some other schema modification methods that have no +alter_table+
473
+ counterpart:
474
+
475
+ === +drop_table+
476
+
477
+ +drop_table+ takes multiple arguments and treats all arguments as a
478
+ table name to drop:
479
+
480
+ drop_table(:albums_artists, :albums, :artists)
481
+
482
+ Note that when dropping tables, you may need to drop them in a specific order
483
+ if you are using foreign keys and the database is enforcing referential
484
+ integrity. In general, you need to drop the tables containing the foreign
485
+ keys before the tables containing the primary keys they reference.
486
+
487
+ === +rename_table+
488
+
489
+ You can rename an existing table using +rename_table+. Like +rename_column+,
490
+ the first argument is the current name, and the second is the new name:
491
+
492
+ rename_table(:artist, :artists)
493
+
494
+ === <tt>create_table!</tt>
495
+
496
+ <tt>create_table!</tt> with the bang drops the table if it exists
497
+ before attempting to create it, so:
498
+
499
+ create_table!(:artists)
500
+ primary_key :id
501
+ end
502
+
503
+ is the same as:
504
+
505
+ drop_table(:artists) if table_exists?(:artists)
506
+ create_table(:artists)
507
+ primary_key :id
508
+ end
509
+
510
+ It should not be used inside migrations, as if the table does not exist, it may
511
+ mess up the migration.
512
+
513
+ === <tt>create_table?</tt>
514
+
515
+ <tt>create_table?</tt> with a question mark only creates the table if it does
516
+ not already exist, so:
517
+
518
+ create_table!(:artists)
519
+ primary_key :id
520
+ end
521
+
522
+ is the same as:
523
+
524
+ create_table(:artists)
525
+ primary_key :id
526
+ end unless table_exists?(:artists)
527
+
528
+ Like <tt>create_table!</tt>, it should not be used inside migrations.
529
+
530
+ === +create_view+ and +create_or_replace_view+
531
+
532
+ These can be used to create views. The difference between them is that
533
+ +create_or_replace_view+ will unconditionally replace an existing view of
534
+ the same name, while +create_view+ will probably raise an error. Both methods
535
+ take the name as the first argument, and either an string or a dataset as the
536
+ second argument:
537
+
538
+ create_view(:gold_albums, DB[:albums].filter{copies_sold > 500000})
539
+ create_or_replace_view(:gold_albums, "SELECT * FROM albums WHERE copies_sold > 500000")
540
+
541
+ === +drop_view+
542
+
543
+ +drop_view+ drops existing views. Just like +drop_table+, it can accept multiple
544
+ arguments:
545
+
546
+ drop_view(:gold_albums, :platinum_albums)
547
+