sequel 3.42.0 → 3.43.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/CHANGELOG +40 -0
  2. data/MIT-LICENSE +1 -1
  3. data/Rakefile +1 -1
  4. data/doc/opening_databases.rdoc +2 -2
  5. data/doc/prepared_statements.rdoc +7 -0
  6. data/doc/release_notes/3.43.0.txt +105 -0
  7. data/doc/schema_modification.rdoc +19 -0
  8. data/lib/sequel/adapters/do/mysql.rb +1 -1
  9. data/lib/sequel/adapters/jdbc.rb +13 -8
  10. data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
  11. data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
  12. data/lib/sequel/adapters/jdbc/oracle.rb +6 -0
  13. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -3
  14. data/lib/sequel/adapters/mysql.rb +1 -1
  15. data/lib/sequel/adapters/mysql2.rb +1 -1
  16. data/lib/sequel/adapters/oracle.rb +1 -1
  17. data/lib/sequel/adapters/postgres.rb +4 -2
  18. data/lib/sequel/adapters/shared/db2.rb +12 -0
  19. data/lib/sequel/adapters/shared/mssql.rb +9 -5
  20. data/lib/sequel/adapters/shared/postgres.rb +2 -0
  21. data/lib/sequel/adapters/swift/mysql.rb +1 -1
  22. data/lib/sequel/core.rb +2 -2
  23. data/lib/sequel/database.rb +0 -2
  24. data/lib/sequel/database/query.rb +20 -5
  25. data/lib/sequel/database/schema_generator.rb +5 -0
  26. data/lib/sequel/database/schema_methods.rb +5 -0
  27. data/lib/sequel/dataset.rb +0 -2
  28. data/lib/sequel/dataset/actions.rb +25 -2
  29. data/lib/sequel/dataset/misc.rb +1 -1
  30. data/lib/sequel/dataset/sql.rb +28 -6
  31. data/lib/sequel/extensions/core_refinements.rb +221 -0
  32. data/lib/sequel/extensions/date_arithmetic.rb +194 -0
  33. data/lib/sequel/extensions/meta_def.rb +30 -0
  34. data/lib/sequel/extensions/migration.rb +5 -0
  35. data/lib/sequel/extensions/null_dataset.rb +2 -0
  36. data/lib/sequel/extensions/pagination.rb +2 -0
  37. data/lib/sequel/extensions/pg_array.rb +12 -1
  38. data/lib/sequel/extensions/pg_array_ops.rb +10 -1
  39. data/lib/sequel/extensions/pg_hstore.rb +12 -1
  40. data/lib/sequel/extensions/pg_hstore_ops.rb +10 -1
  41. data/lib/sequel/extensions/pg_json.rb +18 -1
  42. data/lib/sequel/extensions/pg_range.rb +12 -1
  43. data/lib/sequel/extensions/pg_range_ops.rb +10 -1
  44. data/lib/sequel/extensions/pg_row.rb +18 -2
  45. data/lib/sequel/extensions/pg_row_ops.rb +10 -1
  46. data/lib/sequel/extensions/query.rb +2 -0
  47. data/lib/sequel/model/associations.rb +5 -13
  48. data/lib/sequel/model/base.rb +4 -6
  49. data/lib/sequel/plugins/boolean_readers.rb +4 -2
  50. data/lib/sequel/plugins/many_through_many.rb +23 -0
  51. data/lib/sequel/plugins/string_stripper.rb +53 -3
  52. data/lib/sequel/plugins/validation_class_methods.rb +5 -0
  53. data/lib/sequel/sql.rb +3 -3
  54. data/lib/sequel/version.rb +1 -1
  55. data/spec/adapters/db2_spec.rb +19 -8
  56. data/spec/adapters/mssql_spec.rb +1 -2
  57. data/spec/adapters/mysql_spec.rb +2 -2
  58. data/spec/adapters/postgres_spec.rb +29 -3
  59. data/spec/core/dataset_spec.rb +107 -0
  60. data/spec/core/expression_filters_spec.rb +5 -0
  61. data/spec/core/schema_spec.rb +14 -3
  62. data/spec/core/spec_helper.rb +2 -0
  63. data/spec/extensions/core_refinements_spec.rb +551 -0
  64. data/spec/extensions/date_arithmetic_spec.rb +150 -0
  65. data/spec/extensions/force_encoding_spec.rb +1 -1
  66. data/spec/extensions/meta_def_spec.rb +21 -0
  67. data/spec/extensions/spec_helper.rb +5 -0
  68. data/spec/extensions/string_stripper_spec.rb +44 -2
  69. data/spec/integration/associations_test.rb +2 -2
  70. data/spec/integration/plugin_test.rb +90 -0
  71. data/spec/integration/schema_test.rb +1 -1
  72. data/spec/model/association_reflection_spec.rb +4 -4
  73. data/spec/model/associations_spec.rb +2 -2
  74. data/spec/model/base_spec.rb +2 -2
  75. data/spec/model/eager_loading_spec.rb +5 -5
  76. data/spec/model/hooks_spec.rb +4 -4
  77. data/spec/model/model_spec.rb +9 -9
  78. data/spec/model/record_spec.rb +15 -18
  79. metadata +12 -5
  80. 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
- pk_index_id = metadata_dataset.from(:sysindexes).
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(:sysindexkeys___sik).
321
- join(:syscolumns___sc, :id=>:id, :colid=>:colid).
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(:information_schema__tables___t).
325
- join(:information_schema__columns___c, :table_catalog=>:table_catalog,
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 == 'tinyint(1)' ? :boolean : super
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.instance_eval(&block)
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"metaprogramming sql connection_pool exceptions dataset database timezones ast_transformer version")
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
@@ -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
- tab = table.first_source_table
188
- sch, table_name = schema_and_table(tab)
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
- sch, table_name = schema_and_table(table)
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?
@@ -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).single_value
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
- select(column).single_value
256
+ ds.single_value
234
257
  end
235
258
  end
236
259
 
@@ -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.sort_by{|k, v| k.to_s}, sql].hash
110
+ [db, opts, sql].hash
111
111
  end
112
112
 
113
113
  # The String instance method to call on identifiers before sending them to
@@ -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
- def schema_and_table(table_name)
641
- sch = db.default_schema if db
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