sequel 3.37.0 → 3.38.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +56 -0
- data/README.rdoc +82 -58
- data/Rakefile +6 -5
- data/bin/sequel +1 -1
- data/doc/active_record.rdoc +67 -52
- data/doc/advanced_associations.rdoc +33 -48
- data/doc/association_basics.rdoc +41 -51
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +47 -43
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +4 -5
- data/doc/model_hooks.rdoc +3 -3
- data/doc/object_model.rdoc +31 -25
- data/doc/opening_databases.rdoc +19 -5
- data/doc/prepared_statements.rdoc +2 -2
- data/doc/querying.rdoc +109 -52
- data/doc/reflection.rdoc +6 -6
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/schema_modification.rdoc +22 -13
- data/doc/sharding.rdoc +8 -9
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +47 -7
- data/doc/thread_safety.rdoc +1 -1
- data/doc/transactions.rdoc +1 -1
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +29 -43
- data/lib/sequel/adapters/do/postgres.rb +1 -4
- data/lib/sequel/adapters/jdbc.rb +14 -3
- data/lib/sequel/adapters/jdbc/db2.rb +9 -0
- data/lib/sequel/adapters/jdbc/derby.rb +41 -4
- data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
- data/lib/sequel/adapters/mock.rb +10 -4
- data/lib/sequel/adapters/postgres.rb +1 -28
- data/lib/sequel/adapters/shared/mssql.rb +23 -13
- data/lib/sequel/adapters/shared/postgres.rb +46 -0
- data/lib/sequel/adapters/swift.rb +21 -13
- data/lib/sequel/adapters/swift/mysql.rb +1 -0
- data/lib/sequel/adapters/swift/postgres.rb +4 -5
- data/lib/sequel/adapters/swift/sqlite.rb +2 -1
- data/lib/sequel/adapters/tinytds.rb +14 -2
- data/lib/sequel/adapters/utils/pg_types.rb +5 -0
- data/lib/sequel/core.rb +29 -17
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +3 -0
- data/lib/sequel/dataset/actions.rb +5 -6
- data/lib/sequel/dataset/query.rb +7 -7
- data/lib/sequel/dataset/sql.rb +5 -18
- data/lib/sequel/extensions/core_extensions.rb +8 -12
- data/lib/sequel/extensions/pg_array.rb +59 -33
- data/lib/sequel/extensions/pg_array_ops.rb +32 -4
- data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +32 -17
- data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
- data/lib/sequel/extensions/pg_inet.rb +1 -2
- data/lib/sequel/extensions/pg_interval.rb +0 -1
- data/lib/sequel/extensions/pg_json.rb +41 -23
- data/lib/sequel/extensions/pg_range.rb +36 -11
- data/lib/sequel/extensions/pg_range_ops.rb +32 -4
- data/lib/sequel/extensions/pg_row.rb +572 -0
- data/lib/sequel/extensions/pg_row_ops.rb +164 -0
- data/lib/sequel/extensions/query.rb +3 -3
- data/lib/sequel/extensions/schema_dumper.rb +7 -8
- data/lib/sequel/extensions/select_remove.rb +1 -1
- data/lib/sequel/model/base.rb +1 -0
- data/lib/sequel/no_core_ext.rb +1 -1
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/validation_helpers.rb +31 -0
- data/lib/sequel/sql.rb +64 -44
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +37 -12
- data/spec/adapters/mysql_spec.rb +39 -75
- data/spec/adapters/oracle_spec.rb +11 -11
- data/spec/adapters/postgres_spec.rb +414 -237
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +14 -14
- data/spec/core/database_spec.rb +6 -6
- data/spec/core/dataset_spec.rb +169 -205
- data/spec/core/expression_filters_spec.rb +182 -295
- data/spec/core/object_graph_spec.rb +6 -6
- data/spec/core/schema_spec.rb +14 -14
- data/spec/core/spec_helper.rb +1 -0
- data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
- data/spec/extensions/columns_introspection_spec.rb +5 -5
- data/spec/extensions/hook_class_methods_spec.rb +28 -36
- data/spec/extensions/many_through_many_spec.rb +4 -4
- data/spec/extensions/pg_array_ops_spec.rb +15 -7
- data/spec/extensions/pg_array_spec.rb +81 -48
- data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
- data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
- data/spec/extensions/pg_hstore_spec.rb +66 -65
- data/spec/extensions/pg_inet_spec.rb +2 -4
- data/spec/extensions/pg_interval_spec.rb +2 -3
- data/spec/extensions/pg_json_spec.rb +20 -18
- data/spec/extensions/pg_range_ops_spec.rb +11 -4
- data/spec/extensions/pg_range_spec.rb +30 -7
- data/spec/extensions/pg_row_ops_spec.rb +48 -0
- data/spec/extensions/pg_row_plugin_spec.rb +45 -0
- data/spec/extensions/pg_row_spec.rb +323 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
- data/spec/extensions/query_literals_spec.rb +11 -11
- data/spec/extensions/query_spec.rb +3 -3
- data/spec/extensions/schema_dumper_spec.rb +20 -4
- data/spec/extensions/schema_spec.rb +18 -41
- data/spec/extensions/select_remove_spec.rb +4 -4
- data/spec/extensions/spec_helper.rb +4 -8
- data/spec/extensions/to_dot_spec.rb +5 -5
- data/spec/extensions/validation_class_methods_spec.rb +28 -16
- data/spec/integration/associations_test.rb +20 -20
- data/spec/integration/dataset_test.rb +98 -98
- data/spec/integration/eager_loader_test.rb +13 -27
- data/spec/integration/plugin_test.rb +5 -5
- data/spec/integration/prepared_statement_test.rb +22 -13
- data/spec/integration/schema_test.rb +28 -18
- data/spec/integration/spec_helper.rb +1 -1
- data/spec/integration/timezone_test.rb +2 -2
- data/spec/integration/type_test.rb +15 -6
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +4 -4
- data/spec/model/base_spec.rb +5 -5
- data/spec/model/eager_loading_spec.rb +15 -15
- data/spec/model/model_spec.rb +32 -32
- data/spec/model/record_spec.rb +16 -0
- data/spec/model/spec_helper.rb +2 -6
- data/spec/model/validations_spec.rb +1 -1
- metadata +16 -4
data/doc/reflection.rdoc
CHANGED
@@ -58,12 +58,12 @@ The hash may also contain entries for:
|
|
58
58
|
|
59
59
|
Database#schema takes a table symbol and returns column information in an array with each element being an array with two elements. The first elements of the subarray is a column symbol, and the second element is a hash of information about that column. The hash should include the following keys:
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
:allow_null :: Whether NULL/nil is an allowed value for this column. Used by the Sequel::Model typecasting code.
|
62
|
+
:db_type :: The type of column the database provided, as a string. Used by the schema_dumper plugin for a more specific type translation.
|
63
|
+
:default :: The default value of the column, as either a string or nil. Uses a database specific format. Used by the schema_dumper plugin for converting to a ruby value.
|
64
|
+
:primary_key :: Whether this column is one of the primary key columns for the table. Used by the Sequel::Model code to determine primary key columns.
|
65
|
+
:ruby_default :: The default value of the column as a ruby object, or nil if there is no default or the default could not be successfully parsed into a ruby object.
|
66
|
+
:type :: The type of column, as a symbol (e.g. :string). Used by the Sequel::Model typecasting code.
|
67
67
|
|
68
68
|
Example:
|
69
69
|
|
@@ -0,0 +1,234 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A pg_row extension has been added that supports PostgreSQL's
|
4
|
+
row-valued/composite types. You can register support for
|
5
|
+
specific row types:
|
6
|
+
|
7
|
+
DB.register_row_type(:address)
|
8
|
+
|
9
|
+
Then you can create values of that row type:
|
10
|
+
|
11
|
+
ad = DB.row_type(:address, ['555 Foo St.', 'Bar City', '98765'])
|
12
|
+
# or
|
13
|
+
ad = DB.row_type(:address, :street=>'555 Foo St.',
|
14
|
+
:city=>'Bar City', :zip=>'98765')
|
15
|
+
|
16
|
+
Which you can use in your datasets:
|
17
|
+
|
18
|
+
DB[:people].insert(:name=>'Me', :address=>ad)
|
19
|
+
|
20
|
+
If you are using the native postgres adapter, when retreiving
|
21
|
+
row type values, they will be returned as instances of the row
|
22
|
+
type, which are hash-like objects:
|
23
|
+
|
24
|
+
ad = DB[:people].get(:address)
|
25
|
+
ad[:street] # => '555 Foo St.'
|
26
|
+
ad[:city] # => 'Bar City'
|
27
|
+
ad[:zip] # => '98765'
|
28
|
+
|
29
|
+
If you are also using the pg_array extension, then arrays of
|
30
|
+
composite types are supported automatically. Composite
|
31
|
+
types can also include arrays of other types as well as other
|
32
|
+
composite types, though recursive composite types are not
|
33
|
+
allowed by PostgreSQL.
|
34
|
+
|
35
|
+
Using arrays and composite types brings one of the benefits
|
36
|
+
of document databases to PostgreSQL, allowing you to store
|
37
|
+
nested structures inside a single row.
|
38
|
+
|
39
|
+
* A pg_row_ops extension has been added that adds DSL support
|
40
|
+
for accessing members of row-valued/composite types. You
|
41
|
+
first create a row op:
|
42
|
+
|
43
|
+
r = Sequel.pg_row_op(:row_column)
|
44
|
+
|
45
|
+
Then you can get DSL support for accessing members of that
|
46
|
+
row_column via the #[] method:
|
47
|
+
|
48
|
+
r[:a] # (row_column).a
|
49
|
+
|
50
|
+
This works with composite types containing composite types:
|
51
|
+
|
52
|
+
r[:a][:b] # ((row_column).a).b
|
53
|
+
|
54
|
+
When used in conjunction with the pg_array_ops extension,
|
55
|
+
there is support for composite types that include arrays,
|
56
|
+
as well as arrays of composite types:
|
57
|
+
|
58
|
+
r[1][:a] # (row_column[1]).a
|
59
|
+
r[:a][1] # (row_column).a[1]
|
60
|
+
|
61
|
+
The extension offers additional support for referencing
|
62
|
+
a table's type when it contains a column with the same
|
63
|
+
name, see the RDoc for details.
|
64
|
+
|
65
|
+
* A pg_row plugin has been added, that works with the pg_row
|
66
|
+
extension, and allows you to represent row-valued types as
|
67
|
+
Sequel::Model objects (instead of the hash-like objects
|
68
|
+
they use by default). In your model class, you load the
|
69
|
+
plugin:
|
70
|
+
|
71
|
+
class Address < Sequel::Model(:address)
|
72
|
+
plugin :pg_row
|
73
|
+
end
|
74
|
+
|
75
|
+
Then you can use Address instances in your datasets:
|
76
|
+
|
77
|
+
ad = Address.new(:street=>'555 Foo St.',
|
78
|
+
:city=>'Bar City', :zip=>'98765')
|
79
|
+
DB[:people].insert(:name=>'Me', :address=>ad)
|
80
|
+
|
81
|
+
And if you are using the native postgres adapter, the dataset
|
82
|
+
will return the type as a model instance:
|
83
|
+
|
84
|
+
ad = DB[:people].get(:address)
|
85
|
+
ad.street # => '555 Foo St.'
|
86
|
+
ad.city # => 'Bar City'
|
87
|
+
ad.zip # => '98765'
|
88
|
+
|
89
|
+
* A pg_typecast_on_load plugin has been added. This plugin is
|
90
|
+
designed for use with the jdbc/postgres, do/postgres, and
|
91
|
+
swift/postgres adapters, and it is similar to the
|
92
|
+
typecast_on_load plugin. However, while the typecast_on_load
|
93
|
+
plugin uses setter methods, the pg_typecast_on_load plugin
|
94
|
+
uses the same code that the native postgres adapter uses for
|
95
|
+
typecasting.
|
96
|
+
|
97
|
+
* The tinytds adapter now supports a :textsize option to override
|
98
|
+
the default TEXTSIZE setting. The FreeTDS default is fairly
|
99
|
+
small (~64k), so if you want to use large blob or text columns,
|
100
|
+
you should probably set this to a value larger than the
|
101
|
+
largest text/blob you want to use.
|
102
|
+
|
103
|
+
* Sequel.expr when called with a symbol now splits the symbol and
|
104
|
+
returns an Identifier, QualifiedIdentifier, or AliasedExpression,
|
105
|
+
depending on the content of the symbol. Previously, it only
|
106
|
+
wrapped the symbol using a Wrapper.
|
107
|
+
|
108
|
+
* Identifier#* and QualifiedIdentifier#* when called without any
|
109
|
+
argument now represent a selection of all columns from the
|
110
|
+
represented table:
|
111
|
+
|
112
|
+
Sequel.expr(:table).* # table.*
|
113
|
+
Sequel.expr(:schema__table).* # schema.table.*
|
114
|
+
|
115
|
+
This makes it easier to represent the selection of all columns
|
116
|
+
in a table without using the core extensions.
|
117
|
+
|
118
|
+
* Model#values now has a Model#to_hash alias.
|
119
|
+
|
120
|
+
* SQL::Blob values now have as, cast, and lit methods even if the
|
121
|
+
core extensions are not loaded.
|
122
|
+
|
123
|
+
= Other Improvements
|
124
|
+
|
125
|
+
* When loading multiple pg_* extensions into a Database instance,
|
126
|
+
the conversion procs are only reset once instead of once per
|
127
|
+
extension.
|
128
|
+
|
129
|
+
* All adapters that access PostgreSQL now store type conversion
|
130
|
+
procs, similar to the native postgres adapter. This has been
|
131
|
+
added to make it easier to write extensions that support
|
132
|
+
advanced PostgreSQL types.
|
133
|
+
|
134
|
+
* Database#schema output on PostgreSQL now includes the type oid
|
135
|
+
for each column.
|
136
|
+
|
137
|
+
* You can now register custom array types to specific Database
|
138
|
+
instances, using the :type_procs and :typecast_methods_module
|
139
|
+
options, so it is now possible to have custom array types
|
140
|
+
without affecting global state.
|
141
|
+
|
142
|
+
* Dropping of columns with defaults now works correctly on
|
143
|
+
Microsoft SQL Server. Before, it would fail as the related
|
144
|
+
constraint was not dropped first.
|
145
|
+
|
146
|
+
* The MySQL type "double(x,y)" is now recognized as a float type.
|
147
|
+
|
148
|
+
* The jdbc/jtds and jdbc/derby adapters now handle nil prepared
|
149
|
+
statement values in more cases.
|
150
|
+
|
151
|
+
* Blob prepared statement arguments are now handled correctly on
|
152
|
+
jdbc/db2 and jdbc/oracle.
|
153
|
+
|
154
|
+
* Sequel now works around a Time#nsec bug in JRuby 1.6 ruby 1.9 mode
|
155
|
+
when using Time values in prepared statements in the jdbc adapter.
|
156
|
+
|
157
|
+
* Java::JavaUtil::UUID types are now returned as ruby strings
|
158
|
+
when converting types in the jdbc adapter.
|
159
|
+
|
160
|
+
* Real boolean literals are now used on derby 10.7+. On derby <10.7
|
161
|
+
Sequel still uses (1 = 1) and (1 != 1) for true and false. This
|
162
|
+
allows you to use boolean columns with a true/false default on
|
163
|
+
derby 10.7+.
|
164
|
+
|
165
|
+
* Clobs are now treated as string types instead of blobs on derby,
|
166
|
+
since treating clob as blob doesn't work there.
|
167
|
+
|
168
|
+
* The swift adapter now supports an output identifier method.
|
169
|
+
|
170
|
+
* The swift adapter now returns blobs as SQL::Blob instances.
|
171
|
+
|
172
|
+
* The schema_dumper extension no longer produces code that requires
|
173
|
+
the core extensions.
|
174
|
+
|
175
|
+
* All of Sequel's specs now run without the core extensions loaded,
|
176
|
+
ensuring that none of the internals depend on the core extensions.
|
177
|
+
The only exception is the specs for the core extensions themselves.
|
178
|
+
|
179
|
+
= Backwards Compatibility
|
180
|
+
|
181
|
+
* The pg_* extensions no longer modify core classes if the
|
182
|
+
core_extensions extension is not loaded. All methods they added now
|
183
|
+
have equivalent methods on the main Sequel module:
|
184
|
+
|
185
|
+
Sequel.pg_array
|
186
|
+
Sequel.pg_array_op
|
187
|
+
Sequel.hstore
|
188
|
+
Sequel.hstore_op
|
189
|
+
Sequel.pg_json
|
190
|
+
Sequel.pg_range
|
191
|
+
Sequel.pg_range_op
|
192
|
+
|
193
|
+
* The Sequel::SQL::IdentifierMethods module has been removed. This
|
194
|
+
module was only included in Symbol if the core_extensions were
|
195
|
+
enabled. Since it only defined a single method, now the core
|
196
|
+
extensions just define that method directly on Symbol.
|
197
|
+
|
198
|
+
* The swift adapter now requires swift-db-{postgres,mysql,sqlite3}
|
199
|
+
gems instead of the swift gem. swift/postgres requires
|
200
|
+
swift-db-postgres 0.2.0+, swift/sqlite requires swift-db-sqlite
|
201
|
+
0.1.2+, and swift/mysql requires swift-db-mysql.
|
202
|
+
|
203
|
+
* Sequel will no longer typecast a string to a PostgreSQL array
|
204
|
+
or hstore column in a model column setter. This is because the
|
205
|
+
parsers that Sequel uses were designed to support only
|
206
|
+
PostgreSQL's output format. It's unlikely that a user would
|
207
|
+
provide that format for typecasting, and while there aren't known
|
208
|
+
security issues with the parsers, they were not designed to handle
|
209
|
+
arbtirary user input, so typecasting from string is no longer
|
210
|
+
allowed and will now raise an error.
|
211
|
+
|
212
|
+
The only reason such typecasting was allowed in the first place
|
213
|
+
was to work around issues in the jdbc/postgres, do/postgres, and
|
214
|
+
swift/postgres adapters, using the the typecast_on_load plugin.
|
215
|
+
If you were previously using the typecast_on_load plugin for
|
216
|
+
hstore or array columns, you need to switch to using the new
|
217
|
+
pg_typecast_on_load plugin.
|
218
|
+
|
219
|
+
* The private get_conversion_procs method in the postgres adapter
|
220
|
+
no longer accepts an argument.
|
221
|
+
|
222
|
+
* The Sequel::Postgres::PGArray::DatabaseMethods singleton
|
223
|
+
define_array_typecast_method method has been removed. This
|
224
|
+
method was designed for internal use.
|
225
|
+
|
226
|
+
* The change to make Sequel.expr split symbols can cause the
|
227
|
+
following type of code to break:
|
228
|
+
|
229
|
+
Sequel.expr(:column___alias).desc
|
230
|
+
|
231
|
+
This is because expr now returns an AliasedExpression, which
|
232
|
+
doesn't support the desc method. However, as you can't
|
233
|
+
apply an order to an aliased expression, nobody should be
|
234
|
+
relying on this.
|
@@ -241,12 +241,12 @@ both take the same options as +index+.
|
|
241
241
|
end
|
242
242
|
|
243
243
|
Instead of using a block, you can use arguments that will be handled similarly
|
244
|
-
to <tt>Dataset#
|
244
|
+
to <tt>Dataset#where</tt>:
|
245
245
|
|
246
246
|
create_table(:artists) do
|
247
247
|
primary_key :id
|
248
248
|
String :name
|
249
|
-
constraint(:name_length_range,
|
249
|
+
constraint(:name_length_range, Sequel.function(:char_length, :name)=>3..50)
|
250
250
|
end
|
251
251
|
|
252
252
|
==== +check+
|
@@ -299,9 +299,6 @@ hash:
|
|
299
299
|
add_column :copies_sold, Integer, :default=>0
|
300
300
|
end
|
301
301
|
|
302
|
-
When adding a column, it's a good idea to provide a default value, unless you
|
303
|
-
want the value for all rows to be set to NULL.
|
304
|
-
|
305
302
|
=== +drop_column+
|
306
303
|
|
307
304
|
As you may expect, +drop_column+ takes a column name and drops the column. It's
|
@@ -439,7 +436,7 @@ There is no database independent method to drop an unnamed constraint. Generall
|
|
439
436
|
database will give it a name automatically, and you will have to figure out what it is.
|
440
437
|
For that reason, you should not add unnamed constraints that you ever might need to remove.
|
441
438
|
|
442
|
-
On
|
439
|
+
On some databases, you must specify the type of constraint via a <tt>:type</tt> option:
|
443
440
|
|
444
441
|
alter_table(:albums) do
|
445
442
|
drop_constraint(:albums_pk, :type=>:primary_key)
|
@@ -513,6 +510,16 @@ if you are using foreign keys and the database is enforcing referential
|
|
513
510
|
integrity. In general, you need to drop the tables containing the foreign
|
514
511
|
keys before the tables containing the primary keys they reference.
|
515
512
|
|
513
|
+
=== <tt>drop_table?</tt>
|
514
|
+
|
515
|
+
<tt>drop_table?</tt> is similar to drop_table, except that it only drops
|
516
|
+
the table if the table does not already exist. On some databases, it uses
|
517
|
+
<tt>IF NOT EXISTS</tt>, on others it does a separate query to check for
|
518
|
+
existence.
|
519
|
+
|
520
|
+
This should not be used inside migrations, as if the the tbale does not
|
521
|
+
exist, it may mess up the migration.
|
522
|
+
|
516
523
|
=== +rename_table+
|
517
524
|
|
518
525
|
You can rename an existing table using +rename_table+. Like +rename_column+,
|
@@ -522,7 +529,7 @@ the first argument is the current name, and the second is the new name:
|
|
522
529
|
|
523
530
|
=== <tt>create_table!</tt>
|
524
531
|
|
525
|
-
<tt>create_table!</tt>
|
532
|
+
<tt>create_table!</tt> drops the table if it exists
|
526
533
|
before attempting to create it, so:
|
527
534
|
|
528
535
|
create_table!(:artists)
|
@@ -531,7 +538,7 @@ before attempting to create it, so:
|
|
531
538
|
|
532
539
|
is the same as:
|
533
540
|
|
534
|
-
drop_table
|
541
|
+
drop_table?(:artists)
|
535
542
|
create_table(:artists)
|
536
543
|
primary_key :id
|
537
544
|
end
|
@@ -541,7 +548,7 @@ mess up the migration.
|
|
541
548
|
|
542
549
|
=== <tt>create_table?</tt>
|
543
550
|
|
544
|
-
<tt>create_table?</tt>
|
551
|
+
<tt>create_table?</tt> only creates the table if it does
|
545
552
|
not already exist, so:
|
546
553
|
|
547
554
|
create_table?(:artists)
|
@@ -550,9 +557,11 @@ not already exist, so:
|
|
550
557
|
|
551
558
|
is the same as:
|
552
559
|
|
553
|
-
|
554
|
-
|
555
|
-
|
560
|
+
unless table_exists?(:artists)
|
561
|
+
create_table(:artists)
|
562
|
+
primary_key :id
|
563
|
+
end
|
564
|
+
end
|
556
565
|
|
557
566
|
Like <tt>create_table!</tt>, it should not be used inside migrations.
|
558
567
|
|
@@ -564,7 +573,7 @@ the same name, while +create_view+ will probably raise an error. Both methods
|
|
564
573
|
take the name as the first argument, and either an string or a dataset as the
|
565
574
|
second argument:
|
566
575
|
|
567
|
-
create_view(:gold_albums, DB[:albums].
|
576
|
+
create_view(:gold_albums, DB[:albums].where{copies_sold > 500000})
|
568
577
|
create_or_replace_view(:gold_albums, "SELECT * FROM albums WHERE copies_sold > 500000")
|
569
578
|
|
570
579
|
=== +drop_view+
|
data/doc/sharding.rdoc
CHANGED
@@ -109,7 +109,7 @@ schemas, so you should always have a default server that works.
|
|
109
109
|
|
110
110
|
To set the shard for a given query, you use the Dataset#server method:
|
111
111
|
|
112
|
-
DB[:hashes].server(:a).
|
112
|
+
DB[:hashes].server(:a).where(:hash=>/31337/)
|
113
113
|
|
114
114
|
That will return all matching rows on the hash_host_a shard that have a hash
|
115
115
|
column that contains 31337.
|
@@ -119,10 +119,11 @@ work, you might want to add a method to the dataset that automatically sets
|
|
119
119
|
the shard to use. This is fairly easy using a Sequel::Model:
|
120
120
|
|
121
121
|
class Rainbow < Sequel::Model(:hashes)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
122
|
+
dataset_module do
|
123
|
+
def plaintext_for_hash(hash)
|
124
|
+
raise(ArgumentError, 'Invalid SHA-1 Hash') unless /\A[0-9a-f]{40}\z/.match(hash)
|
125
|
+
server(hash[0...1].to_sym).where(:hash=>hash).get(:plaintext)
|
126
|
+
end
|
126
127
|
end
|
127
128
|
end
|
128
129
|
|
@@ -179,8 +180,7 @@ same shard, it can get a bit redundent to specify the same shard for all of them
|
|
179
180
|
The server_block extension adds a Database#with_server method that scopes all database
|
180
181
|
access inside the block to the given shard by default:
|
181
182
|
|
182
|
-
|
183
|
-
DB.extend Sequel::ServerBlock
|
183
|
+
DB.extension :server_block
|
184
184
|
DB.with_server(:a) do
|
185
185
|
# this SELECT query uses the "a" shard
|
186
186
|
if r = Rainbow.first(:hash=>/31337/)
|
@@ -208,8 +208,7 @@ shards on the fly, but it is a bit cumbersome to work with truly arbitrary serve
|
|
208
208
|
The arbitrary_servers extension allows you to pass a server/shard options hash as the
|
209
209
|
server to use, and those options will be merged directly into the database's default options:
|
210
210
|
|
211
|
-
|
212
|
-
DB.pool.extend Sequel::ArbitraryServers
|
211
|
+
DB.extension :arbitrary_servers
|
213
212
|
DB[:rainbows].server(:host=>'hash_host_a').all
|
214
213
|
# or
|
215
214
|
DB[:rainbows].server(:host=>'hash_host_b', :database=>'backup').all
|
data/doc/sql.rdoc
CHANGED
@@ -73,10 +73,14 @@ You can also use <tt>Database#<<</tt>:
|
|
73
73
|
|
74
74
|
=== Other Places
|
75
75
|
|
76
|
-
Almost everywhere in Sequel, you can drop down to literal SQL by providing a literal string, which you can create with <tt>
|
76
|
+
Almost everywhere in Sequel, you can drop down to literal SQL by providing a literal string, which you can create with <tt>Sequel.lit</tt>:
|
77
77
|
|
78
78
|
DB[:albums].select('name') # SELECT 'name' FROM albums
|
79
|
-
DB[:albums].select('name'
|
79
|
+
DB[:albums].select(Sequel.lit('name')) # SELECT name FROM albums
|
80
|
+
|
81
|
+
For a simpler way of creating literal strings, you can also use the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html], which adds the <tt>String#lit</tt> method, and other methods that integrate Sequel's DSL with the ruby language:
|
82
|
+
|
83
|
+
DB[:albums].select('name'.lit)
|
80
84
|
|
81
85
|
So you can use Sequel's DSL everywhere you find it helpful, and fallback to literal SQL if the DSL can't do what you want or you just find literal SQL easier.
|
82
86
|
|
@@ -129,9 +133,9 @@ Also note that specifying the period inside the symbol doesn't work if you are q
|
|
129
133
|
|
130
134
|
:"table.column" # "table.column"
|
131
135
|
|
132
|
-
The other way to qualify an identifier is to use the
|
136
|
+
The other way to qualify an identifier is to use the <tt>Sequel.qualify</tt> with the table and column symbols:
|
133
137
|
|
134
|
-
|
138
|
+
Sequel.qualify(:table, :column) # "table"."column"
|
135
139
|
|
136
140
|
Another way to generate identifiers is to use Sequel's {virtual row support}[link:files/doc/virtual_rows_rdoc.html]:
|
137
141
|
|
@@ -169,37 +173,37 @@ You can combine this with implicit qualification:
|
|
169
173
|
|
170
174
|
:table__column___alias # "table"."column" AS "alias"
|
171
175
|
|
172
|
-
You can also use the +as+ method on
|
176
|
+
You can also use the <tt>Sequel.as</tt> method to create an alias, and the +as+ method on most Sequel-specific expression objects:
|
173
177
|
|
174
|
-
|
175
|
-
|
178
|
+
Sequel.as(:column, :alias) # "column" AS "alias"
|
179
|
+
Sequel.qualify(:table, :column).as(:alias) # "table"."column" AS "alias"
|
176
180
|
|
177
181
|
=== Functions
|
178
182
|
|
179
183
|
The easiest way to use SQL functions is via a virtual row:
|
180
184
|
|
181
|
-
DB[:albums].select{
|
182
|
-
DB[:albums].select{
|
185
|
+
DB[:albums].select{func{}} # SELECT func() FROM "albums"
|
186
|
+
DB[:albums].select{func(col1, col2)} # SELECT func("col1", "col2") FROM "albums"
|
183
187
|
|
184
|
-
You can also use the
|
188
|
+
You can also use the <tt>Sequel.function</tt> method on the symbol that contains the function name:
|
185
189
|
|
186
|
-
:
|
187
|
-
|
190
|
+
Sequel.function(:func) # func()
|
191
|
+
Sequel.function(:func, :col1, :col2) # func("col1", "col2")
|
188
192
|
|
189
193
|
=== Aggregate Functions
|
190
194
|
|
191
195
|
Aggregate functions work the same way as normal functions, since they share the same syntax:
|
192
196
|
|
193
|
-
|
197
|
+
Sequel.function(:sum, :column) # sum(column)
|
194
198
|
|
195
199
|
However, if you want to use the DISTINCT modifier to an aggregate function, you either have to use literal SQL or a virtual row block:
|
196
200
|
|
197
|
-
:sum.
|
201
|
+
Sequel.function(:sum, Sequel.lit('DISTINCT column')) # sum(DISTINCT column)
|
198
202
|
DB[:albums].select{sum(:distinct, :column){}} # SELECT sum(DISTINCT column) FROM albums
|
199
203
|
|
200
204
|
If you want to use the wildcard as the sole argument of the aggregate function, you again have to use literal SQL or a virtual row block:
|
201
205
|
|
202
|
-
:count.
|
206
|
+
Sequel.function(:count, Sequel.lit('*')) # count(*)
|
203
207
|
DB[:albums].select{count(:*){}} # SELECT count(*) FROM albums
|
204
208
|
|
205
209
|
Note that Sequel provides helper methods for aggregate functions such as +count+, +sum+, +min+, +max+, +avg+, and +group_and_count+, which handle common uses of aggregate functions.
|
@@ -232,28 +236,35 @@ You can also specify this as an array of two element arrays:
|
|
232
236
|
|
233
237
|
=== Not Equal Operator (!=)
|
234
238
|
|
235
|
-
You can specify a not equals condition by inverting the hash or array of two element arrays using
|
239
|
+
You can specify a not equals condition by inverting the hash or array of two element arrays using <tt>Sequel.negate</tt> or <tt>Sequel.~</tt>:
|
240
|
+
|
241
|
+
Sequel.negate(:column => 1) # ("column" != 1)
|
242
|
+
Sequel.negate([[:column, 1]]) # ("column" != 1)
|
243
|
+
Sequel.~(:column => 1) # ("column" != 1)
|
244
|
+
Sequel.~([[:column, 1]]) # ("column" != 1)
|
236
245
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
246
|
+
The difference between the two is that negate only works on hashes and arrays of element arrays, and it negates all entries in the, while ~ does a general inversion. This is best shown by an example with multiple entries:
|
247
|
+
|
248
|
+
Sequel.negate(:column => 1, :foo => 2) # (("column" != 1) AND (foo != 2))
|
249
|
+
Sequel.~(:column => 1, :foo => 2) # (("column" != 1) OR (foo != 2))
|
241
250
|
|
242
251
|
The most common need for not equals is in filters, in which case you can use the +exclude+ method:
|
243
252
|
|
244
253
|
DB[:albums].exclude(:column=>1) # SELECT * FROM "albums" WHERE ("column" != 1)
|
245
254
|
|
255
|
+
Note that +exclude+ does a generalized inversion, similar to <tt>Sequel.~</tt>.
|
256
|
+
|
246
257
|
=== Inclusion and Exclusion Operators (IN, NOT IN)
|
247
258
|
|
248
259
|
Sequel also uses hashes to specify inclusion, and inversions of those hashes to specify exclusion:
|
249
260
|
|
250
261
|
{:column=>[1, 2, 3]} # ("column" IN (1, 2, 3))
|
251
|
-
|
262
|
+
Sequel.~(:column=>[1, 2, 3]) # ("column" NOT IN (1, 2, 3))
|
252
263
|
|
253
264
|
As you may have guessed, Sequel switches from an = to an IN when the hash value is an array. It also does this for datasets, which easily allows you to test for inclusion and exclusion in a subselect:
|
254
265
|
|
255
266
|
{:column=>DB[:albums].select(:id)} # ("column" IN (SELECT "id" FROM "albums"))
|
256
|
-
|
267
|
+
Sequel.~(:column=>DB[:albums].select(:id)) # ("column" NOT IN (SELECT "id" FROM "albums"))
|
257
268
|
|
258
269
|
Sequel also supports the SQL EXISTS operator using <tt>Dataset#exists</tt>:
|
259
270
|
|
@@ -269,19 +280,19 @@ Hashes in Sequel use IS if the value is true, false, or nil:
|
|
269
280
|
|
270
281
|
Negation works the same way as it does for equality and inclusion:
|
271
282
|
|
272
|
-
|
273
|
-
|
274
|
-
|
283
|
+
Sequel.~(:column=>nil) # ("column" IS NOT NULL)
|
284
|
+
Sequel.~(:column=>true) # ("column" IS NOT TRUE)
|
285
|
+
Sequel.~(:column=>false) # ("column" IS NOT FALSE)
|
275
286
|
|
276
287
|
=== Inversion Operator (NOT)
|
277
288
|
|
278
289
|
Sequel's general inversion operator is ~, which works on symbols and most Sequel-specific expression objects:
|
279
290
|
|
280
|
-
|
291
|
+
Sequel.~(:column) # NOT "column"
|
281
292
|
|
282
293
|
Note that ~ will actually apply the inversion operation to the underlying object, which is why
|
283
294
|
|
284
|
-
|
295
|
+
Sequel.~(:column=>1)
|
285
296
|
|
286
297
|
produces <tt>(column != 1)</tt> instead of <tt>NOT (column = 1)</tt>.
|
287
298
|
|
@@ -289,198 +300,229 @@ produces <tt>(column != 1)</tt> instead of <tt>NOT (column = 1)</tt>.
|
|
289
300
|
|
290
301
|
Sequel defines the inequality operators directly on most Sequel-specific expression objects:
|
291
302
|
|
292
|
-
|
293
|
-
|
294
|
-
:
|
295
|
-
|
303
|
+
Sequel.qualify(:table, :column) > 1 # ("table"."column" > 1)
|
304
|
+
Sequel.qualify(:table, :column) < 1 # ("table"."column" < 1)
|
305
|
+
Sequel.function(:func) >= 1 # (func() >= 1)
|
306
|
+
Sequel.function(:func, :column) <= 1 # (func("column") <= 1)
|
296
307
|
|
297
|
-
If you want to use them on a symbol, you should call
|
308
|
+
If you want to use them on a symbol, you should call <tt>Sequel.expr</tt> with the symbol:
|
298
309
|
|
299
|
-
:column
|
310
|
+
Sequel.expr(:column) > 1 # ("column" > 1)
|
300
311
|
|
301
312
|
A common use of virtual rows is to handle inequality operators:
|
302
313
|
|
303
|
-
DB[:albums].
|
314
|
+
DB[:albums].where{col1 > col2} # SELECT * FROM "albums" WHERE ("col1" > "col2")
|
304
315
|
|
305
316
|
=== Standard Mathematical Operators (+ - * /)
|
306
317
|
|
307
|
-
The standard mathematical operates are defined on
|
318
|
+
The standard mathematical operates are defined on most Sequel-specific expression objects:
|
319
|
+
|
320
|
+
Sequel.expr(:column) + 1 # "column" + 1
|
321
|
+
Sequel.expr(:table__column) - 1 # "table"."column" - 1
|
322
|
+
Sequel.qualify(:table, :column) * 1 # "table"."column" * 1
|
323
|
+
Sequel.expr(:column) / 1 # "column" / 1
|
308
324
|
|
309
|
-
|
310
|
-
|
311
|
-
:column
|
312
|
-
:
|
325
|
+
You can also call the operator methods directly on the Sequel module:
|
326
|
+
|
327
|
+
Sequel.+(:column, 1) # "column" + 1
|
328
|
+
Sequel.-(:table__column, 1) # "table"."column" - 1
|
329
|
+
Sequel.*(Sequel.qualify(:table, :column), 1) # "table"."column" * 1
|
330
|
+
Sequel./(:column, 1) # "column" / 1
|
313
331
|
|
314
332
|
Note that the following does not work:
|
315
333
|
|
316
|
-
1 + :column # raises TypeError
|
334
|
+
1 + Sequel.expr(:column) # raises TypeError
|
317
335
|
|
318
|
-
For commutative operates such as + and *, this isn't a problem as you can just reorder, but non-commutative operators such as - and / cannot be expressed directly.
|
336
|
+
For commutative operates such as + and *, this isn't a problem as you can just reorder, but non-commutative operators such as - and / cannot be expressed directly. The solution is to use one of the methods on the Sequel module:
|
319
337
|
|
320
|
-
Sequel.
|
321
|
-
1
|
338
|
+
Sequel.expr(1) / :column # (1 / "column")
|
339
|
+
Sequel./(1, :column) # (1 / "column")
|
322
340
|
|
323
341
|
=== Boolean Operators (AND OR)
|
324
342
|
|
325
|
-
Sequel defines the & and | methods on
|
343
|
+
Sequel defines the & and | methods on most Sequel-specific expression objects to handle AND and OR:
|
326
344
|
|
327
|
-
:column1 & :column2 # ("column1" AND "column2")
|
328
|
-
|
329
|
-
(:
|
345
|
+
Sequel.expr(:column1) & :column2 # ("column1" AND "column2")
|
346
|
+
Sequel.expr(:column1=>1) | {:column2=>2} # (("column1" = 1) OR ("column2" = 2))
|
347
|
+
(Sequel.function(:func) > 1) & :column3 # ((func() > 1) AND "column3")
|
330
348
|
|
331
349
|
Note the use of parentheses in the last statement. If you omit them, you won't get what you expect:
|
332
350
|
|
333
|
-
:
|
351
|
+
Sequel.function(:func) > 1 & :column3 # (func() > 1)
|
334
352
|
|
335
353
|
This is because & has higher precedence than >, so it is parsed as:
|
336
354
|
|
337
|
-
:
|
355
|
+
Sequel.function(:func) > (1 & :column3)
|
338
356
|
|
339
357
|
In this case, <tt>:column3.to_int</tt> returns an odd integer, so:
|
340
358
|
|
341
359
|
1 & :column3 # => 1
|
342
360
|
|
361
|
+
You and also use the <tt>Sequel.&</tt> and <tt>Sequel.|</tt> methods:
|
362
|
+
|
363
|
+
Sequel.&(:column1, :column2) # ("column1" AND "column2")
|
364
|
+
Sequel.|({:column1=>1}, {:column2=>2}) # (("column1" = 1) OR ("column2" = 2))
|
365
|
+
|
343
366
|
You can use hashes and arrays of two element arrays to specify AND and OR with equality conditions:
|
344
367
|
|
345
368
|
{:column1=>1, :column2=>2} # (("column1" = 1) AND ("column2" = 2))
|
346
369
|
[[:column1, 1], [:column2, 2]] # (("column1" = 1) AND ("column2" = 2))
|
347
370
|
|
348
|
-
As you can see, these literalize with ANDs by default. You can use the
|
371
|
+
As you can see, these literalize with ANDs by default. You can use the <tt>Sequel.or</tt> method to use OR instead:
|
349
372
|
|
350
|
-
|
373
|
+
Sequel.or(:column1=>1, :column2=>2) # (("column1" = 1) OR ("column2" = 2))
|
351
374
|
|
352
|
-
You've already seen the
|
375
|
+
You've already seen the <tt>Sequel.negate</tt> method, which will use ANDs if multiple entries are used:
|
353
376
|
|
354
|
-
|
377
|
+
Sequel.negate(:column1=>1, :column2=>2) # (("column1" != 1) AND ("column2" != 2))
|
355
378
|
|
356
|
-
To negate while using ORs, the
|
379
|
+
To negate while using ORs, the <tt>Sequel.~</tt> operator can be used:
|
357
380
|
|
358
|
-
|
381
|
+
Sequel.~(:column1=>1, :column2=>2) # (("column1" != 1) OR ("column2" != 2))
|
359
382
|
|
360
|
-
Note that <tt>Dataset#exclude</tt> uses ~, not +
|
383
|
+
Note again that <tt>Dataset#exclude</tt> uses ~, not +negate+:
|
361
384
|
|
362
385
|
DB[:albums].exclude(:column1=>1, :column2=>2) # SELECT * FROM "albums" WHERE (("column" != 1) OR ("column2" != 2))
|
363
386
|
|
364
387
|
=== Casts
|
365
388
|
|
366
|
-
Casting in Sequel is done with the +cast+ method, which is available on
|
389
|
+
Casting in Sequel is done with the +cast+ method, which is available on most of the Sequel-specific expression objects:
|
367
390
|
|
368
|
-
:name.cast(:text) # CAST("name" AS text)
|
369
|
-
'1'.cast(:integer) # CAST('1' AS integer)
|
370
|
-
|
391
|
+
Sequel.expr(:name).cast(:text) # CAST("name" AS text)
|
392
|
+
Sequel.expr('1').cast(:integer) # CAST('1' AS integer)
|
393
|
+
Sequel.qualify(:table, :column).cast(:date) # CAST("table"."column" AS date)
|
371
394
|
|
372
|
-
|
395
|
+
You can also use the <tt>Sequel.cast</tt> method:
|
373
396
|
|
374
|
-
Sequel
|
397
|
+
Sequel.cast(:name, :text) # CAST("name" AS text)
|
375
398
|
|
376
|
-
|
377
|
-
(:number + 1) & 5 # (("number" + 1) & 5)
|
399
|
+
=== Bitwise Mathematical Operators (& | ^ << >> ~)
|
378
400
|
|
379
|
-
|
401
|
+
Sequel allows the use of bitwise mathematical operators on Sequel::SQL::NumericExpression objects:
|
380
402
|
|
381
|
-
:number
|
403
|
+
Sequel.expr(:number) + 1 # => #<Sequel::SQL::NumericExpression ...>
|
404
|
+
(Sequel.expr(:number) + 1) & 5 # (("number" + 1) & 5)
|
382
405
|
|
383
|
-
|
406
|
+
As you can see, when you use the + operator on a symbol, you get a NumericExpression. You can turn an expression a NumericExpression using +sql_number+:
|
384
407
|
|
385
|
-
:
|
386
|
-
|
408
|
+
Sequel.expr(:number).sql_number | 5 # ("number" | 5)
|
409
|
+
Sequel.function(:func).sql_number << 7 # (func() << 7)
|
410
|
+
Sequel.cast(:name, :integer).sql_number >> 8 # (CAST("name" AS integer) >> 8)
|
387
411
|
|
388
412
|
Sequel allows you to do the cast and conversion at the same time via +cast_numeric+:
|
389
413
|
|
390
|
-
:name.cast_numeric ^ 9 # (CAST("name" AS integer) ^ 9)
|
414
|
+
Sequel.expr(:name).cast_numeric ^ 9 # (CAST("name" AS integer) ^ 9)
|
391
415
|
|
392
|
-
Note that &, |, and ~ are already defined to do AND, OR, and NOT on most
|
416
|
+
Note that &, |, and ~ are already defined to do AND, OR, and NOT on most expressions, so if you want to use the bitwise operators, you need to make sure that they are converted first:
|
393
417
|
|
394
|
-
|
395
|
-
|
418
|
+
~Sequel.expr(:name) # NOT "name"
|
419
|
+
~Sequel.expr(:name).sql_number # ~"name"
|
396
420
|
|
397
421
|
=== String Operators (||, LIKE, Regexp)
|
398
422
|
|
399
|
-
Sequel allows the use of the string concatenation operator on Sequel::SQL::StringExpression objects, which can be created using the +sql_string+ method:
|
423
|
+
Sequel allows the use of the string concatenation operator on Sequel::SQL::StringExpression objects, which can be created using the +sql_string+ method on an expression:
|
400
424
|
|
401
|
-
:name.sql_string + ' - Name' # ("name" || ' - Name')
|
425
|
+
Sequel.expr(:name).sql_string + ' - Name' # ("name" || ' - Name')
|
402
426
|
|
403
427
|
Just like for the bitwise operators, Sequel allows you do do the cast and conversion at the same time via +cast_string+:
|
404
428
|
|
405
|
-
:number.cast_string + ' - Number' # (CAST(number AS varchar(255)) || ' - Number')
|
429
|
+
Sequel.expr(:number).cast_string + ' - Number' # (CAST(number AS varchar(255)) || ' - Number')
|
406
430
|
|
407
431
|
Note that similar to the mathematical operators, you cannot switch the order the expression and have it work:
|
408
432
|
|
409
|
-
'Name - ' + :name.sql_string # raises TypeError
|
433
|
+
'Name - ' + Sequel.expr(:name).sql_string # raises TypeError
|
410
434
|
|
411
|
-
Just like for the mathematical operators, you can use
|
435
|
+
Just like for the mathematical operators, you can use <tt>Sequel.expr</tt> to wrap the object:
|
412
436
|
|
413
|
-
Sequel.
|
414
|
-
'Name - '.sql_expr + :name # ('Name - ' || "name")
|
437
|
+
Sequel.expr('Name - ') + :name # ('Name - ' || "name")
|
415
438
|
|
416
|
-
|
439
|
+
The <tt>Sequel.join</tt> method concatenates all of the elements in the array:
|
417
440
|
|
418
|
-
['Name', :name]
|
441
|
+
Sequel.join(['Name', :name]) # ('Name' || "name")
|
419
442
|
|
420
443
|
Just like ruby's <tt>String#join</tt>, you can provide an argument for a string used to join each element:
|
421
444
|
|
422
|
-
['Name', :name]
|
445
|
+
Sequel.join(['Name', :name], ' - ') # ('Name' || ' - ' || "name")
|
446
|
+
|
447
|
+
For the LIKE operator, Sequel defines the +like+ and +ilike+ methods on most Sequel-specific expression objects:
|
423
448
|
|
424
|
-
|
449
|
+
Sequel.expr(:name).like('A%') # ("name" LIKE 'A%')
|
450
|
+
Sequel.expr(:name).ilike('A%') # ("name" ILIKE 'A%')
|
425
451
|
|
426
|
-
|
427
|
-
:name.qualify.ilike('A%') # ("name" ILIKE 'A%')
|
452
|
+
You can also use the <tt>Sequel.like</tt> and <tt>Sequel.ilike</tt> methods:
|
428
453
|
|
429
|
-
|
454
|
+
Sequel.like(:name, 'A%') # ("name" LIKE 'A%')
|
455
|
+
Sequel.ilike(:name, 'A%') # ("name" ILIKE 'A%')
|
456
|
+
|
457
|
+
Note the above syntax for ilike, while Sequel's default, is specific to PostgreSQL. However, most other adapters override the behavior. For example, on MySQL, Sequel uses LIKE BINARY for +like+, and LIKE for +ilike+. If the database supports both case sensitive and case insensitive LIKE, then +like+ will use a case sensitive LIKE, and +ilike+ will use a case insensitive LIKE.
|
430
458
|
|
431
459
|
Inverting the LIKE operator works like other inversions:
|
432
460
|
|
433
|
-
|
461
|
+
~Sequel.like(:name, 'A%') # ("name" NOT LIKE 'A%')
|
434
462
|
|
435
|
-
Sequel also supports SQL regular expressions on MySQL and PostgreSQL. You can use these by passing a ruby regular expression to
|
463
|
+
Sequel also supports SQL regular expressions on MySQL and PostgreSQL. You can use these by passing a ruby regular expression to +like+ or +ilike+, or by making the regular expression a hash value:
|
436
464
|
|
437
|
-
|
438
|
-
|
465
|
+
Sequel.like(:name, /^A/) # ("name" ~ '^A')
|
466
|
+
~Sequel.ilike(:name, /^A/) # ("name" !~* '^A')
|
439
467
|
{:name=>/^A/i} # ("name" ~* '^A')
|
440
|
-
|
468
|
+
Sequel.~(:name=>/^A/) # ("name" !~ '^A')
|
441
469
|
|
442
470
|
Note that using +ilike+ with a regular expression will always make the regexp case insensitive. If you use +like+ or the hash with regexp value, it will only be case insensitive if the Regexp itself is case insensitive.
|
443
471
|
|
444
472
|
=== Order Specifications (ASC, DESC)
|
445
473
|
|
446
|
-
Sequel supports specifying ascending or descending order using the
|
474
|
+
Sequel supports specifying ascending or descending order using the asc+ and +desc+ method on most Sequel-specific expression objects:
|
475
|
+
|
476
|
+
Sequel.expr(:column).asc # "column" ASC
|
477
|
+
Sequel.expr(:column).qualify(:table).desc # "table"."column" DESC
|
447
478
|
|
448
|
-
|
449
|
-
|
479
|
+
You can also use the <tt>Sequel.asc</tt> and <tt>Sequel.desc</tt> methods:
|
480
|
+
|
481
|
+
Sequel.asc(:column) # "column" ASC
|
482
|
+
Sequel.desc(Sequel.expr(:column).qualify(:table)) # "table"."column" DESC
|
483
|
+
|
484
|
+
On some databases, you can specify null ordering:
|
485
|
+
|
486
|
+
Sequel.asc(:column, :nulls=>:first) # "column" ASC NULLS FIRST
|
487
|
+
Sequel.desc(Sequel.expr(:column).qualify(:table), :nulls=>:last) # "table"."column" DESC NULLS LAST
|
450
488
|
|
451
489
|
=== All Columns (.*)
|
452
490
|
|
453
|
-
To select all columns in a table, Sequel supports the * method on
|
491
|
+
To select all columns in a table, Sequel supports the * method on identifiers without an argument:
|
454
492
|
|
455
|
-
:table.* # "table".*
|
493
|
+
Sequel.expr(:table).* # "table".*
|
456
494
|
|
457
495
|
=== CASE statements
|
458
496
|
|
459
|
-
Sequel allows the easy production of SQL CASE statements using the
|
497
|
+
Sequel allows the easy production of SQL CASE statements using the <tt>Sequel.case</tt> method. The first argument is a hash or array of two element arrays representing the conditions, the second argument is the default value (ELSE). The keys of the hash (or first element in each array) is the WHEN condition, and the values of the hash (or second element in each array) is the THEN result. Here are some examples:
|
460
498
|
|
461
|
-
{:column=>1
|
462
|
-
[[column, 1]]
|
463
|
-
{{:column=>nil}=>1}
|
499
|
+
Sequel.case({:column=>1, 0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
|
500
|
+
Sequel.case([[column, 1]], 0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
|
501
|
+
Sequel.case({{:column=>nil}=>1}, 0) # (CASE WHEN (column IS NULL) THEN 1 ELSE 0 END)
|
464
502
|
|
465
503
|
If the hash or array has multiple arguments, multiple WHEN clauses are used:
|
466
504
|
|
467
|
-
{:c=>1, :d=>2}
|
468
|
-
[[:c, 1], [:d, 2]]
|
505
|
+
Sequel.case({:c=>1, :d=>2}, 0) # (CASE WHEN "c" THEN 1 WHEN "d" THEN 2 ELSE 0 END)
|
506
|
+
Sequel.case([[:c, 1], [:d, 2]], 0) # (CASE WHEN "c" THEN 1 WHEN "d" THEN 2 ELSE 0 END)
|
469
507
|
|
470
508
|
If you provide a 2nd argument to CASE, it goes between CASE and WHEN:
|
471
509
|
|
472
|
-
{2=>1, 3=>5}
|
510
|
+
Sequel.case({2=>1, 3=>5}, 0, :column) # (CASE column WHEN 2 THEN 1 WHEN 3 THEN 5 ELSE 0 END)
|
473
511
|
|
474
512
|
=== Subscripts/Array Access ([])
|
475
513
|
|
476
|
-
Sequel supports SQL subscripts using the +sql_subscript+ method on
|
514
|
+
Sequel supports SQL subscripts using the +sql_subscript+ method on most Sequel-specific expression objects:
|
515
|
+
|
516
|
+
Sequel.expr(:column).sql_subscript(3) # column[3]
|
517
|
+
Sequel.expr(:column).qualify(:table).sql_subscript(3) # table.column[3]
|
518
|
+
|
519
|
+
You can also use the <tt>Sequel.subscript</tt> method:
|
477
520
|
|
478
|
-
:column
|
479
|
-
:column.qualify(:table).sql_subscript(3) # table.column[3]
|
521
|
+
Sequel.subscript(:column, 3) # column[3]
|
480
522
|
|
481
523
|
Just like in SQL, you can use any expression as a subscript:
|
482
524
|
|
483
|
-
:column.
|
525
|
+
Sequel.subscript(:column, Sequel.function(:func)) # column[func()]
|
484
526
|
|
485
527
|
== Building Queries in Sequel
|
486
528
|
|
@@ -504,12 +546,12 @@ If you don't want to select from any FROM tables, use no arguments:
|
|
504
546
|
|
505
547
|
Once you have your dataset object, you build queries by chaining methods, usually with one method per clause in the query:
|
506
548
|
|
507
|
-
DB[:albums].select(:id, :name).where(
|
549
|
+
DB[:albums].select(:id, :name).where(Sequel.like(:name, 'A%')).order(:name)
|
508
550
|
# SELECT id, name FROM albums WHERE (name LIKE 'A%') ORDER BY name
|
509
551
|
|
510
552
|
Note that the order of your method chain is not usually important unless you have multiple methods that affect the same clause:
|
511
553
|
|
512
|
-
DB[:albums].order(:name).where(
|
554
|
+
DB[:albums].order(:name).where(Sequel.like(:name, 'A%')).select(:id, :name)
|
513
555
|
# SELECT id, name FROM albums WHERE (name LIKE 'A%') ORDER BY name
|
514
556
|
|
515
557
|
=== Using the Same Dataset for SELECT, INSERT, UPDATE, and DELETE
|
@@ -524,13 +566,13 @@ Also note that while the SELECT clause is displayed when you look at a dataset,
|
|
524
566
|
|
525
567
|
In general, the +insert+, +update+, and +delete+ methods use the appropriate clauses you defined on the dataset:
|
526
568
|
|
527
|
-
ds = DB[:albums].
|
569
|
+
ds = DB[:albums].where(:id=>1)
|
528
570
|
ds.all # SELECT * FROM albums WHERE (id = 1)
|
529
571
|
ds.insert(:name=>'RF') # INSERT INTO albums (name) VALUES ('RF')
|
530
572
|
ds.update(:name=>'RF') # UPDATE albums SET name = 'RF' WHERE (id = 1)
|
531
573
|
ds.delete # DELETE FROM albums WHERE (id = 1)
|
532
574
|
|
533
|
-
Note how +update+ and +delete+ used the +
|
575
|
+
Note how +update+ and +delete+ used the +where+ argument, but that +insert+ did not, because INSERT doesn't use a WHERE clause.
|
534
576
|
|
535
577
|
=== Methods Used for Each SQL Clause
|
536
578
|
|