sequel 3.37.0 → 3.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/CHANGELOG +56 -0
  2. data/README.rdoc +82 -58
  3. data/Rakefile +6 -5
  4. data/bin/sequel +1 -1
  5. data/doc/active_record.rdoc +67 -52
  6. data/doc/advanced_associations.rdoc +33 -48
  7. data/doc/association_basics.rdoc +41 -51
  8. data/doc/cheat_sheet.rdoc +21 -21
  9. data/doc/core_extensions.rdoc +374 -0
  10. data/doc/dataset_basics.rdoc +5 -5
  11. data/doc/dataset_filtering.rdoc +47 -43
  12. data/doc/mass_assignment.rdoc +1 -1
  13. data/doc/migration.rdoc +4 -5
  14. data/doc/model_hooks.rdoc +3 -3
  15. data/doc/object_model.rdoc +31 -25
  16. data/doc/opening_databases.rdoc +19 -5
  17. data/doc/prepared_statements.rdoc +2 -2
  18. data/doc/querying.rdoc +109 -52
  19. data/doc/reflection.rdoc +6 -6
  20. data/doc/release_notes/3.38.0.txt +234 -0
  21. data/doc/schema_modification.rdoc +22 -13
  22. data/doc/sharding.rdoc +8 -9
  23. data/doc/sql.rdoc +154 -112
  24. data/doc/testing.rdoc +47 -7
  25. data/doc/thread_safety.rdoc +1 -1
  26. data/doc/transactions.rdoc +1 -1
  27. data/doc/validations.rdoc +1 -1
  28. data/doc/virtual_rows.rdoc +29 -43
  29. data/lib/sequel/adapters/do/postgres.rb +1 -4
  30. data/lib/sequel/adapters/jdbc.rb +14 -3
  31. data/lib/sequel/adapters/jdbc/db2.rb +9 -0
  32. data/lib/sequel/adapters/jdbc/derby.rb +41 -4
  33. data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
  34. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
  35. data/lib/sequel/adapters/mock.rb +10 -4
  36. data/lib/sequel/adapters/postgres.rb +1 -28
  37. data/lib/sequel/adapters/shared/mssql.rb +23 -13
  38. data/lib/sequel/adapters/shared/postgres.rb +46 -0
  39. data/lib/sequel/adapters/swift.rb +21 -13
  40. data/lib/sequel/adapters/swift/mysql.rb +1 -0
  41. data/lib/sequel/adapters/swift/postgres.rb +4 -5
  42. data/lib/sequel/adapters/swift/sqlite.rb +2 -1
  43. data/lib/sequel/adapters/tinytds.rb +14 -2
  44. data/lib/sequel/adapters/utils/pg_types.rb +5 -0
  45. data/lib/sequel/core.rb +29 -17
  46. data/lib/sequel/database/query.rb +1 -1
  47. data/lib/sequel/database/schema_generator.rb +3 -0
  48. data/lib/sequel/dataset/actions.rb +5 -6
  49. data/lib/sequel/dataset/query.rb +7 -7
  50. data/lib/sequel/dataset/sql.rb +5 -18
  51. data/lib/sequel/extensions/core_extensions.rb +8 -12
  52. data/lib/sequel/extensions/pg_array.rb +59 -33
  53. data/lib/sequel/extensions/pg_array_ops.rb +32 -4
  54. data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
  55. data/lib/sequel/extensions/pg_hstore.rb +32 -17
  56. data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
  57. data/lib/sequel/extensions/pg_inet.rb +1 -2
  58. data/lib/sequel/extensions/pg_interval.rb +0 -1
  59. data/lib/sequel/extensions/pg_json.rb +41 -23
  60. data/lib/sequel/extensions/pg_range.rb +36 -11
  61. data/lib/sequel/extensions/pg_range_ops.rb +32 -4
  62. data/lib/sequel/extensions/pg_row.rb +572 -0
  63. data/lib/sequel/extensions/pg_row_ops.rb +164 -0
  64. data/lib/sequel/extensions/query.rb +3 -3
  65. data/lib/sequel/extensions/schema_dumper.rb +7 -8
  66. data/lib/sequel/extensions/select_remove.rb +1 -1
  67. data/lib/sequel/model/base.rb +1 -0
  68. data/lib/sequel/no_core_ext.rb +1 -1
  69. data/lib/sequel/plugins/pg_row.rb +121 -0
  70. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  71. data/lib/sequel/plugins/validation_helpers.rb +31 -0
  72. data/lib/sequel/sql.rb +64 -44
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/mssql_spec.rb +37 -12
  75. data/spec/adapters/mysql_spec.rb +39 -75
  76. data/spec/adapters/oracle_spec.rb +11 -11
  77. data/spec/adapters/postgres_spec.rb +414 -237
  78. data/spec/adapters/spec_helper.rb +1 -1
  79. data/spec/adapters/sqlite_spec.rb +14 -14
  80. data/spec/core/database_spec.rb +6 -6
  81. data/spec/core/dataset_spec.rb +169 -205
  82. data/spec/core/expression_filters_spec.rb +182 -295
  83. data/spec/core/object_graph_spec.rb +6 -6
  84. data/spec/core/schema_spec.rb +14 -14
  85. data/spec/core/spec_helper.rb +1 -0
  86. data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
  87. data/spec/extensions/columns_introspection_spec.rb +5 -5
  88. data/spec/extensions/hook_class_methods_spec.rb +28 -36
  89. data/spec/extensions/many_through_many_spec.rb +4 -4
  90. data/spec/extensions/pg_array_ops_spec.rb +15 -7
  91. data/spec/extensions/pg_array_spec.rb +81 -48
  92. data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
  93. data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
  94. data/spec/extensions/pg_hstore_spec.rb +66 -65
  95. data/spec/extensions/pg_inet_spec.rb +2 -4
  96. data/spec/extensions/pg_interval_spec.rb +2 -3
  97. data/spec/extensions/pg_json_spec.rb +20 -18
  98. data/spec/extensions/pg_range_ops_spec.rb +11 -4
  99. data/spec/extensions/pg_range_spec.rb +30 -7
  100. data/spec/extensions/pg_row_ops_spec.rb +48 -0
  101. data/spec/extensions/pg_row_plugin_spec.rb +45 -0
  102. data/spec/extensions/pg_row_spec.rb +323 -0
  103. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  104. data/spec/extensions/query_literals_spec.rb +11 -11
  105. data/spec/extensions/query_spec.rb +3 -3
  106. data/spec/extensions/schema_dumper_spec.rb +20 -4
  107. data/spec/extensions/schema_spec.rb +18 -41
  108. data/spec/extensions/select_remove_spec.rb +4 -4
  109. data/spec/extensions/spec_helper.rb +4 -8
  110. data/spec/extensions/to_dot_spec.rb +5 -5
  111. data/spec/extensions/validation_class_methods_spec.rb +28 -16
  112. data/spec/integration/associations_test.rb +20 -20
  113. data/spec/integration/dataset_test.rb +98 -98
  114. data/spec/integration/eager_loader_test.rb +13 -27
  115. data/spec/integration/plugin_test.rb +5 -5
  116. data/spec/integration/prepared_statement_test.rb +22 -13
  117. data/spec/integration/schema_test.rb +28 -18
  118. data/spec/integration/spec_helper.rb +1 -1
  119. data/spec/integration/timezone_test.rb +2 -2
  120. data/spec/integration/type_test.rb +15 -6
  121. data/spec/model/association_reflection_spec.rb +1 -1
  122. data/spec/model/associations_spec.rb +4 -4
  123. data/spec/model/base_spec.rb +5 -5
  124. data/spec/model/eager_loading_spec.rb +15 -15
  125. data/spec/model/model_spec.rb +32 -32
  126. data/spec/model/record_spec.rb +16 -0
  127. data/spec/model/spec_helper.rb +2 -6
  128. data/spec/model/validations_spec.rb +1 -1
  129. 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
- * :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.
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#filter</tt>:
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, :char_length.sql_function(:name)=>3..50)
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 MySQL, you must specify the type of constraint via a <tt>:type</tt> option:
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> with the bang drops the table if it exists
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(:artists) if table_exists?(:artists)
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> with a question mark only creates the table if it does
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
- create_table(:artists)
554
- primary_key :id
555
- end unless table_exists?(:artists)
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].filter{copies_sold > 500000})
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).filter(:hash=>/31337/)
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
- def_dataset_method(:plaintext_for_hash) do |hash|
123
- raise(ArgumentError, 'Invalid SHA-1 Hash') unless /\A[0-9a-f]{40}\z/.match(hash)
124
- row = self.server(hash[0...1].to_sym).first(:hash=>hash)
125
- row[:plaintext] if row
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
- Sequel.extension :server_block
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
- Sequel.extension :arbitrary_servers
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>String#lit</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'.lit) # SELECT name FROM albums
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 +qualify+ method on the column symbol with the table symbol:
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
- :column.qualify(:table) # "table"."column"
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 symbols and most Sequel-specific expression objects:
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
- :column.as(:alias) # "column" AS "alias"
175
- :column.qualify(:table).as(:alias) # "table"."column" AS "alias"
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{function{}} # SELECT function() FROM "albums"
182
- DB[:albums].select{function(col1, col2)} # SELECT function("col1", "col2") FROM "albums"
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 +sql_function+ method on the symbol that contains the function name:
188
+ You can also use the <tt>Sequel.function</tt> method on the symbol that contains the function name:
185
189
 
186
- :function.sql_function # function()
187
- :function.sql_function(:col1, :col2) # function("col1", "col2")
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
- :sum.sql_function(:column) # sum(column)
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.sql_function('DISTINCT column'.lit) # sum(DISTINCT column)
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.sql_function('*'.lit) # 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 +sql_negate+ or ~:
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
- {:column => 1}.sql_negate # ("column" != 1)
238
- [[:column, 1]].sql_negate # ("column" != 1)
239
- ~{:column => 1} # ("column" != 1)
240
- ~[[:column, 1]] # ("column" != 1)
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
- ~{:column=>[1, 2, 3]} # ("column" NOT IN (1, 2, 3))
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
- ~{:column=>DB[:albums].select(:id)} # ("column" NOT IN (SELECT "id" FROM "albums"))
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
- {:column=>nil).sql_negate # ("column" IS NOT NULL)
273
- {:column=>true).sql_negate # ("column" IS NOT TRUE)
274
- {:column=>false).sql_negate # ("column" IS NOT FALSE)
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
- ~:column # NOT "column"
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
- ~{:column=>1}
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
- :column.qualify(:table) > 1 # ("table"."column" > 1)
293
- :column.qualify(:table) < 1 # ("table"."column" < 1)
294
- :function.sql_function >= 1 # (function() >= 1)
295
- :function.sql_function(:column) <= 1 # (function("column") <= 1)
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 +identifier+ on the symbol:
308
+ If you want to use them on a symbol, you should call <tt>Sequel.expr</tt> with the symbol:
298
309
 
299
- :column.identifier > 1 # ("column" > 1)
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].filter{col1 > col2} # SELECT * FROM "albums" WHERE ("col1" > "col2")
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 symbol and most Sequel-specific expression objects:
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
- :column + 1 # "column" + 1
310
- :table__column - 1 # "table"."column" - 1
311
- :column.qualify(:table) * 1 # "table"."column" * 1
312
- :column / 1 # "column" / 1
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. However, Sequel comes with an +sql_expr+ extension that adds an +sql_expr+ method to all objects, allowing you to do:
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.extension :sql_expr
321
- 1.sql_expr / :column # (1 / "column")
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 symbols, hashes, and most Sequel-specific expression objects to handle AND and OR:
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
- {:column1=>1} | {:column2=>2} # (("column1" = 1) OR ("column2" = 2))
329
- (:function.sql_function > 1) & :column3 # ((function() > 1) AND "column3")
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
- :function.sql_function > 1 & :column3 # (function() > 1)
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
- :function.sql_function > (1 & :column3)
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 +sql_or+ method to use OR instead:
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
- {:column1=>1, :column2=>2}.sql_or # (("column1" = 1) OR ("column2" = 2))
373
+ Sequel.or(:column1=>1, :column2=>2) # (("column1" = 1) OR ("column2" = 2))
351
374
 
352
- You've already seen the +sql_negate+ method, which will use ANDs if multiple entries are used:
375
+ You've already seen the <tt>Sequel.negate</tt> method, which will use ANDs if multiple entries are used:
353
376
 
354
- {:column1=>1, :column2=>2}.sql_negate # (("column1" != 1) AND ("column2" != 2))
377
+ Sequel.negate(:column1=>1, :column2=>2) # (("column1" != 1) AND ("column2" != 2))
355
378
 
356
- To negate while using ORs, the ~ operator can be used:
379
+ To negate while using ORs, the <tt>Sequel.~</tt> operator can be used:
357
380
 
358
- ~{:column1=>1, :column2=>2} # (("column1" != 1) OR ("column2" != 2))
381
+ Sequel.~(:column1=>1, :column2=>2) # (("column1" != 1) OR ("column2" != 2))
359
382
 
360
- Note that <tt>Dataset#exclude</tt> uses ~, not +sql_negate+:
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 strings, symbols, and most of the Sequel-specific expression objects:
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
- :column.qualify(:table).cast(:date) # CAST("table"."column" AS date)
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
- === Bitwise Mathematical Operators (& | ^ << >> ~)
395
+ You can also use the <tt>Sequel.cast</tt> method:
373
396
 
374
- Sequel allows the use of bitwise mathematical operators on Sequel::SQL::NumericExpression objects:
397
+ Sequel.cast(:name, :text) # CAST("name" AS text)
375
398
 
376
- :number + 1 # => #<Sequel::SQL::NumericExpression ...>
377
- (:number + 1) & 5 # (("number" + 1) & 5)
399
+ === Bitwise Mathematical Operators (& | ^ << >> ~)
378
400
 
379
- As you can see, when you use the + operator on a symbol, you get a NumericExpression. You can turn a symbol into a NumericExpression using +sql_number+:
401
+ Sequel allows the use of bitwise mathematical operators on Sequel::SQL::NumericExpression objects:
380
402
 
381
- :number.sql_number | 5 # ("number" | 5)
403
+ Sequel.expr(:number) + 1 # => #<Sequel::SQL::NumericExpression ...>
404
+ (Sequel.expr(:number) + 1) & 5 # (("number" + 1) & 5)
382
405
 
383
- +sql_number+ also works on the many other Sequel-specific expression objects:
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
- :function.sql_function.sql_number << 7 # (function() << 7)
386
- :name.cast(:integer).sql_number >> 8 # (CAST("name" AS integer) >> 8)
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 objects, so if you want to use the bitwise operators, you need to make sure that they are converted first:
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
- ~:name # NOT "name"
395
- ~:name.sql_number # ~"name"
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 the +sql_expr+ extension to work around this:
435
+ Just like for the mathematical operators, you can use <tt>Sequel.expr</tt> to wrap the object:
412
436
 
413
- Sequel.extension :sql_expr
414
- 'Name - '.sql_expr + :name # ('Name - ' || "name")
437
+ Sequel.expr('Name - ') + :name # ('Name - ' || "name")
415
438
 
416
- Sequel also adds an <tt>Array#sql_string_join</tt> method, which concatenates all of the elements in the array:
439
+ The <tt>Sequel.join</tt> method concatenates all of the elements in the array:
417
440
 
418
- ['Name', :name].sql_string_join # ('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].sql_string_join(' - ') # ('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
- For the LIKE operator, Sequel defines the +like+ and +ilike+ methods on symbol and most Sequel-specific expression objects:
449
+ Sequel.expr(:name).like('A%') # ("name" LIKE 'A%')
450
+ Sequel.expr(:name).ilike('A%') # ("name" ILIKE 'A%')
425
451
 
426
- :name.like('A%') # ("name" LIKE 'A%')
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
- Note the above syntax, 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. Some databases only support case insensitive behavior, in which case +like+ and +ilike+ will act identically.
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
- ~:name.like('A%') # ("name" NOT LIKE 'A%')
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 the +like+ or +ilike+ method, or by making the regular expression a hash value:
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
- :name.like(/^A/) # ("name" ~ '^A')
438
- ~:name.ilike(/^A/) # ("name" !~* '^A')
465
+ Sequel.like(:name, /^A/) # ("name" ~ '^A')
466
+ ~Sequel.ilike(:name, /^A/) # ("name" !~* '^A')
439
467
  {:name=>/^A/i} # ("name" ~* '^A')
440
- ~{:name=>/^A/} # ("name" !~ '^A')
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 +asc+ and +desc+ method on symbols and most Sequel-specific expression objects:
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
- :column.asc # "column" ASC
449
- :column.qualify(:table).desc # "table"."column" DESC
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 symbols without an argument:
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 +case+ method of hashes and arrays of two element arrays. The argument to +case+ is the default value, 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:
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}.case(0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
462
- [[column, 1]].case(0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
463
- {{:column=>nil}=>1}.case(0) # (CASE WHEN (column IS NULL) THEN 1 ELSE 0 END)
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}.case(0) # (CASE WHEN "c" THEN 1 WHEN "d" THEN 2 ELSE 0 END)
468
- [[:c, 1], [:d, 2]].case(0) # (CASE WHEN "c" THEN 1 WHEN "d" THEN 2 ELSE 0 END)
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}.case(0, :column) # (CASE column WHEN 2 THEN 1 WHEN 3 THEN 5 ELSE 0 END)
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 symbols and most Sequel-specific expression objects:
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.sql_subscript(3) # column[3]
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.sql_subscript(:function.sql_function) # column[function()]
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(:name.like('A%')).order(:name)
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(:name.like('A%')).select(:id, :name)
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].filter(:id=>1)
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 +filter+ argument, but that +insert+ did not, because INSERT doesn't use a WHERE clause.
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