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.
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