sequel 3.42.0 → 3.43.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|