sequel 3.42.0 → 3.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +40 -0
- data/MIT-LICENSE +1 -1
- data/Rakefile +1 -1
- data/doc/opening_databases.rdoc +2 -2
- data/doc/prepared_statements.rdoc +7 -0
- data/doc/release_notes/3.43.0.txt +105 -0
- data/doc/schema_modification.rdoc +19 -0
- data/lib/sequel/adapters/do/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc.rb +13 -8
- data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +6 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -3
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +4 -2
- data/lib/sequel/adapters/shared/db2.rb +12 -0
- data/lib/sequel/adapters/shared/mssql.rb +9 -5
- data/lib/sequel/adapters/shared/postgres.rb +2 -0
- data/lib/sequel/adapters/swift/mysql.rb +1 -1
- data/lib/sequel/core.rb +2 -2
- data/lib/sequel/database.rb +0 -2
- data/lib/sequel/database/query.rb +20 -5
- data/lib/sequel/database/schema_generator.rb +5 -0
- data/lib/sequel/database/schema_methods.rb +5 -0
- data/lib/sequel/dataset.rb +0 -2
- data/lib/sequel/dataset/actions.rb +25 -2
- data/lib/sequel/dataset/misc.rb +1 -1
- data/lib/sequel/dataset/sql.rb +28 -6
- data/lib/sequel/extensions/core_refinements.rb +221 -0
- data/lib/sequel/extensions/date_arithmetic.rb +194 -0
- data/lib/sequel/extensions/meta_def.rb +30 -0
- data/lib/sequel/extensions/migration.rb +5 -0
- data/lib/sequel/extensions/null_dataset.rb +2 -0
- data/lib/sequel/extensions/pagination.rb +2 -0
- data/lib/sequel/extensions/pg_array.rb +12 -1
- data/lib/sequel/extensions/pg_array_ops.rb +10 -1
- data/lib/sequel/extensions/pg_hstore.rb +12 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +10 -1
- data/lib/sequel/extensions/pg_json.rb +18 -1
- data/lib/sequel/extensions/pg_range.rb +12 -1
- data/lib/sequel/extensions/pg_range_ops.rb +10 -1
- data/lib/sequel/extensions/pg_row.rb +18 -2
- data/lib/sequel/extensions/pg_row_ops.rb +10 -1
- data/lib/sequel/extensions/query.rb +2 -0
- data/lib/sequel/model/associations.rb +5 -13
- data/lib/sequel/model/base.rb +4 -6
- data/lib/sequel/plugins/boolean_readers.rb +4 -2
- data/lib/sequel/plugins/many_through_many.rb +23 -0
- data/lib/sequel/plugins/string_stripper.rb +53 -3
- data/lib/sequel/plugins/validation_class_methods.rb +5 -0
- data/lib/sequel/sql.rb +3 -3
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +19 -8
- data/spec/adapters/mssql_spec.rb +1 -2
- data/spec/adapters/mysql_spec.rb +2 -2
- data/spec/adapters/postgres_spec.rb +29 -3
- data/spec/core/dataset_spec.rb +107 -0
- data/spec/core/expression_filters_spec.rb +5 -0
- data/spec/core/schema_spec.rb +14 -3
- data/spec/core/spec_helper.rb +2 -0
- data/spec/extensions/core_refinements_spec.rb +551 -0
- data/spec/extensions/date_arithmetic_spec.rb +150 -0
- data/spec/extensions/force_encoding_spec.rb +1 -1
- data/spec/extensions/meta_def_spec.rb +21 -0
- data/spec/extensions/spec_helper.rb +5 -0
- data/spec/extensions/string_stripper_spec.rb +44 -2
- data/spec/integration/associations_test.rb +2 -2
- data/spec/integration/plugin_test.rb +90 -0
- data/spec/integration/schema_test.rb +1 -1
- data/spec/model/association_reflection_spec.rb +4 -4
- data/spec/model/associations_spec.rb +2 -2
- data/spec/model/base_spec.rb +2 -2
- data/spec/model/eager_loading_spec.rb +5 -5
- data/spec/model/hooks_spec.rb +4 -4
- data/spec/model/model_spec.rb +9 -9
- data/spec/model/record_spec.rb +15 -18
- metadata +12 -5
- data/lib/sequel/metaprogramming.rb +0 -13
@@ -314,15 +314,19 @@ module Sequel
|
|
314
314
|
m2 = input_identifier_meth(opts[:dataset])
|
315
315
|
tn = m2.call(table_name.to_s)
|
316
316
|
table_id = get{object_id(tn)}
|
317
|
-
|
317
|
+
info_sch_sch = opts[:information_schema_schema]
|
318
|
+
inf_sch_qual = lambda{|s| info_sch_sch ? Sequel.qualify(info_sch_sch, s) : Sequel.expr(s)}
|
319
|
+
sys_qual = lambda{|s| info_sch_sch ? Sequel.qualify(info_sch_sch, Sequel.qualify(Sequel.lit(''), s)) : Sequel.expr(s)}
|
320
|
+
|
321
|
+
pk_index_id = metadata_dataset.from(sys_qual.call(:sysindexes)).
|
318
322
|
where(:id=>table_id, :indid=>1..254){{(status & 2048)=>2048}}.
|
319
323
|
get(:indid)
|
320
|
-
pk_cols = metadata_dataset.from(:
|
321
|
-
join(:
|
324
|
+
pk_cols = metadata_dataset.from(sys_qual.call(:sysindexkeys).as(:sik)).
|
325
|
+
join(sys_qual.call(:syscolumns).as(:sc), :id=>:id, :colid=>:colid).
|
322
326
|
where(:sik__id=>table_id, :sik__indid=>pk_index_id).
|
323
327
|
select_order_map(:sc__name)
|
324
|
-
ds = metadata_dataset.from(:
|
325
|
-
join(:
|
328
|
+
ds = metadata_dataset.from(inf_sch_qual.call(:information_schema__tables).as(:t)).
|
329
|
+
join(inf_sch_qual.call(:information_schema__columns).as(:c), :table_catalog=>:table_catalog,
|
326
330
|
:table_schema => :table_schema, :table_name => :table_name).
|
327
331
|
select(:column_name___column, :data_type___db_type, :character_maximum_length___max_chars, :column_default___default, :is_nullable___allow_null, :numeric_precision___column_size, :numeric_scale___scale).
|
328
332
|
filter(:c__table_name=>tn)
|
@@ -429,6 +429,8 @@ module Sequel
|
|
429
429
|
pk = SQL::Identifier.new(primary_key(table))
|
430
430
|
db = self
|
431
431
|
seq_ds = db.from(LiteralString.new(seq))
|
432
|
+
s, t = schema_and_table(table)
|
433
|
+
table = Sequel.qualify(s, t) if s
|
432
434
|
get{setval(seq, db[table].select{coalesce(max(pk)+seq_ds.select{:increment_by}, seq_ds.select(:min_value))}, false)}
|
433
435
|
end
|
434
436
|
|
@@ -19,7 +19,7 @@ module Sequel
|
|
19
19
|
|
20
20
|
# Consider tinyint(1) columns as boolean.
|
21
21
|
def schema_column_type(db_type)
|
22
|
-
db_type
|
22
|
+
db_type =~ /\Atinyint\(1\)/ ? :boolean : super
|
23
23
|
end
|
24
24
|
|
25
25
|
# Apply the connectiong setting SQLs for every new connection.
|
data/lib/sequel/core.rb
CHANGED
@@ -390,7 +390,7 @@ module Sequel
|
|
390
390
|
vr = SQL::VirtualRow.new
|
391
391
|
case block.arity
|
392
392
|
when -1, 0
|
393
|
-
vr.
|
393
|
+
vr.instance_exec(&block)
|
394
394
|
else
|
395
395
|
block.call(vr)
|
396
396
|
end
|
@@ -422,7 +422,7 @@ module Sequel
|
|
422
422
|
|
423
423
|
private_class_method :adapter_method, :def_adapter_method
|
424
424
|
|
425
|
-
require(%w"
|
425
|
+
require(%w"sql connection_pool exceptions dataset database timezones ast_transformer version")
|
426
426
|
if !defined?(::SEQUEL_NO_CORE_EXTENSIONS) && !ENV.has_key?('SEQUEL_NO_CORE_EXTENSIONS')
|
427
427
|
extension(:core_extensions)
|
428
428
|
end
|
data/lib/sequel/database.rb
CHANGED
@@ -13,8 +13,6 @@ module Sequel
|
|
13
13
|
# The Database class is meant to be subclassed by database adapters in order
|
14
14
|
# to provide the functionality needed for executing queries.
|
15
15
|
class Database
|
16
|
-
extend Metaprogramming
|
17
|
-
include Metaprogramming
|
18
16
|
end
|
19
17
|
|
20
18
|
require(%w"connecting dataset dataset_defaults logging misc query schema_generator schema_methods", 'database')
|
@@ -180,19 +180,34 @@ module Sequel
|
|
180
180
|
raise(Error, 'schema parsing is not implemented on this database') unless respond_to?(:schema_parse_table, true)
|
181
181
|
|
182
182
|
opts = opts.dup
|
183
|
-
if table.is_a?(Dataset)
|
183
|
+
tab = if table.is_a?(Dataset)
|
184
184
|
o = table.opts
|
185
185
|
from = o[:from]
|
186
186
|
raise(Error, "can only parse the schema for a dataset with a single from table") unless from && from.length == 1 && !o.include?(:join) && !o.include?(:sql)
|
187
|
-
|
188
|
-
|
187
|
+
table.first_source_table
|
188
|
+
else
|
189
|
+
table
|
190
|
+
end
|
191
|
+
|
192
|
+
qualifiers = split_qualifiers(tab)
|
193
|
+
table_name = qualifiers.pop
|
194
|
+
sch = qualifiers.pop
|
195
|
+
information_schema_schema = case qualifiers.length
|
196
|
+
when 1
|
197
|
+
Sequel.identifier(*qualifiers)
|
198
|
+
when 2
|
199
|
+
Sequel.qualify(*qualifiers)
|
200
|
+
end
|
201
|
+
|
202
|
+
if table.is_a?(Dataset)
|
189
203
|
quoted_name = table.literal(tab)
|
190
204
|
opts[:dataset] = table
|
191
205
|
else
|
192
|
-
|
193
|
-
quoted_name = quote_schema_table(table)
|
206
|
+
quoted_name = schema_utility_dataset.literal(table)
|
194
207
|
end
|
208
|
+
|
195
209
|
opts[:schema] = sch if sch && !opts.include?(:schema)
|
210
|
+
opts[:information_schema_schema] = information_schema_schema if information_schema_schema && !opts.include?(:information_schema_schema)
|
196
211
|
|
197
212
|
Sequel.synchronize{@schemas.delete(quoted_name)} if opts[:reload]
|
198
213
|
if v = Sequel.synchronize{@schemas[quoted_name]}
|
@@ -199,6 +199,11 @@ module Sequel
|
|
199
199
|
def method_missing(type, name = nil, opts = {})
|
200
200
|
name ? column(name, type, opts) : super
|
201
201
|
end
|
202
|
+
|
203
|
+
# This object responds to all methods.
|
204
|
+
def respond_to_missing?(meth, include_private)
|
205
|
+
true
|
206
|
+
end
|
202
207
|
|
203
208
|
# Adds an autoincrementing primary key column or a primary key constraint to the DDL.
|
204
209
|
# To create a constraint, the first argument should be an array of column symbols
|
@@ -715,6 +715,11 @@ module Sequel
|
|
715
715
|
@schema_utility_dataset ||= dataset
|
716
716
|
end
|
717
717
|
|
718
|
+
# Split the schema information from the table
|
719
|
+
def split_qualifiers(table_name)
|
720
|
+
schema_utility_dataset.split_qualifiers(table_name)
|
721
|
+
end
|
722
|
+
|
718
723
|
# Whether the database supports combining multiple alter table
|
719
724
|
# operations into a single query, false by default.
|
720
725
|
def supports_combining_alter_table_ops?
|
data/lib/sequel/dataset.rb
CHANGED
@@ -23,8 +23,6 @@ module Sequel
|
|
23
23
|
#
|
24
24
|
# For more information, see the {"Dataset Basics" guide}[link:files/doc/dataset_basics_rdoc.html].
|
25
25
|
class Dataset
|
26
|
-
extend Metaprogramming
|
27
|
-
include Metaprogramming
|
28
26
|
include Enumerable
|
29
27
|
include SQL::AliasMethods
|
30
28
|
include SQL::BooleanMethods
|
@@ -225,12 +225,35 @@ module Sequel
|
|
225
225
|
#
|
226
226
|
# ds.get{sum(id)} # SELECT sum(id) FROM table LIMIT 1
|
227
227
|
# # => 6
|
228
|
+
#
|
229
|
+
# You can pass an array of arguments to return multiple arguments,
|
230
|
+
# but you must make sure each element in the array has an alias that
|
231
|
+
# Sequel can determine:
|
232
|
+
#
|
233
|
+
# DB[:table].get([:id, :name]) # SELECT id, name FROM table LIMIT 1
|
234
|
+
# # => [3, 'foo']
|
235
|
+
#
|
236
|
+
# DB[:table].get{[sum(id).as(sum), name]} # SELECT sum(id) AS sum, name FROM table LIMIT 1
|
237
|
+
# # => [6, 'foo']
|
228
238
|
def get(column=(no_arg=true; nil), &block)
|
239
|
+
ds = naked
|
229
240
|
if block
|
230
241
|
raise(Error, ARG_BLOCK_ERROR_MSG) unless no_arg
|
231
|
-
select(&block)
|
242
|
+
ds = ds.select(&block)
|
243
|
+
column = ds.opts[:select]
|
244
|
+
column = nil if column.is_a?(Array) && column.length < 2
|
245
|
+
else
|
246
|
+
ds = if column.is_a?(Array)
|
247
|
+
ds.select(*column)
|
248
|
+
else
|
249
|
+
ds.select(column)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
if column.is_a?(Array)
|
254
|
+
ds.single_record.values_at(*column.map{|c| hash_key_symbol(c)})
|
232
255
|
else
|
233
|
-
|
256
|
+
ds.single_value
|
234
257
|
end
|
235
258
|
end
|
236
259
|
|
data/lib/sequel/dataset/misc.rb
CHANGED
@@ -107,7 +107,7 @@ module Sequel
|
|
107
107
|
# Define a hash value such that datasets with the same DB, opts, and SQL
|
108
108
|
# will have the same hash value
|
109
109
|
def hash
|
110
|
-
[db, opts
|
110
|
+
[db, opts, sql].hash
|
111
111
|
end
|
112
112
|
|
113
113
|
# The String instance method to call on identifiers before sending them to
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -636,24 +636,46 @@ module Sequel
|
|
636
636
|
sql << QUOTE << name.to_s.gsub(QUOTE_RE, DOUBLE_QUOTE) << QUOTE
|
637
637
|
end
|
638
638
|
|
639
|
-
# Split the schema information from the table
|
640
|
-
|
641
|
-
|
639
|
+
# Split the schema information from the table, returning two strings,
|
640
|
+
# one for the schema and one for the table. The returned schema may
|
641
|
+
# be nil, but the table will always have a string value.
|
642
|
+
#
|
643
|
+
# Note that this function does not handle tables with more than one
|
644
|
+
# level of qualification (e.g. database.schema.table on Microsoft
|
645
|
+
# SQL Server).
|
646
|
+
def schema_and_table(table_name, sch=(db.default_schema if db))
|
647
|
+
sch = sch.to_s if sch
|
642
648
|
case table_name
|
643
649
|
when Symbol
|
644
650
|
s, t, a = split_symbol(table_name)
|
645
651
|
[s||sch, t]
|
646
652
|
when SQL::QualifiedIdentifier
|
647
|
-
[table_name.table, table_name.column]
|
653
|
+
[table_name.table.to_s, table_name.column.to_s]
|
648
654
|
when SQL::Identifier
|
649
|
-
[sch, table_name.value]
|
655
|
+
[sch, table_name.value.to_s]
|
650
656
|
when String
|
651
|
-
[sch, table_name]
|
657
|
+
[sch, table_name.to_s]
|
652
658
|
else
|
653
659
|
raise Error, 'table_name should be a Symbol, SQL::QualifiedIdentifier, SQL::Identifier, or String'
|
654
660
|
end
|
655
661
|
end
|
656
662
|
|
663
|
+
# Splits table_name into an array of strings.
|
664
|
+
#
|
665
|
+
# ds.split_qualifiers(:s) # ['s']
|
666
|
+
# ds.split_qualifiers(:t__s) # ['t', 's']
|
667
|
+
# ds.split_qualifiers(Sequel.qualify(:d, :t__s)) # ['d', 't', 's']
|
668
|
+
# ds.split_qualifiers(Sequel.qualify(:h__d, :t__s)) # ['h', 'd', 't', 's']
|
669
|
+
def split_qualifiers(table_name, *args)
|
670
|
+
case table_name
|
671
|
+
when SQL::QualifiedIdentifier
|
672
|
+
split_qualifiers(table_name.table, nil) + split_qualifiers(table_name.column, nil)
|
673
|
+
else
|
674
|
+
sch, table = schema_and_table(table_name, *args)
|
675
|
+
sch ? [sch, table] : [table]
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
657
679
|
# SQL fragment for specifying subscripts (SQL array accesses)
|
658
680
|
def subscript_sql_append(sql, s)
|
659
681
|
literal_append(sql, s.f)
|
@@ -0,0 +1,221 @@
|
|
1
|
+
# These are refinements to core classes that allow the Sequel
|
2
|
+
# DSL to be used without modifying the core classes directly.
|
3
|
+
# After loading the extension via:
|
4
|
+
#
|
5
|
+
# Sequel.extension :core_refinements
|
6
|
+
#
|
7
|
+
# you can enable the refinements for particular files:
|
8
|
+
#
|
9
|
+
# using Sequel::CoreRefinements
|
10
|
+
|
11
|
+
raise(Sequel::Error, "Refinements require ruby 2.0.0 or greater") unless RUBY_VERSION >= '2.0.0'
|
12
|
+
|
13
|
+
module Sequel::CoreRefinements
|
14
|
+
refine Array do
|
15
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this array, not matching all of the
|
16
|
+
# conditions.
|
17
|
+
#
|
18
|
+
# ~[[:a, true]] # SQL: a IS NOT TRUE
|
19
|
+
# ~[[:a, 1], [:b, [2, 3]]] # SQL: a != 1 OR b NOT IN (2, 3)
|
20
|
+
def ~
|
21
|
+
Sequel.~(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return a <tt>Sequel::SQL::CaseExpression</tt> with this array as the conditions and the given
|
25
|
+
# default value and expression.
|
26
|
+
#
|
27
|
+
# [[{:a=>[2,3]}, 1]].case(0) # SQL: CASE WHEN a IN (2, 3) THEN 1 ELSE 0 END
|
28
|
+
# [[:a, 1], [:b, 2]].case(:d, :c) # SQL: CASE c WHEN a THEN 1 WHEN b THEN 2 ELSE d END
|
29
|
+
def case(*args)
|
30
|
+
::Sequel::SQL::CaseExpression.new(self, *args)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return a <tt>Sequel::SQL::ValueList</tt> created from this array. Used if this array contains
|
34
|
+
# all two element arrays and you want it treated as an SQL value list (IN predicate)
|
35
|
+
# instead of as a conditions specifier (similar to a hash). This is not necessary if you are using
|
36
|
+
# this array as a value in a filter, but may be necessary if you are using it as a
|
37
|
+
# value with placeholder SQL:
|
38
|
+
#
|
39
|
+
# DB[:a].filter([:a, :b]=>[[1, 2], [3, 4]]) # SQL: (a, b) IN ((1, 2), (3, 4))
|
40
|
+
# DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]]) # SQL: (a, b) IN ((1 = 2) AND (3 = 4))
|
41
|
+
# DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]].sql_value_list) # SQL: (a, b) IN ((1, 2), (3, 4))
|
42
|
+
def sql_value_list
|
43
|
+
::Sequel::SQL::ValueList.new(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this array, matching all of the
|
47
|
+
# conditions. Rarely do you need to call this explicitly, as Sequel generally
|
48
|
+
# assumes that arrays of two element arrays specify this type of condition. One case where
|
49
|
+
# it can be necessary to use this is if you are using the object as a value in a filter hash
|
50
|
+
# and want to use the = operator instead of the IN operator (which is used by default for
|
51
|
+
# arrays of two element arrays).
|
52
|
+
#
|
53
|
+
# [[:a, true]].sql_expr # SQL: a IS TRUE
|
54
|
+
# [[:a, 1], [:b, [2, 3]]].sql_expr # SQL: a = 1 AND b IN (2, 3)
|
55
|
+
def sql_expr
|
56
|
+
Sequel.expr(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this array, matching none
|
60
|
+
# of the conditions.
|
61
|
+
#
|
62
|
+
# [[:a, true]].sql_negate # SQL: a IS NOT TRUE
|
63
|
+
# [[:a, 1], [:b, [2, 3]]].sql_negate # SQL: a != 1 AND b NOT IN (2, 3)
|
64
|
+
def sql_negate
|
65
|
+
Sequel.negate(self)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this array, matching any of the
|
69
|
+
# conditions.
|
70
|
+
#
|
71
|
+
# [[:a, true]].sql_or # SQL: a IS TRUE
|
72
|
+
# [[:a, 1], [:b, [2, 3]]].sql_or # SQL: a = 1 OR b IN (2, 3)
|
73
|
+
def sql_or
|
74
|
+
Sequel.or(self)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return a <tt>Sequel::SQL::StringExpression</tt> representing an SQL string made up of the
|
78
|
+
# concatenation of this array's elements. If an argument is passed
|
79
|
+
# it is used in between each element of the array in the SQL
|
80
|
+
# concatenation.
|
81
|
+
#
|
82
|
+
# [:a].sql_string_join # SQL: a
|
83
|
+
# [:a, :b].sql_string_join # SQL: a || b
|
84
|
+
# [:a, 'b'].sql_string_join # SQL: a || 'b'
|
85
|
+
# ['a', :b].sql_string_join(' ') # SQL: 'a' || ' ' || b
|
86
|
+
def sql_string_join(joiner=nil)
|
87
|
+
Sequel.join(self, joiner)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
refine Hash do
|
92
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this hash, matching
|
93
|
+
# all of the conditions in this hash and the condition specified by
|
94
|
+
# the given argument.
|
95
|
+
#
|
96
|
+
# {:a=>1} & :b # SQL: a = 1 AND b
|
97
|
+
# {:a=>true} & ~:b # SQL: a IS TRUE AND NOT b
|
98
|
+
def &(ce)
|
99
|
+
::Sequel::SQL::BooleanExpression.new(:AND, self, ce)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this hash, matching
|
103
|
+
# all of the conditions in this hash or the condition specified by
|
104
|
+
# the given argument.
|
105
|
+
#
|
106
|
+
# {:a=>1} | :b # SQL: a = 1 OR b
|
107
|
+
# {:a=>true} | ~:b # SQL: a IS TRUE OR NOT b
|
108
|
+
def |(ce)
|
109
|
+
::Sequel::SQL::BooleanExpression.new(:OR, self, ce)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this hash, not matching all of the
|
113
|
+
# conditions.
|
114
|
+
#
|
115
|
+
# ~{:a=>true} # SQL: a IS NOT TRUE
|
116
|
+
# ~{:a=>1, :b=>[2, 3]} # SQL: a != 1 OR b NOT IN (2, 3)
|
117
|
+
def ~
|
118
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self, :OR, true)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Return a <tt>Sequel::SQL::CaseExpression</tt> with this hash as the conditions and the given
|
122
|
+
# default value. Note that the order of the conditions will be arbitrary on ruby 1.8, so all
|
123
|
+
# conditions should be orthogonal.
|
124
|
+
#
|
125
|
+
# {{:a=>[2,3]}=>1}.case(0) # SQL: CASE WHEN a IN (2, 3) THEN 1 ELSE 0 END
|
126
|
+
# {:a=>1, :b=>2}.case(:d, :c) # SQL: CASE c WHEN a THEN 1 WHEN b THEN 2 ELSE d END
|
127
|
+
# # or: CASE c WHEN b THEN 2 WHEN a THEN 1 ELSE d END
|
128
|
+
def case(*args)
|
129
|
+
::Sequel::SQL::CaseExpression.new(to_a, *args)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this hash, matching all of the
|
133
|
+
# conditions. Rarely do you need to call this explicitly, as Sequel generally
|
134
|
+
# assumes that hashes specify this type of condition.
|
135
|
+
#
|
136
|
+
# {:a=>true}.sql_expr # SQL: a IS TRUE
|
137
|
+
# {:a=>1, :b=>[2, 3]}.sql_expr # SQL: a = 1 AND b IN (2, 3)
|
138
|
+
def sql_expr
|
139
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this hash, matching none
|
143
|
+
# of the conditions.
|
144
|
+
#
|
145
|
+
# {:a=>true}.sql_negate # SQL: a IS NOT TRUE
|
146
|
+
# {:a=>1, :b=>[2, 3]}.sql_negate # SQL: a != 1 AND b NOT IN (2, 3)
|
147
|
+
def sql_negate
|
148
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self, :AND, true)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this hash, matching any of the
|
152
|
+
# conditions.
|
153
|
+
#
|
154
|
+
# {:a=>true}.sql_or # SQL: a IS TRUE
|
155
|
+
# {:a=>1, :b=>[2, 3]}.sql_or # SQL: a = 1 OR b IN (2, 3)
|
156
|
+
def sql_or
|
157
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self, :OR)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
refine String do
|
162
|
+
include Sequel::SQL::AliasMethods
|
163
|
+
include Sequel::SQL::CastMethods
|
164
|
+
|
165
|
+
# Converts a string into a <tt>Sequel::LiteralString</tt>, in order to override string
|
166
|
+
# literalization, e.g.:
|
167
|
+
#
|
168
|
+
# DB[:items].filter(:abc => 'def').sql #=>
|
169
|
+
# "SELECT * FROM items WHERE (abc = 'def')"
|
170
|
+
#
|
171
|
+
# DB[:items].filter(:abc => 'def'.lit).sql #=>
|
172
|
+
# "SELECT * FROM items WHERE (abc = def)"
|
173
|
+
#
|
174
|
+
# You can also provide arguments, to create a <tt>Sequel::SQL::PlaceholderLiteralString</tt>:
|
175
|
+
#
|
176
|
+
# DB[:items].select{|o| o.count('DISTINCT ?'.lit(:a))}.sql #=>
|
177
|
+
# "SELECT count(DISTINCT a) FROM items"
|
178
|
+
def lit(*args)
|
179
|
+
args.empty? ? Sequel::LiteralString.new(self) : Sequel::SQL::PlaceholderLiteralString.new(self, args)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns a <tt>Sequel::SQL::Blob</tt> that holds the same data as this string. Blobs provide proper
|
183
|
+
# escaping of binary data.
|
184
|
+
def to_sequel_blob
|
185
|
+
::Sequel::SQL::Blob.new(self)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
refine Symbol do
|
190
|
+
include Sequel::SQL::AliasMethods
|
191
|
+
include Sequel::SQL::CastMethods
|
192
|
+
include Sequel::SQL::OrderMethods
|
193
|
+
include Sequel::SQL::BooleanMethods
|
194
|
+
include Sequel::SQL::NumericMethods
|
195
|
+
include Sequel::SQL::QualifyingMethods
|
196
|
+
include Sequel::SQL::StringMethods
|
197
|
+
include Sequel::SQL::SubscriptMethods
|
198
|
+
include Sequel::SQL::ComplexExpressionMethods
|
199
|
+
|
200
|
+
# Returns receiver wrapped in an <tt>Sequel::SQL::Identifier</tt>. Usually used to
|
201
|
+
# prevent splitting the symbol.
|
202
|
+
#
|
203
|
+
# :a__b # SQL: "a"."b"
|
204
|
+
# :a__b.identifier # SQL: "a__b"
|
205
|
+
def identifier
|
206
|
+
Sequel::SQL::Identifier.new(self)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Returns a <tt>Sequel::SQL::Function</tt> with this as the function name,
|
210
|
+
# and the given arguments. This is aliased as <tt>Symbol#[]</tt> if the RUBY_VERSION
|
211
|
+
# is less than 1.9.0. Ruby 1.9 defines <tt>Symbol#[]</tt>, and Sequel
|
212
|
+
# doesn't override methods defined by ruby itself.
|
213
|
+
#
|
214
|
+
# :now.sql_function # SQL: now()
|
215
|
+
# :sum.sql_function(:a) # SQL: sum(a)
|
216
|
+
# :concat.sql_function(:a, :b) # SQL: concat(a, b)
|
217
|
+
def sql_function(*args)
|
218
|
+
Sequel::SQL::Function.new(self, *args)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|