sequel 3.12.1 → 3.13.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +42 -0
- data/README.rdoc +137 -118
- data/Rakefile +21 -66
- data/doc/active_record.rdoc +9 -9
- data/doc/advanced_associations.rdoc +59 -188
- data/doc/association_basics.rdoc +15 -2
- data/doc/cheat_sheet.rdoc +38 -33
- data/doc/dataset_filtering.rdoc +16 -7
- data/doc/prepared_statements.rdoc +7 -7
- data/doc/querying.rdoc +5 -4
- data/doc/release_notes/3.13.0.txt +210 -0
- data/doc/sharding.rdoc +1 -1
- data/doc/sql.rdoc +5 -5
- data/doc/validations.rdoc +11 -11
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/do.rb +3 -3
- data/lib/sequel/adapters/firebird.rb +3 -3
- data/lib/sequel/adapters/jdbc/h2.rb +39 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +3 -3
- data/lib/sequel/adapters/mysql.rb +7 -4
- data/lib/sequel/adapters/oracle.rb +3 -3
- data/lib/sequel/adapters/shared/mssql.rb +10 -1
- data/lib/sequel/adapters/shared/mysql.rb +63 -0
- data/lib/sequel/adapters/shared/postgres.rb +61 -3
- data/lib/sequel/adapters/sqlite.rb +105 -18
- data/lib/sequel/connection_pool.rb +31 -30
- data/lib/sequel/core.rb +58 -58
- data/lib/sequel/core_sql.rb +52 -43
- data/lib/sequel/database/misc.rb +11 -0
- data/lib/sequel/database/query.rb +55 -17
- data/lib/sequel/dataset/actions.rb +2 -1
- data/lib/sequel/dataset/query.rb +2 -3
- data/lib/sequel/dataset/sql.rb +24 -11
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/metaprogramming.rb +4 -0
- data/lib/sequel/model.rb +37 -19
- data/lib/sequel/model/associations.rb +33 -25
- data/lib/sequel/model/base.rb +2 -2
- data/lib/sequel/model/plugins.rb +7 -2
- data/lib/sequel/plugins/active_model.rb +1 -1
- data/lib/sequel/plugins/association_pks.rb +2 -2
- data/lib/sequel/plugins/association_proxies.rb +1 -1
- data/lib/sequel/plugins/boolean_readers.rb +2 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +10 -2
- data/lib/sequel/plugins/identity_map.rb +3 -3
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +212 -0
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/list.rb +174 -0
- data/lib/sequel/plugins/many_through_many.rb +2 -2
- data/lib/sequel/plugins/rcte_tree.rb +6 -7
- data/lib/sequel/plugins/tree.rb +118 -0
- data/lib/sequel/plugins/xml_serializer.rb +321 -0
- data/lib/sequel/sql.rb +315 -206
- data/lib/sequel/timezones.rb +40 -17
- data/lib/sequel/version.rb +8 -2
- data/spec/adapters/firebird_spec.rb +2 -2
- data/spec/adapters/informix_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +2 -2
- data/spec/adapters/mysql_spec.rb +2 -2
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/adapters/postgres_spec.rb +36 -6
- data/spec/adapters/spec_helper.rb +2 -2
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/core/connection_pool_spec.rb +3 -3
- data/spec/core/core_sql_spec.rb +31 -13
- data/spec/core/database_spec.rb +39 -2
- data/spec/core/dataset_spec.rb +24 -12
- data/spec/core/expression_filters_spec.rb +5 -1
- data/spec/core/object_graph_spec.rb +1 -1
- data/spec/core/schema_generator_spec.rb +1 -1
- data/spec/core/schema_spec.rb +1 -1
- data/spec/core/spec_helper.rb +1 -1
- data/spec/core/version_spec.rb +1 -1
- data/spec/extensions/active_model_spec.rb +82 -67
- data/spec/extensions/association_dependencies_spec.rb +1 -1
- data/spec/extensions/association_pks_spec.rb +1 -1
- data/spec/extensions/association_proxies_spec.rb +1 -1
- data/spec/extensions/blank_spec.rb +1 -1
- data/spec/extensions/boolean_readers_spec.rb +1 -1
- data/spec/extensions/caching_spec.rb +1 -1
- data/spec/extensions/class_table_inheritance_spec.rb +3 -2
- data/spec/extensions/composition_spec.rb +2 -5
- data/spec/extensions/force_encoding_spec.rb +3 -1
- data/spec/extensions/hook_class_methods_spec.rb +1 -1
- data/spec/extensions/identity_map_spec.rb +1 -1
- data/spec/extensions/inflector_spec.rb +1 -1
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/instance_hooks_spec.rb +1 -1
- data/spec/extensions/json_serializer_spec.rb +154 -0
- data/spec/extensions/lazy_attributes_spec.rb +1 -2
- data/spec/extensions/list_spec.rb +251 -0
- data/spec/extensions/looser_typecasting_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +3 -3
- data/spec/extensions/migration_spec.rb +1 -1
- data/spec/extensions/named_timezones_spec.rb +5 -6
- data/spec/extensions/nested_attributes_spec.rb +1 -1
- data/spec/extensions/optimistic_locking_spec.rb +1 -1
- data/spec/extensions/pagination_spec.rb +1 -1
- data/spec/extensions/pretty_table_spec.rb +1 -1
- data/spec/extensions/query_spec.rb +1 -1
- data/spec/extensions/rcte_tree_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +3 -2
- data/spec/extensions/schema_spec.rb +1 -1
- data/spec/extensions/serialization_spec.rb +6 -2
- data/spec/extensions/sharding_spec.rb +1 -1
- data/spec/extensions/single_table_inheritance_spec.rb +1 -1
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +7 -3
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/string_date_time_spec.rb +1 -1
- data/spec/extensions/string_stripper_spec.rb +1 -1
- data/spec/extensions/subclasses_spec.rb +1 -1
- data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
- data/spec/extensions/thread_local_timezones_spec.rb +1 -1
- data/spec/extensions/timestamps_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/tree_spec.rb +119 -0
- data/spec/extensions/typecast_on_load_spec.rb +1 -1
- data/spec/extensions/update_primary_key_spec.rb +1 -1
- data/spec/extensions/validation_class_methods_spec.rb +1 -1
- data/spec/extensions/validation_helpers_spec.rb +1 -1
- data/spec/extensions/xml_serializer_spec.rb +142 -0
- data/spec/integration/associations_test.rb +1 -1
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +29 -14
- data/spec/integration/eager_loader_test.rb +1 -1
- data/spec/integration/migrator_test.rb +1 -1
- data/spec/integration/model_test.rb +1 -1
- data/spec/integration/plugin_test.rb +316 -1
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +8 -8
- data/spec/integration/spec_helper.rb +1 -1
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +35 -20
- data/spec/integration/type_test.rb +1 -1
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +49 -34
- data/spec/model/base_spec.rb +1 -1
- data/spec/model/dataset_methods_spec.rb +4 -4
- data/spec/model/eager_loading_spec.rb +1 -1
- data/spec/model/hooks_spec.rb +1 -1
- data/spec/model/inflector_spec.rb +1 -1
- data/spec/model/model_spec.rb +7 -1
- data/spec/model/plugins_spec.rb +1 -1
- data/spec/model/record_spec.rb +1 -3
- data/spec/model/spec_helper.rb +2 -2
- data/spec/model/validations_spec.rb +1 -1
- metadata +29 -5
data/lib/sequel/sql.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Sequel
|
2
2
|
if RUBY_VERSION < '1.9.0'
|
3
|
-
# If on Ruby 1.8, create a Sequel::BasicObject class that is similar to the
|
4
|
-
# the Ruby 1.9 BasicObject class. This is used in a few places where proxy
|
3
|
+
# If on Ruby 1.8, create a <tt>Sequel::BasicObject</tt> class that is similar to the
|
4
|
+
# the Ruby 1.9 +BasicObject+ class. This is used in a few places where proxy
|
5
5
|
# objects are needed that respond to any method call.
|
6
6
|
class BasicObject
|
7
7
|
# The instance methods to not remove from the class when removing
|
@@ -10,26 +10,26 @@ module Sequel
|
|
10
10
|
|
11
11
|
# Remove all but the most basic instance methods from the class. A separate
|
12
12
|
# method so that it can be called again if necessary if you load libraries
|
13
|
-
# after Sequel that add instance methods to Object
|
13
|
+
# after Sequel that add instance methods to +Object+.
|
14
14
|
def self.remove_methods!
|
15
15
|
((private_instance_methods + instance_methods) - KEEP_METHODS).each{|m| undef_method(m)}
|
16
16
|
end
|
17
17
|
remove_methods!
|
18
18
|
end
|
19
19
|
else
|
20
|
-
# If on 1.9, create a Sequel::BasicObject class that is just like the
|
21
|
-
# default BasicObject class, except that missing constants are resolved in
|
22
|
-
# Object
|
20
|
+
# If on 1.9, create a <tt>Sequel::BasicObject</tt> class that is just like the
|
21
|
+
# default +BasicObject+ class, except that missing constants are resolved in
|
22
|
+
# +Object+. This allows the virtual row support to work with classes
|
23
23
|
# without prefixing them with ::, such as:
|
24
24
|
#
|
25
25
|
# DB[:bonds].filter{maturity_date > Time.now}
|
26
26
|
class BasicObject < ::BasicObject
|
27
|
-
# Lookup missing constants in
|
27
|
+
# Lookup missing constants in <tt>::Object</tt>
|
28
28
|
def self.const_missing(name)
|
29
29
|
::Object.const_get(name)
|
30
30
|
end
|
31
31
|
|
32
|
-
# No-op method on ruby 1.9, which has a real BasicObject class.
|
32
|
+
# No-op method on ruby 1.9, which has a real +BasicObject+ class.
|
33
33
|
def self.remove_methods!
|
34
34
|
end
|
35
35
|
end
|
@@ -45,17 +45,22 @@ module Sequel
|
|
45
45
|
|
46
46
|
### Parent Classes ###
|
47
47
|
|
48
|
-
# Classes/Modules aren't
|
48
|
+
# Classes/Modules aren't in alphabetical order due to the fact that
|
49
49
|
# some reference constants defined in others at load time.
|
50
50
|
|
51
|
-
# Base class for all SQL
|
51
|
+
# Base class for all SQL expression objects.
|
52
52
|
class Expression
|
53
|
-
#
|
53
|
+
# Expression objects are assumed to be value objects, where their
|
54
|
+
# attribute values can't change after assignment. In order to make
|
55
|
+
# it easy to define equality and hash methods, subclass
|
56
|
+
# instances assume that the only values that affect the results of
|
57
|
+
# such methods are the values of the object's attributes.
|
54
58
|
def self.attr_reader(*args)
|
55
59
|
super
|
56
60
|
comparison_attrs.concat args
|
57
61
|
end
|
58
62
|
|
63
|
+
# All attributes used for equality and hash methods.
|
59
64
|
def self.comparison_attrs
|
60
65
|
@comparison_attrs ||= self == Expression ? [] : superclass.comparison_attrs.clone
|
61
66
|
end
|
@@ -68,7 +73,7 @@ module Sequel
|
|
68
73
|
end
|
69
74
|
private_class_method :to_s_method
|
70
75
|
|
71
|
-
# Alias of eql
|
76
|
+
# Alias of <tt>eql?</tt>
|
72
77
|
def ==(other)
|
73
78
|
eql?(other)
|
74
79
|
end
|
@@ -76,7 +81,7 @@ module Sequel
|
|
76
81
|
# Returns true if the receiver is the same expression as the
|
77
82
|
# the +other+ expression.
|
78
83
|
def eql?(other)
|
79
|
-
other.is_a?(self.class) && !self.class.comparison_attrs.find
|
84
|
+
other.is_a?(self.class) && !self.class.comparison_attrs.find{|a| send(a) != other.send(a)}
|
80
85
|
end
|
81
86
|
|
82
87
|
# Make sure that the hash value is the same if the attributes are the same.
|
@@ -84,13 +89,18 @@ module Sequel
|
|
84
89
|
([self.class] + self.class.comparison_attrs.map{|x| send(x)}).hash
|
85
90
|
end
|
86
91
|
|
87
|
-
#
|
88
|
-
#
|
92
|
+
# Show the class name and instance variables for the object, necessary
|
93
|
+
# for correct operation on ruby 1.9.2.
|
94
|
+
def inspect
|
95
|
+
"#<#{self.class} #{instance_variables.map{|iv| "#{iv}=>#{instance_variable_get(iv).inspect}"}.join(', ')}>"
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns +self+, because <tt>SQL::Expression</tt> already acts like +LiteralString+.
|
89
99
|
def lit
|
90
100
|
self
|
91
101
|
end
|
92
102
|
|
93
|
-
# Alias of to_s
|
103
|
+
# Alias of +to_s+
|
94
104
|
def sql_literal(ds)
|
95
105
|
to_s(ds)
|
96
106
|
end
|
@@ -98,11 +108,10 @@ module Sequel
|
|
98
108
|
|
99
109
|
# Represents a complex SQL expression, with a given operator and one
|
100
110
|
# or more attributes (which may also be ComplexExpressions, forming
|
101
|
-
# a tree). This class is the backbone of
|
102
|
-
# Sequel.
|
111
|
+
# a tree). This class is the backbone of Sequel's ruby expression DSL.
|
103
112
|
#
|
104
113
|
# This is an abstract class that is not that useful by itself. The
|
105
|
-
# subclasses BooleanExpression
|
114
|
+
# subclasses +BooleanExpression+, +NumericExpression+, and +StringExpression+
|
106
115
|
# define the behavior of the DSL via operators.
|
107
116
|
class ComplexExpression < Expression
|
108
117
|
# A hash of the opposite for each operator symbol, used for inverting
|
@@ -114,30 +123,33 @@ module Sequel
|
|
114
123
|
:'!~*' => :'~*', :NOT => :NOOP, :NOOP => :NOT, :ILIKE => :'NOT ILIKE',
|
115
124
|
:'NOT ILIKE'=>:ILIKE}
|
116
125
|
|
117
|
-
# Standard
|
126
|
+
# Standard mathematical operators used in +NumericMethods+
|
118
127
|
MATHEMATICAL_OPERATORS = [:+, :-, :/, :*]
|
119
128
|
|
120
|
-
# Bitwise
|
129
|
+
# Bitwise mathematical operators used in +NumericMethods+
|
121
130
|
BITWISE_OPERATORS = [:&, :|, :^, :<<, :>>]
|
122
131
|
|
123
|
-
# Inequality
|
132
|
+
# Inequality operators used in +InequalityMethods+
|
124
133
|
INEQUALITY_OPERATORS = [:<, :>, :<=, :>=]
|
125
134
|
|
126
|
-
# Hash of ruby operator symbols to SQL operators, used in BooleanMethods
|
135
|
+
# Hash of ruby operator symbols to SQL operators, used in +BooleanMethods+
|
127
136
|
BOOLEAN_OPERATOR_METHODS = {:& => :AND, :| =>:OR}
|
128
137
|
|
138
|
+
# Operators that use IN/NOT IN for inclusion/exclusion
|
139
|
+
IN_OPERATORS = [:IN, :'NOT IN']
|
140
|
+
|
129
141
|
# Operators that use IS, used for special casing to override literal true/false values
|
130
142
|
IS_OPERATORS = [:IS, :'IS NOT']
|
131
143
|
|
132
144
|
# Operator symbols that take exactly two arguments
|
133
145
|
TWO_ARITY_OPERATORS = [:'=', :'!=', :LIKE, :'NOT LIKE', \
|
134
|
-
:~, :'!~', :'~*', :'!~*', :
|
135
|
-
INEQUALITY_OPERATORS + BITWISE_OPERATORS + IS_OPERATORS
|
146
|
+
:~, :'!~', :'~*', :'!~*', :ILIKE, :'NOT ILIKE'] + \
|
147
|
+
INEQUALITY_OPERATORS + BITWISE_OPERATORS + IS_OPERATORS + IN_OPERATORS
|
136
148
|
|
137
149
|
# Operator symbols that take one or more arguments
|
138
150
|
N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS
|
139
151
|
|
140
|
-
# Operator symbols that take
|
152
|
+
# Operator symbols that take only a single argument
|
141
153
|
ONE_ARITY_OPERATORS = [:NOT, :NOOP, :'B~']
|
142
154
|
|
143
155
|
# An array of args for this object
|
@@ -147,11 +159,13 @@ module Sequel
|
|
147
159
|
attr_reader :op
|
148
160
|
|
149
161
|
# Set the operator symbol and arguments for this object to the ones given.
|
150
|
-
# Convert all args that are hashes or arrays
|
151
|
-
#
|
152
|
-
# Raise an
|
162
|
+
# Convert all args that are hashes or arrays of two element arrays to +BooleanExpressions+,
|
163
|
+
# other than the second arg for an IN/NOT IN operator.
|
164
|
+
# Raise an +Error+ if the operator doesn't allow boolean input and a boolean argument is given.
|
165
|
+
# Raise an +Error+ if the wrong number of arguments for a given operator is used.
|
153
166
|
def initialize(op, *args)
|
154
|
-
|
167
|
+
orig_args = args
|
168
|
+
args = args.map{|a| Sequel.condition_specifier?(a) ? SQL::BooleanExpression.from_value_pairs(a) : a}
|
155
169
|
case op
|
156
170
|
when *N_ARITY_OPERATORS
|
157
171
|
raise(Error, "The #{op} operator requires at least 1 argument") unless args.length >= 1
|
@@ -160,6 +174,10 @@ module Sequel
|
|
160
174
|
old_args.each{|a| a.is_a?(self.class) && a.op == op ? args.concat(a.args) : args.push(a)}
|
161
175
|
when *TWO_ARITY_OPERATORS
|
162
176
|
raise(Error, "The #{op} operator requires precisely 2 arguments") unless args.length == 2
|
177
|
+
# With IN/NOT IN, even if the second argument is an array of two element arrays,
|
178
|
+
# don't convert it into a boolean expression, since it's definitely being used
|
179
|
+
# as a value list.
|
180
|
+
args[1] = orig_args[1] if IN_OPERATORS.include?(op)
|
163
181
|
when *ONE_ARITY_OPERATORS
|
164
182
|
raise(Error, "The #{op} operator requires a single argument") unless args.length == 1
|
165
183
|
else
|
@@ -173,23 +191,32 @@ module Sequel
|
|
173
191
|
end
|
174
192
|
|
175
193
|
# The base class for expressions that can be used in multiple places in
|
176
|
-
#
|
194
|
+
# an SQL query.
|
177
195
|
class GenericExpression < Expression
|
178
196
|
end
|
179
197
|
|
180
198
|
### Modules ###
|
181
199
|
|
182
|
-
#
|
200
|
+
# Includes an +as+ method that creates an SQL alias.
|
183
201
|
module AliasMethods
|
184
|
-
# Create an SQL
|
202
|
+
# Create an SQL alias (+AliasedExpression+) of the receiving column or expression to the given alias.
|
203
|
+
#
|
204
|
+
# :column.as(:alias) # "column" AS "alias"
|
185
205
|
def as(aliaz)
|
186
206
|
AliasedExpression.new(self, aliaz)
|
187
207
|
end
|
188
208
|
end
|
189
209
|
|
190
210
|
# This defines the bitwise methods: &, |, ^, ~, <<, and >>. Because these
|
191
|
-
# methods overlap with the standard BooleanMethods methods
|
192
|
-
# make sense for
|
211
|
+
# methods overlap with the standard +BooleanMethods methods+, and they only
|
212
|
+
# make sense for integers, they are only included in +NumericExpression+.
|
213
|
+
#
|
214
|
+
# :a.sql_number & :b # "a" & "b"
|
215
|
+
# :a.sql_number | :b # "a" | "b"
|
216
|
+
# :a.sql_number ^ :b # "a" ^ "b"
|
217
|
+
# :a.sql_number << :b # "a" << "b"
|
218
|
+
# :a.sql_number >> :b # "a" >> "b"
|
219
|
+
# ~:a.sql_number # ~"a"
|
193
220
|
module BitwiseMethods
|
194
221
|
ComplexExpression::BITWISE_OPERATORS.each do |o|
|
195
222
|
define_method(o) do |ce|
|
@@ -203,22 +230,21 @@ module Sequel
|
|
203
230
|
end
|
204
231
|
|
205
232
|
# Do the bitwise compliment of the self
|
233
|
+
#
|
234
|
+
# ~:a.sql_number # ~"a"
|
206
235
|
def ~
|
207
236
|
NumericExpression.new(:'B~', self)
|
208
237
|
end
|
209
238
|
end
|
210
239
|
|
211
|
-
# This module includes the
|
212
|
-
# used in a boolean context in SQL
|
213
|
-
# and SQL::
|
240
|
+
# This module includes the boolean/logical AND (&), OR (|) and NOT (~) operators
|
241
|
+
# that are defined on objects that can be used in a boolean context in SQL
|
242
|
+
# (+Symbol+, +LiteralString+, and <tt>SQL::GenericExpression</tt>).
|
214
243
|
#
|
215
|
-
#
|
244
|
+
# :a & :b # "a" AND "b"
|
245
|
+
# :a | :b # "a" OR "b"
|
246
|
+
# ~:a # NOT "a"
|
216
247
|
module BooleanMethods
|
217
|
-
# Create a new BooleanExpression with NOT, representing the inversion of whatever self represents.
|
218
|
-
def ~
|
219
|
-
BooleanExpression.invert(self)
|
220
|
-
end
|
221
|
-
|
222
248
|
ComplexExpression::BOOLEAN_OPERATOR_METHODS.each do |m, o|
|
223
249
|
define_method(m) do |ce|
|
224
250
|
case ce
|
@@ -229,35 +255,52 @@ module Sequel
|
|
229
255
|
end
|
230
256
|
end
|
231
257
|
end
|
258
|
+
|
259
|
+
# Create a new BooleanExpression with NOT, representing the inversion of whatever self represents.
|
260
|
+
#
|
261
|
+
# ~:a # NOT :a
|
262
|
+
def ~
|
263
|
+
BooleanExpression.invert(self)
|
264
|
+
end
|
232
265
|
end
|
233
266
|
|
234
|
-
# Holds methods that are used to cast objects to
|
267
|
+
# Holds methods that are used to cast objects to different SQL types.
|
235
268
|
module CastMethods
|
236
269
|
# Cast the reciever to the given SQL type. You can specify a ruby class as a type,
|
237
270
|
# and it is handled similarly to using a database independent type in the schema methods.
|
271
|
+
#
|
272
|
+
# :a.cast(:integer) # CAST(a AS integer)
|
273
|
+
# :a.cast(String) # CAST(a AS varchar(255))
|
238
274
|
def cast(sql_type)
|
239
275
|
Cast.new(self, sql_type)
|
240
276
|
end
|
241
277
|
|
242
|
-
# Cast the reciever to the given SQL type (or the database's default
|
243
|
-
# and return the result as a NumericExpression
|
278
|
+
# Cast the reciever to the given SQL type (or the database's default Integer type if none given),
|
279
|
+
# and return the result as a +NumericExpression+, so you can use the bitwise operators
|
280
|
+
# on the result.
|
281
|
+
#
|
282
|
+
# :a.cast_numeric # CAST(a AS integer)
|
283
|
+
# :a.cast_numeric(Float) # CAST(a AS double precision)
|
244
284
|
def cast_numeric(sql_type = nil)
|
245
285
|
cast(sql_type || Integer).sql_number
|
246
286
|
end
|
247
287
|
|
248
|
-
# Cast the reciever to the given SQL type (or the database's default
|
249
|
-
# and return the result as a StringExpression
|
288
|
+
# Cast the reciever to the given SQL type (or the database's default String type if none given),
|
289
|
+
# and return the result as a +StringExpression+, so you can use +
|
250
290
|
# directly on the result for SQL string concatenation.
|
291
|
+
#
|
292
|
+
# :a.cast_string # CAST(a AS varchar(255))
|
293
|
+
# :a.cast_string(:text) # CAST(a AS text)
|
251
294
|
def cast_string(sql_type = nil)
|
252
295
|
cast(sql_type || String).sql_string
|
253
296
|
end
|
254
297
|
end
|
255
298
|
|
256
299
|
# Adds methods that allow you to treat an object as an instance of a specific
|
257
|
-
# ComplexExpression subclass. This is useful if another library
|
300
|
+
# +ComplexExpression+ subclass. This is useful if another library
|
258
301
|
# overrides the methods defined by Sequel.
|
259
302
|
#
|
260
|
-
# For example, if Symbol
|
303
|
+
# For example, if <tt>Symbol#/</tt> is overridden to produce a string (for
|
261
304
|
# example, to make file system path creation easier), the
|
262
305
|
# following code will not do what you want:
|
263
306
|
#
|
@@ -269,51 +312,64 @@ module Sequel
|
|
269
312
|
module ComplexExpressionMethods
|
270
313
|
# Extract a datetime_part (e.g. year, month) from self:
|
271
314
|
#
|
272
|
-
# :date.extract(:year) #
|
315
|
+
# :date.extract(:year) # extract(year FROM "date")
|
273
316
|
#
|
274
317
|
# Also has the benefit of returning the result as a
|
275
318
|
# NumericExpression instead of a generic ComplexExpression.
|
276
319
|
#
|
277
320
|
# The extract function is in the SQL standard, but it doesn't
|
278
|
-
# doesn't use the standard function calling convention
|
321
|
+
# doesn't use the standard function calling convention, and it
|
322
|
+
# doesn't work on all databases.
|
279
323
|
def extract(datetime_part)
|
280
324
|
Function.new(:extract, PlaceholderLiteralString.new("#{datetime_part} FROM ?", [self])).sql_number
|
281
325
|
end
|
282
326
|
|
283
|
-
# Return a BooleanExpression representation of self
|
327
|
+
# Return a BooleanExpression representation of +self+.
|
284
328
|
def sql_boolean
|
285
329
|
BooleanExpression.new(:NOOP, self)
|
286
330
|
end
|
287
331
|
|
288
|
-
# Return a NumericExpression representation of self
|
332
|
+
# Return a NumericExpression representation of +self+.
|
333
|
+
#
|
334
|
+
# ~:a # NOT "a"
|
335
|
+
# ~:a.sql_number # ~"a"
|
289
336
|
def sql_number
|
290
337
|
NumericExpression.new(:NOOP, self)
|
291
338
|
end
|
292
339
|
|
293
|
-
# Return a StringExpression representation of self
|
340
|
+
# Return a StringExpression representation of +self+.
|
341
|
+
#
|
342
|
+
# :a + :b # "a" + "b"
|
343
|
+
# :a.sql_string + :b # "a" || "b"
|
294
344
|
def sql_string
|
295
345
|
StringExpression.new(:NOOP, self)
|
296
346
|
end
|
297
347
|
end
|
298
348
|
|
299
|
-
# Includes
|
349
|
+
# Includes an +identifier+ method that returns <tt>Identifier</tt>s.
|
300
350
|
module IdentifierMethods
|
301
|
-
# Return self wrapped as an
|
351
|
+
# Return self wrapped as an <tt>SQL::Identifier</tt>.
|
352
|
+
#
|
353
|
+
# :a__b # "a"."b"
|
354
|
+
# :a__b.identifier # "a__b"
|
302
355
|
def identifier
|
303
356
|
Identifier.new(self)
|
304
357
|
end
|
305
358
|
end
|
306
359
|
|
307
|
-
# This module includes the methods that are defined on objects that can be
|
308
|
-
# used in a numeric or string context in SQL (Symbol (except on ruby 1.9), LiteralString
|
309
|
-
# SQL::
|
360
|
+
# This module includes the inequality methods (>, <, >=, <=) that are defined on objects that can be
|
361
|
+
# used in a numeric or string context in SQL (+Symbol+ (except on ruby 1.9), +LiteralString+,
|
362
|
+
# <tt>SQL::GenericExpression</tt>).
|
310
363
|
#
|
311
|
-
#
|
364
|
+
# 'a'.lit > :b # a > "b"
|
365
|
+
# 'a'.lit < :b # a > "b"
|
366
|
+
# 'a'.lit >= :b # a >= "b"
|
367
|
+
# 'a'.lit <= :b # a <= "b"
|
312
368
|
module InequalityMethods
|
313
369
|
ComplexExpression::INEQUALITY_OPERATORS.each do |o|
|
314
370
|
define_method(o) do |ce|
|
315
371
|
case ce
|
316
|
-
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
|
372
|
+
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, ::Array
|
317
373
|
raise(Error, "cannot apply #{o} to a boolean expression")
|
318
374
|
else
|
319
375
|
BooleanExpression.new(o, self, ce)
|
@@ -323,16 +379,17 @@ module Sequel
|
|
323
379
|
end
|
324
380
|
|
325
381
|
# This module augments the default initalize method for the
|
326
|
-
# ComplexExpression subclass it is included in, so that
|
327
|
-
# attempting to use boolean input when initializing a NumericExpression
|
328
|
-
# or StringExpression results in an error.
|
382
|
+
# +ComplexExpression+ subclass it is included in, so that
|
383
|
+
# attempting to use boolean input when initializing a +NumericExpression+
|
384
|
+
# or +StringExpression+ results in an error. It is not expected to be
|
385
|
+
# used directly.
|
329
386
|
module NoBooleanInputMethods
|
330
|
-
# Raise an Error if one of the args would be boolean in an SQL
|
387
|
+
# Raise an +Error+ if one of the args would be boolean in an SQL
|
331
388
|
# context, otherwise call super.
|
332
389
|
def initialize(op, *args)
|
333
390
|
args.each do |a|
|
334
391
|
case a
|
335
|
-
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
|
392
|
+
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, ::Array
|
336
393
|
raise(Error, "cannot apply #{op} to a boolean expression")
|
337
394
|
end
|
338
395
|
end
|
@@ -340,11 +397,14 @@ module Sequel
|
|
340
397
|
end
|
341
398
|
end
|
342
399
|
|
343
|
-
# This module includes the
|
344
|
-
# used in a numeric context in SQL
|
345
|
-
# and SQL::
|
400
|
+
# This module includes the standard mathematical methods (+, -, *, and /)
|
401
|
+
# that are defined on objects that can be used in a numeric context in SQL
|
402
|
+
# (+Symbol+, +LiteralString+, and +SQL::GenericExpression+).
|
346
403
|
#
|
347
|
-
#
|
404
|
+
# :a + :b # "a" + "b"
|
405
|
+
# :a - :b # "a" - "b"
|
406
|
+
# :a * :b # "a" * "b"
|
407
|
+
# :a / :b # "a" / "b"
|
348
408
|
module NumericMethods
|
349
409
|
ComplexExpression::MATHEMATICAL_OPERATORS.each do |o|
|
350
410
|
define_method(o) do |ce|
|
@@ -358,66 +418,83 @@ module Sequel
|
|
358
418
|
end
|
359
419
|
end
|
360
420
|
|
361
|
-
# Methods that create OrderedExpressions
|
421
|
+
# Methods that create +OrderedExpressions+, used for sorting by columns
|
362
422
|
# or more complex expressions.
|
363
423
|
module OrderMethods
|
364
|
-
# Mark the receiving SQL column as sorting in
|
365
|
-
|
366
|
-
|
424
|
+
# Mark the receiving SQL column as sorting in an ascending fashion (generally a no-op).
|
425
|
+
# Options:
|
426
|
+
#
|
427
|
+
# :nulls :: Set to :first to use NULLS FIRST (so NULL values are ordered
|
428
|
+
# before other values), or :last to use NULLS LAST (so NULL values
|
429
|
+
# are ordered after other values).
|
430
|
+
def asc(opts={})
|
431
|
+
OrderedExpression.new(self, false, opts)
|
367
432
|
end
|
368
433
|
|
369
|
-
# Mark the receiving SQL column as sorting in
|
370
|
-
|
371
|
-
|
434
|
+
# Mark the receiving SQL column as sorting in a descending fashion.
|
435
|
+
# Options:
|
436
|
+
#
|
437
|
+
# :nulls :: Set to :first to use NULLS FIRST (so NULL values are ordered
|
438
|
+
# before other values), or :last to use NULLS LAST (so NULL values
|
439
|
+
# are ordered after other values).
|
440
|
+
def desc(opts={})
|
441
|
+
OrderedExpression.new(self, true, opts)
|
372
442
|
end
|
373
443
|
end
|
374
444
|
|
375
|
-
#
|
445
|
+
# Includes a +qualify+ method that created <tt>QualifiedIdentifier</tt>s, used for qualifying column
|
376
446
|
# names with a table or table names with a schema.
|
377
447
|
module QualifyingMethods
|
378
|
-
# Qualify the
|
379
|
-
|
380
|
-
|
448
|
+
# Qualify the receiver with the given +qualifier+ (table for column/schema for table).
|
449
|
+
#
|
450
|
+
# :column.qualify(:table) # "table"."column"
|
451
|
+
# :table.qualify(:schema) # "schema"."table"
|
452
|
+
# :column.qualify(:table).qualify(:schema) # "schema"."table"."column"
|
453
|
+
def qualify(qualifier)
|
454
|
+
QualifiedIdentifier.new(qualifier, self)
|
381
455
|
end
|
382
456
|
end
|
383
457
|
|
384
|
-
# This module includes the methods that are defined on objects that can be
|
385
|
-
# used in a string context in SQL (Symbol
|
386
|
-
# and SQL::StringExpression).
|
387
|
-
#
|
388
|
-
# This defines the like (LIKE) and ilike methods, used for pattern matching.
|
389
|
-
# like is case sensitive (if the database supports it), ilike is case insensitive.
|
458
|
+
# This module includes the +like+ and +ilike+ methods used for pattern matching that are defined on objects that can be
|
459
|
+
# used in a string context in SQL (+Symbol+, +LiteralString+, <tt>SQL::GenericExpression</tt>).
|
390
460
|
module StringMethods
|
391
|
-
# Create a BooleanExpression case insensitive pattern match of
|
392
|
-
# with the given patterns. See StringExpression.like
|
461
|
+
# Create a +BooleanExpression+ case insensitive pattern match of the receiver
|
462
|
+
# with the given patterns. See <tt>StringExpression.like</tt>.
|
463
|
+
#
|
464
|
+
# :a.ilike('A%') # "a" ILIKE 'A%'
|
393
465
|
def ilike(*ces)
|
394
466
|
StringExpression.like(self, *(ces << {:case_insensitive=>true}))
|
395
467
|
end
|
396
468
|
|
397
|
-
# Create a BooleanExpression case sensitive (if the database supports it) pattern match of
|
398
|
-
# the given patterns. See StringExpression.like
|
469
|
+
# Create a +BooleanExpression+ case sensitive (if the database supports it) pattern match of the receiver with
|
470
|
+
# the given patterns. See <tt>StringExpression.like</tt>.
|
471
|
+
#
|
472
|
+
# :a.like('A%') # "a" LIKE 'A%'
|
399
473
|
def like(*ces)
|
400
474
|
StringExpression.like(self, *ces)
|
401
475
|
end
|
402
476
|
end
|
403
477
|
|
404
|
-
# This module is included in StringExpression and can be included elsewhere
|
405
|
-
# to allow the use of the + operator to represent concatenation of SQL
|
406
|
-
# Strings:
|
407
|
-
#
|
408
|
-
# :x.sql_string + :y => # SQL: x || y
|
478
|
+
# This module includes the <tt>+</tt> method. It is included in +StringExpression+ and can be included elsewhere
|
479
|
+
# to allow the use of the + operator to represent concatenation of SQL Strings:
|
409
480
|
module StringConcatenationMethods
|
481
|
+
# Return a +StringExpression+ representing the concatenation of the receiver
|
482
|
+
# with the given argument.
|
483
|
+
#
|
484
|
+
# :x.sql_string + :y => # "x" || "y"
|
410
485
|
def +(ce)
|
411
486
|
StringExpression.new(:'||', self, ce)
|
412
487
|
end
|
413
488
|
end
|
414
489
|
|
415
|
-
#
|
490
|
+
# This module includes the +sql_subscript+ method, representing SQL array accesses.
|
416
491
|
module SubscriptMethods
|
417
|
-
# Return
|
492
|
+
# Return a <tt>Subscript</tt> with the given arguments, representing an
|
493
|
+
# SQL array access.
|
418
494
|
#
|
419
|
-
# :array.sql_subscript(1) #
|
420
|
-
# :array.sql_subscript(1, 2) #
|
495
|
+
# :array.sql_subscript(1) # array[1]
|
496
|
+
# :array.sql_subscript(1, 2) # array[1, 2]
|
497
|
+
# :array.sql_subscript([1, 2]) # array[1, 2]
|
421
498
|
def sql_subscript(*sub)
|
422
499
|
Subscript.new(self, sub.flatten)
|
423
500
|
end
|
@@ -425,12 +502,12 @@ module Sequel
|
|
425
502
|
|
426
503
|
### Classes ###
|
427
504
|
|
428
|
-
# Represents an aliasing of an expression
|
505
|
+
# Represents an aliasing of an expression to a given alias.
|
429
506
|
class AliasedExpression < Expression
|
430
507
|
# The expression to alias
|
431
508
|
attr_reader :expression
|
432
509
|
|
433
|
-
# The alias to use for the expression, not alias since that is
|
510
|
+
# The alias to use for the expression, not +alias+ since that is
|
434
511
|
# a keyword in ruby.
|
435
512
|
attr_reader :aliaz
|
436
513
|
|
@@ -442,28 +519,31 @@ module Sequel
|
|
442
519
|
to_s_method :aliased_expression_sql
|
443
520
|
end
|
444
521
|
|
445
|
-
# Blob is used to represent binary data in the Ruby environment that is
|
522
|
+
# +Blob+ is used to represent binary data in the Ruby environment that is
|
446
523
|
# stored as a blob type in the database. Sequel represents binary data as a Blob object because
|
447
|
-
#
|
524
|
+
# most database engines require binary data to be escaped differently than regular strings.
|
448
525
|
class Blob < ::String
|
449
|
-
# Returns self
|
526
|
+
# Returns +self+, used so that Blobs don't get wrapped in multiple
|
527
|
+
# levels.
|
450
528
|
def to_sequel_blob
|
451
529
|
self
|
452
530
|
end
|
453
531
|
end
|
454
532
|
|
455
|
-
# Subclass of ComplexExpression where the expression results
|
533
|
+
# Subclass of +ComplexExpression+ where the expression results
|
456
534
|
# in a boolean value in SQL.
|
457
535
|
class BooleanExpression < ComplexExpression
|
458
536
|
include BooleanMethods
|
459
537
|
|
460
|
-
# Take pairs of values (e.g. a hash or array of
|
461
|
-
# and converts it to a BooleanExpression
|
538
|
+
# Take pairs of values (e.g. a hash or array of two element arrays)
|
539
|
+
# and converts it to a +BooleanExpression+. The operator and args
|
462
540
|
# used depends on the case of the right (2nd) argument:
|
463
541
|
#
|
464
542
|
# * 0..10 - left >= 0 AND left <= 10
|
465
543
|
# * [1,2] - left IN (1,2)
|
466
544
|
# * nil - left IS NULL
|
545
|
+
# * true - left IS TRUE
|
546
|
+
# * false - left IS FALSE
|
467
547
|
# * /as/ - left ~ 'as'
|
468
548
|
# * :blah - left = blah
|
469
549
|
# * 'blah' - left = 'blah'
|
@@ -480,7 +560,7 @@ module Sequel
|
|
480
560
|
ce = case r
|
481
561
|
when Range
|
482
562
|
new(:AND, new(:>=, l, r.begin), new(r.exclude_end? ? :< : :<=, l, r.end))
|
483
|
-
when Array, ::Sequel::Dataset
|
563
|
+
when ::Array, ::Sequel::Dataset
|
484
564
|
new(:IN, l, r)
|
485
565
|
when NegativeBooleanConstant
|
486
566
|
new(:"IS NOT", l, r.constant)
|
@@ -502,6 +582,8 @@ module Sequel
|
|
502
582
|
# be inverted, raise an error. An inverted expression should match everything that the
|
503
583
|
# uninverted expression did not match, and vice-versa, except for possible issues with
|
504
584
|
# SQL NULL (i.e. 1 == NULL is NULL and 1 != NULL is also NULL).
|
585
|
+
#
|
586
|
+
# BooleanExpression.invert(:a) # NOT "a"
|
505
587
|
def self.invert(ce)
|
506
588
|
case ce
|
507
589
|
when BooleanExpression
|
@@ -519,23 +601,31 @@ module Sequel
|
|
519
601
|
end
|
520
602
|
end
|
521
603
|
|
522
|
-
# Represents an SQL CASE expression, used for
|
604
|
+
# Represents an SQL CASE expression, used for conditional branching in SQL.
|
523
605
|
class CaseExpression < GenericExpression
|
524
606
|
# An array of all two pairs with the first element specifying the
|
525
|
-
# condition and the second element specifying the result
|
607
|
+
# condition and the second element specifying the result if the
|
608
|
+
# condition matches.
|
526
609
|
attr_reader :conditions
|
527
610
|
|
528
|
-
# The default value if no conditions
|
611
|
+
# The default value if no conditions match.
|
529
612
|
attr_reader :default
|
530
613
|
|
531
614
|
# The expression to test the conditions against
|
532
615
|
attr_reader :expression
|
533
616
|
|
534
617
|
# Create an object with the given conditions and
|
535
|
-
# default value.
|
536
|
-
|
618
|
+
# default value. An expression can be provided to
|
619
|
+
# test each condition against, instead of having
|
620
|
+
# all conditions represent their own boolean expression.
|
621
|
+
def initialize(conditions, default, expression=(no_expression=true; nil))
|
537
622
|
raise(Sequel::Error, 'CaseExpression conditions must be a hash or array of all two pairs') unless Sequel.condition_specifier?(conditions)
|
538
|
-
@conditions, @default, @expression = conditions.to_a, default, expression
|
623
|
+
@conditions, @default, @expression, @no_expression = conditions.to_a, default, expression, no_expression
|
624
|
+
end
|
625
|
+
|
626
|
+
# Whether to use an expression for this CASE expression.
|
627
|
+
def expression?
|
628
|
+
!@no_expression
|
539
629
|
end
|
540
630
|
|
541
631
|
to_s_method :case_expression_sql
|
@@ -578,9 +668,12 @@ module Sequel
|
|
578
668
|
include SubscriptMethods
|
579
669
|
end
|
580
670
|
|
581
|
-
# Represents constants or psuedo-constants (e.g. CURRENT_DATE) in SQL.
|
671
|
+
# Represents constants or psuedo-constants (e.g. +CURRENT_DATE+) in SQL.
|
582
672
|
class Constant < GenericExpression
|
583
|
-
#
|
673
|
+
# The underlying constant related to this object.
|
674
|
+
attr_reader :constant
|
675
|
+
|
676
|
+
# Create an constant with the given value
|
584
677
|
def initialize(constant)
|
585
678
|
@constant = constant
|
586
679
|
end
|
@@ -588,15 +681,12 @@ module Sequel
|
|
588
681
|
to_s_method :constant_sql, '@constant'
|
589
682
|
end
|
590
683
|
|
591
|
-
# Represents boolean constants such as NULL
|
684
|
+
# Represents boolean constants such as +NULL+, +NOTNULL+, +TRUE+, and +FALSE+.
|
592
685
|
class BooleanConstant < Constant
|
593
|
-
# The underlying constant related for this object.
|
594
|
-
attr_reader :constant
|
595
|
-
|
596
686
|
to_s_method :boolean_constant_sql, '@constant'
|
597
687
|
end
|
598
688
|
|
599
|
-
# Represents inverse boolean constants (currently only NOTNULL). A
|
689
|
+
# Represents inverse boolean constants (currently only +NOTNULL+). A
|
600
690
|
# special class to allow for special behavior.
|
601
691
|
class NegativeBooleanConstant < BooleanConstant
|
602
692
|
to_s_method :negative_boolean_constant_sql, '@constant'
|
@@ -624,7 +714,7 @@ module Sequel
|
|
624
714
|
# The SQL function to call
|
625
715
|
attr_reader :f
|
626
716
|
|
627
|
-
# Set the
|
717
|
+
# Set the functions and args to the given arguments
|
628
718
|
def initialize(f, *args)
|
629
719
|
@f, @args = f, args
|
630
720
|
end
|
@@ -645,12 +735,12 @@ module Sequel
|
|
645
735
|
end
|
646
736
|
|
647
737
|
# Represents an identifier (column or table). Can be used
|
648
|
-
# to specify a Symbol with multiple underscores should not be
|
738
|
+
# to specify a +Symbol+ with multiple underscores should not be
|
649
739
|
# split, or for creating an identifier without using a symbol.
|
650
740
|
class Identifier < GenericExpression
|
651
741
|
include QualifyingMethods
|
652
742
|
|
653
|
-
# The table
|
743
|
+
# The table or column to reference
|
654
744
|
attr_reader :value
|
655
745
|
|
656
746
|
# Set the value to the given argument
|
@@ -680,7 +770,7 @@ module Sequel
|
|
680
770
|
to_s_method :join_clause_sql
|
681
771
|
end
|
682
772
|
|
683
|
-
# Represents an SQL JOIN
|
773
|
+
# Represents an SQL JOIN clause with ON conditions.
|
684
774
|
class JoinOnClause < JoinClause
|
685
775
|
# The conditions for the join
|
686
776
|
attr_reader :on
|
@@ -695,7 +785,7 @@ module Sequel
|
|
695
785
|
to_s_method :join_on_clause_sql
|
696
786
|
end
|
697
787
|
|
698
|
-
# Represents an SQL JOIN
|
788
|
+
# Represents an SQL JOIN clause with USING conditions.
|
699
789
|
class JoinUsingClause < JoinClause
|
700
790
|
# The columns that appear in both tables that should be equal
|
701
791
|
# for the conditions to match.
|
@@ -713,8 +803,9 @@ module Sequel
|
|
713
803
|
|
714
804
|
# Represents a literal string with placeholders and arguments.
|
715
805
|
# This is necessary to ensure delayed literalization of the arguments
|
716
|
-
# required for the prepared statement support
|
717
|
-
|
806
|
+
# required for the prepared statement support and for database-specific
|
807
|
+
# literalization.
|
808
|
+
class PlaceholderLiteralString < GenericExpression
|
718
809
|
# The arguments that will be subsituted into the placeholders.
|
719
810
|
# Either an array of unnamed placeholders (which will be substituted in
|
720
811
|
# order for ? characters), or a hash of named placeholders (which will be
|
@@ -737,7 +828,7 @@ module Sequel
|
|
737
828
|
to_s_method :placeholder_literal_string_sql
|
738
829
|
end
|
739
830
|
|
740
|
-
# Subclass of ComplexExpression where the expression results
|
831
|
+
# Subclass of +ComplexExpression+ where the expression results
|
741
832
|
# in a numeric value in SQL.
|
742
833
|
class NumericExpression < ComplexExpression
|
743
834
|
include BitwiseMethods
|
@@ -748,43 +839,51 @@ module Sequel
|
|
748
839
|
|
749
840
|
# Represents a column/expression to order the result set by.
|
750
841
|
class OrderedExpression < Expression
|
842
|
+
INVERT_NULLS = {:first=>:last, :last=>:first}.freeze
|
843
|
+
|
751
844
|
# The expression to order the result set by.
|
752
845
|
attr_reader :expression
|
753
846
|
|
754
847
|
# Whether the expression should order the result set in a descending manner
|
755
848
|
attr_reader :descending
|
756
849
|
|
850
|
+
# Whether to sort NULLS FIRST/LAST
|
851
|
+
attr_reader :nulls
|
852
|
+
|
757
853
|
# Set the expression and descending attributes to the given values.
|
758
|
-
|
759
|
-
|
854
|
+
# Options:
|
855
|
+
#
|
856
|
+
# :nulls :: Can be :first/:last for NULLS FIRST/LAST.
|
857
|
+
def initialize(expression, descending = true, opts={})
|
858
|
+
@expression, @descending, @nulls = expression, descending, opts[:nulls]
|
760
859
|
end
|
761
860
|
|
762
|
-
# Return a copy that is ASC
|
861
|
+
# Return a copy that is ordered ASC
|
763
862
|
def asc
|
764
|
-
OrderedExpression.new(@expression, false)
|
863
|
+
OrderedExpression.new(@expression, false, :nulls=>@nulls)
|
765
864
|
end
|
766
865
|
|
767
|
-
# Return a copy that is DESC
|
866
|
+
# Return a copy that is ordered DESC
|
768
867
|
def desc
|
769
|
-
OrderedExpression.new(@expression)
|
868
|
+
OrderedExpression.new(@expression, true, :nulls=>@nulls)
|
770
869
|
end
|
771
870
|
|
772
|
-
# Return an inverted expression, changing ASC to DESC and
|
871
|
+
# Return an inverted expression, changing ASC to DESC and NULLS FIRST to NULLS LAST.
|
773
872
|
def invert
|
774
|
-
OrderedExpression.new(@expression, !@descending)
|
873
|
+
OrderedExpression.new(@expression, !@descending, :nulls=>INVERT_NULLS.fetch(@nulls, @nulls))
|
775
874
|
end
|
776
875
|
|
777
876
|
to_s_method :ordered_expression_sql
|
778
877
|
end
|
779
878
|
|
780
|
-
# Represents a qualified (column with table or table with schema)
|
879
|
+
# Represents a qualified identifier (column with table or table with schema).
|
781
880
|
class QualifiedIdentifier < GenericExpression
|
782
881
|
include QualifyingMethods
|
783
882
|
|
784
|
-
# The column
|
883
|
+
# The column/table referenced
|
785
884
|
attr_reader :column
|
786
885
|
|
787
|
-
# The table
|
886
|
+
# The table/schema qualifying the reference
|
788
887
|
attr_reader :table
|
789
888
|
|
790
889
|
# Set the table and column to the given arguments
|
@@ -795,7 +894,7 @@ module Sequel
|
|
795
894
|
to_s_method :qualified_identifier_sql
|
796
895
|
end
|
797
896
|
|
798
|
-
# Subclass of ComplexExpression where the expression results
|
897
|
+
# Subclass of +ComplexExpression+ where the expression results
|
799
898
|
# in a text/string/varchar value in SQL.
|
800
899
|
class StringExpression < ComplexExpression
|
801
900
|
include StringMethods
|
@@ -803,23 +902,31 @@ module Sequel
|
|
803
902
|
include InequalityMethods
|
804
903
|
include NoBooleanInputMethods
|
805
904
|
|
806
|
-
# Map of [regexp, case_insenstive] to ComplexExpression operator
|
905
|
+
# Map of [regexp, case_insenstive] to +ComplexExpression+ operator symbol
|
807
906
|
LIKE_MAP = {[true, true]=>:'~*', [true, false]=>:~, [false, true]=>:ILIKE, [false, false]=>:LIKE}
|
808
907
|
|
809
908
|
# Creates a SQL pattern match exprssion. left (l) is the SQL string we
|
810
909
|
# are matching against, and ces are the patterns we are matching.
|
811
|
-
# The match succeeds if any of the patterns match (SQL OR).
|
812
|
-
#
|
813
|
-
#
|
814
|
-
#
|
815
|
-
#
|
816
|
-
#
|
817
|
-
#
|
910
|
+
# The match succeeds if any of the patterns match (SQL OR).
|
911
|
+
#
|
912
|
+
# If a regular expression is used as a pattern, an SQL regular expression will be
|
913
|
+
# used, which is currently only supported on MySQL and PostgreSQL. Be aware
|
914
|
+
# that MySQL and PostgreSQL regular expression syntax is similar to ruby
|
915
|
+
# regular expression syntax, but it not exactly the same, especially for
|
916
|
+
# advanced regular expression features. Sequel just uses the source of the
|
917
|
+
# ruby regular expression verbatim as the SQL regular expression string.
|
918
|
+
#
|
919
|
+
# If any other object is used as a regular expression, the SQL LIKE operator will
|
920
|
+
# be used, and should be supported by most databases.
|
818
921
|
#
|
819
922
|
# The pattern match will be case insensitive if the last argument is a hash
|
820
923
|
# with a key of :case_insensitive that is not false or nil. Also,
|
821
924
|
# if a case insensitive regular expression is used (//i), that particular
|
822
925
|
# pattern which will always be case insensitive.
|
926
|
+
#
|
927
|
+
# StringExpression.like(:a, 'a%') # "a" LIKE 'a%'
|
928
|
+
# StringExpression.like(:a, 'a%', :case_insensitive=>true) # "a" ILIKE 'a%'
|
929
|
+
# StringExpression.like(:a, 'a%', /^a/i) # "a" LIKE 'a%' OR "a" ~* '^a'
|
823
930
|
def self.like(l, *ces)
|
824
931
|
l, lre, lci = like_element(l)
|
825
932
|
lci = (ces.last.is_a?(Hash) ? ces.pop : {})[:case_insensitive] ? true : lci
|
@@ -830,7 +937,7 @@ module Sequel
|
|
830
937
|
ces.length == 1 ? ces.at(0) : BooleanExpression.new(:OR, *ces)
|
831
938
|
end
|
832
939
|
|
833
|
-
#
|
940
|
+
# Returns a three element array, made up of:
|
834
941
|
# * The object to use
|
835
942
|
# * Whether it is a regular expression
|
836
943
|
# * Whether it is case insensitive
|
@@ -844,22 +951,6 @@ module Sequel
|
|
844
951
|
private_class_method :like_element
|
845
952
|
end
|
846
953
|
|
847
|
-
# Represents an SQL array. Added so it is possible to deal with a
|
848
|
-
# ruby array of all two pairs as an SQL array instead of an ordered
|
849
|
-
# hash-like conditions specifier.
|
850
|
-
class SQLArray < Expression
|
851
|
-
# The array of objects this SQLArray wraps
|
852
|
-
attr_reader :array
|
853
|
-
alias to_a array
|
854
|
-
|
855
|
-
# Create an object with the given array.
|
856
|
-
def initialize(array)
|
857
|
-
@array = array
|
858
|
-
end
|
859
|
-
|
860
|
-
to_s_method :array_sql, '@array'
|
861
|
-
end
|
862
|
-
|
863
954
|
# Represents an SQL array access, with multiple possible arguments.
|
864
955
|
class Subscript < GenericExpression
|
865
956
|
# The SQL array column
|
@@ -873,7 +964,7 @@ module Sequel
|
|
873
964
|
@f, @sub = f, sub
|
874
965
|
end
|
875
966
|
|
876
|
-
# Create a new
|
967
|
+
# Create a new +Subscript+ appending the given subscript(s)
|
877
968
|
# the the current array of subscripts.
|
878
969
|
def |(sub)
|
879
970
|
Subscript.new(@f, @sub + Array(sub))
|
@@ -882,32 +973,48 @@ module Sequel
|
|
882
973
|
to_s_method :subscript_sql
|
883
974
|
end
|
884
975
|
|
885
|
-
#
|
886
|
-
#
|
887
|
-
#
|
976
|
+
# Represents an SQL value list (IN/NOT IN predicate value). Added so it is possible to deal with a
|
977
|
+
# ruby array of two element arrays as an SQL value list instead of an ordered
|
978
|
+
# hash-like conditions specifier.
|
979
|
+
class ValueList < ::Array
|
980
|
+
end
|
981
|
+
|
982
|
+
# Deprecated name for +ValueList+, used for backwards compatibility
|
983
|
+
SQLArray = ValueList
|
984
|
+
|
985
|
+
# The purpose of the +VirtualRow+ class is to allow the easy creation of SQL identifiers and functions
|
986
|
+
# without relying on methods defined on +Symbol+. This is useful if another library defines
|
987
|
+
# the methods defined by Sequel, if you are running on ruby 1.9, or if you are not using the
|
988
|
+
# core extensions.
|
888
989
|
#
|
889
|
-
# An instance of this class is yielded to the block supplied to filter
|
990
|
+
# An instance of this class is yielded to the block supplied to <tt>Dataset#filter</tt>, <tt>Dataset#order</tt>, and <tt>Dataset#select</tt>
|
991
|
+
# (and the other methods that accept a block and pass it to one of those methods).
|
890
992
|
# If the block doesn't take an argument, the block is instance_evaled in the context of
|
891
993
|
# a new instance of this class.
|
892
994
|
#
|
893
|
-
# VirtualRow uses method_missing to return
|
894
|
-
# depending on how it is called.
|
895
|
-
#
|
896
|
-
#
|
897
|
-
#
|
898
|
-
#
|
899
|
-
#
|
900
|
-
#
|
995
|
+
# +VirtualRow+ uses +method_missing+ to return either an +Identifier+, +QualifiedIdentifier+, +Function+, or +WindowFunction+,
|
996
|
+
# depending on how it is called.
|
997
|
+
#
|
998
|
+
# If a block is _not_ given, creates one of the following objects:
|
999
|
+
#
|
1000
|
+
# +Function+ :: Returned if any arguments are supplied, using the method name
|
1001
|
+
# as the function name, and the arguments as the function arguments.
|
1002
|
+
# +QualifiedIdentifier+ :: Returned if the method name contains __, with the
|
1003
|
+
# table being the part before __, and the column being the part after.
|
1004
|
+
# +Identifier+ :: Returned otherwise, using the method name.
|
1005
|
+
#
|
1006
|
+
# If a block is given, it returns either a +Function+ or +WindowFunction+, depending on the first
|
901
1007
|
# argument to the method. Note that the block is currently not called by the code, though
|
902
1008
|
# this may change in a future version. If the first argument is:
|
903
|
-
#
|
904
|
-
#
|
905
|
-
#
|
906
|
-
#
|
907
|
-
#
|
908
|
-
#
|
909
|
-
#
|
910
|
-
#
|
1009
|
+
#
|
1010
|
+
# no arguments given :: creates a +Function+ with no arguments.
|
1011
|
+
# :* :: creates a +Function+ with a literal wildcard argument (*), mostly useful for COUNT.
|
1012
|
+
# :distinct :: creates a +Function+ that prepends DISTINCT to the rest of the arguments, mostly
|
1013
|
+
# useful for aggregate functions.
|
1014
|
+
# :over :: creates a +WindowFunction+. If a second argument is provided, it should be a hash
|
1015
|
+
# of options which are passed to Window (with possible keys :window, :partition, :order, and :frame). The
|
1016
|
+
# arguments to the function itself should be specified as <tt>:*=>true</tt> for a wildcard, or via
|
1017
|
+
# the <tt>:args</tt> option.
|
911
1018
|
#
|
912
1019
|
# Examples:
|
913
1020
|
#
|
@@ -927,13 +1034,15 @@ module Sequel
|
|
927
1034
|
# ds.select{rank(:over){}} # SELECT rank() OVER () FROM t
|
928
1035
|
# ds.select{count(:over, :*=>true){}} # SELECT count(*) OVER () FROM t
|
929
1036
|
# ds.select{sum(:over, :args=>col1, :partition=>col2, :order=>col3){}} # SELECT sum(col1) OVER (PARTITION BY col2 ORDER BY col3) FROM t
|
1037
|
+
#
|
1038
|
+
# For a more detailed explanation, see the {Virtual Rows guide}[link:files/doc/virtual_rows_rdoc.html].
|
930
1039
|
class VirtualRow < BasicObject
|
931
1040
|
WILDCARD = LiteralString.new('*').freeze
|
932
1041
|
QUESTION_MARK = LiteralString.new('?').freeze
|
933
1042
|
COMMA_SEPARATOR = LiteralString.new(', ').freeze
|
934
1043
|
DOUBLE_UNDERSCORE = '__'.freeze
|
935
1044
|
|
936
|
-
# Return
|
1045
|
+
# Return an +Identifier+, +QualifiedIdentifier+, +Function+, or +WindowFunction+, depending
|
937
1046
|
# on arguments and whether a block is provided. Does not currently call the block.
|
938
1047
|
# See the class level documentation.
|
939
1048
|
def method_missing(m, *args, &block)
|
@@ -963,17 +1072,17 @@ module Sequel
|
|
963
1072
|
end
|
964
1073
|
end
|
965
1074
|
|
966
|
-
# A
|
967
|
-
# It is separated from the WindowFunction class because it also can be used separately on
|
1075
|
+
# A +Window+ is part of a window function specifying the window over which the function operates.
|
1076
|
+
# It is separated from the +WindowFunction+ class because it also can be used separately on
|
968
1077
|
# some databases.
|
969
1078
|
class Window < Expression
|
970
|
-
# The options for this window. Options currently
|
971
|
-
#
|
972
|
-
#
|
973
|
-
#
|
974
|
-
#
|
975
|
-
#
|
976
|
-
#
|
1079
|
+
# The options for this window. Options currently supported:
|
1080
|
+
# :frame :: if specified, should be :all, :rows, or a String that is used literally. :all always operates over all rows in the
|
1081
|
+
# partition, while :rows excludes the current row's later peers. The default is to include
|
1082
|
+
# all previous rows in the partition up to the current row's last peer.
|
1083
|
+
# :order :: order on the column(s) given
|
1084
|
+
# :partition :: partition/group on the column(s) given
|
1085
|
+
# :window :: base results on a previously specified named window
|
977
1086
|
attr_reader :opts
|
978
1087
|
|
979
1088
|
# Set the options to the options given
|
@@ -984,12 +1093,12 @@ module Sequel
|
|
984
1093
|
to_s_method :window_sql, '@opts'
|
985
1094
|
end
|
986
1095
|
|
987
|
-
# A WindowFunction is a grouping of a
|
1096
|
+
# A +WindowFunction+ is a grouping of a +Function+ with a +Window+ over which it operates.
|
988
1097
|
class WindowFunction < GenericExpression
|
989
|
-
# The function to use, should be an SQL::Function
|
1098
|
+
# The function to use, should be an <tt>SQL::Function</tt>.
|
990
1099
|
attr_reader :function
|
991
1100
|
|
992
|
-
# The window to use, should be an SQL::Window
|
1101
|
+
# The window to use, should be an <tt>SQL::Window</tt>.
|
993
1102
|
attr_reader :window
|
994
1103
|
|
995
1104
|
# Set the function and window.
|
@@ -1001,9 +1110,9 @@ module Sequel
|
|
1001
1110
|
end
|
1002
1111
|
end
|
1003
1112
|
|
1004
|
-
# LiteralString is used to represent literal SQL expressions. A
|
1005
|
-
# LiteralString is copied verbatim into an SQL statement. Instances of
|
1006
|
-
# LiteralString can be created by calling String#lit
|
1113
|
+
# +LiteralString+ is used to represent literal SQL expressions. A
|
1114
|
+
# +LiteralString+ is copied verbatim into an SQL statement. Instances of
|
1115
|
+
# +LiteralString+ can be created by calling <tt>String#lit</tt>.
|
1007
1116
|
class LiteralString
|
1008
1117
|
include SQL::OrderMethods
|
1009
1118
|
include SQL::ComplexExpressionMethods
|