sequel_core 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +50 -0
- data/README +1 -2
- data/Rakefile +1 -1
- data/bin/sequel +26 -11
- data/doc/dataset_filtering.rdoc +9 -2
- data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -2
- data/lib/sequel_core/adapters/mysql.rb +11 -97
- data/lib/sequel_core/adapters/odbc_mssql.rb +1 -1
- data/lib/sequel_core/adapters/oracle.rb +1 -1
- data/lib/sequel_core/adapters/postgres.rb +33 -17
- data/lib/sequel_core/adapters/sqlite.rb +1 -1
- data/lib/sequel_core/connection_pool.rb +12 -35
- data/lib/sequel_core/core_ext.rb +5 -19
- data/lib/sequel_core/core_sql.rb +17 -6
- data/lib/sequel_core/database.rb +14 -2
- data/lib/sequel_core/dataset/callback.rb +0 -3
- data/lib/sequel_core/dataset/convenience.rb +4 -3
- data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +0 -21
- data/lib/sequel_core/dataset/sequelizer.rb +42 -43
- data/lib/sequel_core/dataset/sql.rb +121 -62
- data/lib/sequel_core/dataset.rb +20 -4
- data/lib/sequel_core/deprecated.rb +0 -6
- data/lib/sequel_core/migration.rb +4 -0
- data/lib/sequel_core/object_graph.rb +8 -6
- data/lib/sequel_core/pretty_table.rb +1 -1
- data/lib/sequel_core/schema/sql.rb +2 -0
- data/lib/sequel_core/sql.rb +393 -153
- data/lib/sequel_core.rb +22 -7
- data/spec/adapters/mysql_spec.rb +11 -7
- data/spec/adapters/postgres_spec.rb +32 -4
- data/spec/blockless_filters_spec.rb +33 -6
- data/spec/connection_pool_spec.rb +18 -16
- data/spec/core_ext_spec.rb +0 -13
- data/spec/core_sql_spec.rb +59 -13
- data/spec/database_spec.rb +5 -5
- data/spec/dataset_spec.rb +167 -55
- data/spec/object_graph_spec.rb +9 -4
- data/spec/sequelizer_spec.rb +8 -17
- data/spec/spec_helper.rb +4 -3
- metadata +2 -2
data/lib/sequel_core/dataset.rb
CHANGED
@@ -103,7 +103,16 @@ module Sequel
|
|
103
103
|
]
|
104
104
|
}
|
105
105
|
|
106
|
-
|
106
|
+
# The database that corresponds to this dataset
|
107
|
+
attr_accessor :db
|
108
|
+
|
109
|
+
# The hash of options for this dataset, keys are symbols.
|
110
|
+
attr_accessor :opts
|
111
|
+
|
112
|
+
# The row_proc for this database, should be a Proc that takes
|
113
|
+
# a single hash argument and returns the object you want to
|
114
|
+
# fetch_rows to return.
|
115
|
+
attr_accessor :row_proc
|
107
116
|
|
108
117
|
# Whether to quote identifiers for this dataset
|
109
118
|
attr_writer :quote_identifiers
|
@@ -158,8 +167,8 @@ module Sequel
|
|
158
167
|
|
159
168
|
# Return the dataset as a column with the given alias, so it can be used in the
|
160
169
|
# SELECT clause. This dataset should result in a single row and a single column.
|
161
|
-
def as(
|
162
|
-
::Sequel::SQL::
|
170
|
+
def as(aliaz)
|
171
|
+
::Sequel::SQL::AliasedExpression.new(self, aliaz)
|
163
172
|
end
|
164
173
|
|
165
174
|
# Returns an array with all records in the dataset. If a block is given,
|
@@ -178,7 +187,7 @@ module Sequel
|
|
178
187
|
def clone(opts = {})
|
179
188
|
c = super()
|
180
189
|
c.opts = @opts.merge(opts)
|
181
|
-
c.instance_variable_set(:@columns, nil)
|
190
|
+
c.instance_variable_set(:@columns, nil) if c.options_overlap(COLUMN_CHANGE_OPTS)
|
182
191
|
c
|
183
192
|
end
|
184
193
|
|
@@ -424,6 +433,13 @@ module Sequel
|
|
424
433
|
# Add the mutation methods via metaprogramming
|
425
434
|
def_mutation_method(*MUTATION_METHODS)
|
426
435
|
|
436
|
+
protected
|
437
|
+
|
438
|
+
# Return true if the dataset has a non-nil value for any key in opts.
|
439
|
+
def options_overlap(opts)
|
440
|
+
!(@opts.collect{|k,v| k unless v.nil?}.compact & opts).empty?
|
441
|
+
end
|
442
|
+
|
427
443
|
private
|
428
444
|
|
429
445
|
# Modify the receiver with the results of sending the meth, args, and block
|
@@ -22,11 +22,5 @@ module Sequel
|
|
22
22
|
caller.each{|c| @dms.puts(c)} if @pt
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
26
|
-
# Formats the message with a message that it will be removed in Sequel 2.0.
|
27
|
-
# This is the method that is added to the classes that include Sequel::Deprecation.
|
28
|
-
def deprecate(meth, message = nil)
|
29
|
-
::Sequel::Deprecation.deprecate("#{meth} is deprecated, and will be removed in Sequel 2.0.#{" #{message}." if message}")
|
30
|
-
end
|
31
25
|
end
|
32
26
|
end
|
@@ -22,6 +22,10 @@ module Sequel
|
|
22
22
|
#
|
23
23
|
# DB = Sequel.open ('sqlite://mydb')
|
24
24
|
# CreateSessions.apply(DB, :up)
|
25
|
+
#
|
26
|
+
# See Sequel::Schema::Generator for the syntax to use for creating tables,
|
27
|
+
# and Sequel::Schema::AlterTableGenerator for the syntax to use when
|
28
|
+
# altering existing tables.
|
25
29
|
class Migration
|
26
30
|
# Creates a new instance of the migration and sets the @db attribute.
|
27
31
|
def initialize(db)
|
@@ -38,11 +38,11 @@ module Sequel
|
|
38
38
|
# used more than once.
|
39
39
|
# * :join_type - The type of join to use (passed to join_table). Defaults to
|
40
40
|
# :left_outer.
|
41
|
-
# * :select -
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
41
|
+
# * :select - An array of columns to select. When not used, selects
|
42
|
+
# all columns in the given dataset. When set to false, selects no
|
43
|
+
# columns and is like simply joining the tables, though graph keeps
|
44
|
+
# some metadata about join that makes it important to use graph instead
|
45
|
+
# of join.
|
46
46
|
def graph(dataset, join_conditions, options = {})
|
47
47
|
# Allow the use of a model, dataset, or symbol as the first argument
|
48
48
|
# Find the table name/dataset based on the argument
|
@@ -112,12 +112,14 @@ module Sequel
|
|
112
112
|
select = opts[:select]
|
113
113
|
column_aliases = graph[:column_aliases]
|
114
114
|
ca_num = graph[:column_alias_num]
|
115
|
+
# Which columns to add to the result set
|
116
|
+
cols = options[:select] || dataset.columns
|
115
117
|
# If the column hasn't been used yet, don't alias it.
|
116
118
|
# If it has been used, try table_column.
|
117
119
|
# If that has been used, try table_column_N
|
118
120
|
# using the next value of N that we know hasn't been
|
119
121
|
# used
|
120
|
-
|
122
|
+
cols.each do |column|
|
121
123
|
col_alias, c = if column_aliases[column]
|
122
124
|
tc = :"#{table_alias}_#{column}"
|
123
125
|
if column_aliases[tc]
|
@@ -65,7 +65,7 @@ module Sequel
|
|
65
65
|
'+' << columns.map {|c| '-' * sizes[c]}.join('+') << '+'
|
66
66
|
end
|
67
67
|
|
68
|
-
|
68
|
+
private_class_method :column_sizes, :data_line, :format_cell, :header_line, :separator_line
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
data/lib/sequel_core/sql.rb
CHANGED
@@ -1,94 +1,22 @@
|
|
1
|
-
# This file holds classes and modules under Sequel that are related to SQL
|
2
|
-
# creation.
|
3
|
-
|
4
1
|
module Sequel
|
5
2
|
# The SQL module holds classes whose instances represent SQL fragments.
|
6
3
|
# It also holds modules that are included in core ruby classes that
|
7
4
|
# make Sequel a friendly DSL.
|
8
5
|
module SQL
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
ASC = 'ASC'.freeze
|
14
|
-
|
15
|
-
# Create an SQL column alias of the receiving column to the given alias.
|
16
|
-
def as(a)
|
17
|
-
ColumnExpr.new(self, AS, a)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Mark the receiving SQL column as sorting in a descending fashion.
|
21
|
-
def desc
|
22
|
-
ColumnExpr.new(self, DESC)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Mark the receiving SQL column as sorting in an ascending fashion (generally a no-op).
|
26
|
-
def asc
|
27
|
-
ColumnExpr.new(self, ASC)
|
28
|
-
end
|
6
|
+
### Parent Classes ###
|
7
|
+
|
8
|
+
# Classes/Modules aren't an alphabetical order due to the fact that
|
9
|
+
# some reference constants defined in others at load time.
|
29
10
|
|
30
|
-
# Cast the reciever to the given SQL type
|
31
|
-
def cast_as(t)
|
32
|
-
t = t.to_s.lit if t.is_a?(Symbol)
|
33
|
-
Sequel::SQL::Function.new(:cast, self.as(t))
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
11
|
# Base class for all SQL fragments
|
38
12
|
class Expression
|
39
|
-
include ColumnMethods
|
40
|
-
|
41
13
|
# Returns self, because SQL::Expression already acts like
|
42
14
|
# LiteralString.
|
43
15
|
def lit
|
44
16
|
self
|
45
17
|
end
|
46
18
|
end
|
47
|
-
|
48
|
-
# Represents all columns in a given table, table.* in SQL
|
49
|
-
class ColumnAll < Expression
|
50
|
-
# The table containing the columns being selected
|
51
|
-
attr_reader :table
|
52
|
-
|
53
|
-
# Create an object with the given table
|
54
|
-
def initialize(table)
|
55
|
-
@table = table
|
56
|
-
end
|
57
|
-
|
58
|
-
# ColumnAll expressions are considered equivalent if they
|
59
|
-
# have the same class and string representation
|
60
|
-
def ==(x)
|
61
|
-
x.class == self.class && @table == x.table
|
62
|
-
end
|
63
|
-
|
64
|
-
# Delegate the creation of the resulting SQL to the given dataset,
|
65
|
-
# since it may be database dependent.
|
66
|
-
def to_s(ds)
|
67
|
-
ds.column_all_sql(self)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Represents a generic column expression, used for specifying order
|
72
|
-
# and aliasing of columns.
|
73
|
-
class ColumnExpr < Expression
|
74
|
-
# Created readers for the left, operator, and right expression.
|
75
|
-
attr_reader :l, :op, :r
|
76
19
|
|
77
|
-
# Sets the attributes for the object to those given.
|
78
|
-
# The right (r) is not required, it is used when aliasing.
|
79
|
-
# The left (l) usually specifies the column name, and the
|
80
|
-
# operator (op) is usually 'ASC', 'DESC', or 'AS'.
|
81
|
-
def initialize(l, op, r = nil)
|
82
|
-
@l, @op, @r = l, op, r
|
83
|
-
end
|
84
|
-
|
85
|
-
# Delegate the creation of the resulting SQL to the given dataset,
|
86
|
-
# since it may be database dependent.
|
87
|
-
def to_s(ds)
|
88
|
-
ds.column_expr_sql(self)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
20
|
# Represents a complex SQL expression, with a given operator and one
|
93
21
|
# or more attributes (which may also be ComplexExpressions, forming
|
94
22
|
# a tree). This class is the backbone of the blockless filter support in
|
@@ -110,6 +38,9 @@ module Sequel
|
|
110
38
|
# Mathematical Operators used in NumericMethods
|
111
39
|
MATHEMATICAL_OPERATORS = [:+, :-, :/, :*]
|
112
40
|
|
41
|
+
# Mathematical Operators used in NumericMethods
|
42
|
+
BITWISE_OPERATORS = [:&, :|, :^, :<<, :>>]
|
43
|
+
|
113
44
|
# Inequality Operators used in InequalityMethods
|
114
45
|
INEQUALITY_OPERATORS = [:<, :>, :<=, :>=]
|
115
46
|
|
@@ -118,13 +49,14 @@ module Sequel
|
|
118
49
|
|
119
50
|
# Operator symbols that take exactly two arguments
|
120
51
|
TWO_ARITY_OPERATORS = [:'=', :'!=', :IS, :'IS NOT', :LIKE, :'NOT LIKE', \
|
121
|
-
:~, :'!~', :'~*', :'!~*', :IN, :'NOT IN', :ILIKE, :'NOT ILIKE'] +
|
52
|
+
:~, :'!~', :'~*', :'!~*', :IN, :'NOT IN', :ILIKE, :'NOT ILIKE'] + \
|
53
|
+
INEQUALITY_OPERATORS + BITWISE_OPERATORS
|
122
54
|
|
123
55
|
# Operator symbols that take one or more arguments
|
124
56
|
N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS
|
125
57
|
|
126
58
|
# Operator symbols that take one argument
|
127
|
-
ONE_ARITY_OPERATORS = [:NOT, :NOOP]
|
59
|
+
ONE_ARITY_OPERATORS = [:NOT, :NOOP, :'B~']
|
128
60
|
|
129
61
|
# An array of args for this object
|
130
62
|
attr_reader :args
|
@@ -168,6 +100,56 @@ module Sequel
|
|
168
100
|
end
|
169
101
|
end
|
170
102
|
|
103
|
+
# The base class for expressions that can be used in multiple places in
|
104
|
+
# the SQL query.
|
105
|
+
class GenericExpression < Expression
|
106
|
+
end
|
107
|
+
|
108
|
+
# The base class for expressions that are specific and can only be used
|
109
|
+
# in a certain place in the SQL query (ordering, selecting).
|
110
|
+
class SpecificExpression < Expression
|
111
|
+
end
|
112
|
+
|
113
|
+
### Modules ###
|
114
|
+
|
115
|
+
# Methods the create aliased identifiers
|
116
|
+
module AliasMethods
|
117
|
+
# Create an SQL column alias of the receiving column to the given alias.
|
118
|
+
def as(aliaz)
|
119
|
+
AliasedExpression.new(self, aliaz)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# This defines the bitwise methods &, |, ^, ~, <<, and >>. Because these
|
124
|
+
# methods overlap with the standard BooleanMethods methods, and they only
|
125
|
+
# make sense for numbers, they are only included in NumericExpression.
|
126
|
+
module BitwiseMethods
|
127
|
+
ComplexExpression::BITWISE_OPERATORS.each do |o|
|
128
|
+
define_method(o) do |ce|
|
129
|
+
case ce
|
130
|
+
when NumericExpression
|
131
|
+
NumericExpression.new(o, self, ce)
|
132
|
+
when ComplexExpression
|
133
|
+
raise(Sequel::Error, "cannot apply #{o} to a non-numeric expression")
|
134
|
+
else
|
135
|
+
NumericExpression.new(o, self, ce)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Do the bitwise compliment of the self
|
141
|
+
def ~
|
142
|
+
case self
|
143
|
+
when NumericExpression
|
144
|
+
NumericExpression.new(:'B~', self)
|
145
|
+
when ComplexExpression
|
146
|
+
raise(Sequel::Error, "cannot apply #{o} to a non-numeric expression")
|
147
|
+
else
|
148
|
+
NumericExpression.new(:'B~', self)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
171
153
|
# This module includes the methods that are defined on objects that can be
|
172
154
|
# used in a boolean context in SQL (Symbol, LiteralString, SQL::Function,
|
173
155
|
# and SQL::BooleanExpression).
|
@@ -193,6 +175,64 @@ module Sequel
|
|
193
175
|
end
|
194
176
|
end
|
195
177
|
|
178
|
+
# Holds methods that are used to cast objects to differen SQL types.
|
179
|
+
module CastMethods
|
180
|
+
# Cast the reciever to the given SQL type
|
181
|
+
def cast(sql_type)
|
182
|
+
IrregularFunction.new(:cast, self, :AS, sql_type.to_s.lit)
|
183
|
+
end
|
184
|
+
alias_method :cast_as, :cast
|
185
|
+
|
186
|
+
# Cast the reciever to the given SQL type (or integer if none given),
|
187
|
+
# and return the result as a NumericExpression.
|
188
|
+
def cast_numeric(sql_type = nil)
|
189
|
+
cast(sql_type || :integer).sql_number
|
190
|
+
end
|
191
|
+
|
192
|
+
# Cast the reciever to the given SQL type (or text if none given),
|
193
|
+
# and return the result as a StringExpression, so you can use +
|
194
|
+
# directly on the result for SQL string concatenation.
|
195
|
+
def cast_string(sql_type = nil)
|
196
|
+
cast(sql_type || :text).sql_string
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# This module includes the methods that are defined on objects that can be
|
201
|
+
# used in a numeric or string context in SQL (Symbol, LiteralString,
|
202
|
+
# SQL::Function, and SQL::StringExpression).
|
203
|
+
#
|
204
|
+
# This defines the >, <, >=, and <= methods.
|
205
|
+
module InequalityMethods
|
206
|
+
ComplexExpression::INEQUALITY_OPERATORS.each do |o|
|
207
|
+
define_method(o) do |ce|
|
208
|
+
case ce
|
209
|
+
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
|
210
|
+
raise(Error, "cannot apply #{o} to a boolean expression")
|
211
|
+
else
|
212
|
+
BooleanExpression.new(o, self, ce)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# This module augments the default initalize method for the
|
219
|
+
# ComplexExpression subclass it is included in, so that
|
220
|
+
# attempting to use boolean input when initializing a NumericExpression
|
221
|
+
# or StringExpression results in an error.
|
222
|
+
module NoBooleanInputMethods
|
223
|
+
# Raise an Error if one of the args would be boolean in an SQL
|
224
|
+
# context, otherwise call super.
|
225
|
+
def initialize(op, *args)
|
226
|
+
args.each do |a|
|
227
|
+
case a
|
228
|
+
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
|
229
|
+
raise(Error, "cannot apply #{op} to a boolean expression")
|
230
|
+
end
|
231
|
+
end
|
232
|
+
super
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
196
236
|
# This module includes the methods that are defined on objects that can be
|
197
237
|
# used in a numeric context in SQL (Symbol, LiteralString, SQL::Function,
|
198
238
|
# and SQL::NumericExpression).
|
@@ -213,6 +253,29 @@ module Sequel
|
|
213
253
|
end
|
214
254
|
end
|
215
255
|
|
256
|
+
# Methods that create OrderedExpressions, used for sorting by columns
|
257
|
+
# or more complex expressions.
|
258
|
+
module OrderMethods
|
259
|
+
# Mark the receiving SQL column as sorting in a descending fashion.
|
260
|
+
def desc
|
261
|
+
OrderedExpression.new(self)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Mark the receiving SQL column as sorting in an ascending fashion (generally a no-op).
|
265
|
+
def asc
|
266
|
+
OrderedExpression.new(self, false)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Methods that created QualifiedIdentifiers, used for qualifying column
|
271
|
+
# names with a table or table names with a schema.
|
272
|
+
module QualifyingMethods
|
273
|
+
# Qualify the current object with the given table/schema.
|
274
|
+
def qualify(ts)
|
275
|
+
QualifiedIdentifier.new(ts, self)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
216
279
|
# This module includes the methods that are defined on objects that can be
|
217
280
|
# used in a numeric context in SQL (Symbol, LiteralString, SQL::Function,
|
218
281
|
# and SQL::StringExpression).
|
@@ -243,41 +306,7 @@ module Sequel
|
|
243
306
|
end
|
244
307
|
end
|
245
308
|
|
246
|
-
|
247
|
-
# used in a numeric or string context in SQL (Symbol, LiteralString,
|
248
|
-
# SQL::Function, and SQL::StringExpression).
|
249
|
-
#
|
250
|
-
# This defines the >, <, >=, and <= methods.
|
251
|
-
module InequalityMethods
|
252
|
-
ComplexExpression::INEQUALITY_OPERATORS.each do |o|
|
253
|
-
define_method(o) do |ce|
|
254
|
-
case ce
|
255
|
-
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
|
256
|
-
raise(Error, "cannot apply #{o} to a boolean expression")
|
257
|
-
else
|
258
|
-
BooleanExpression.new(o, self, ce)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
# This module augments the default initalize method for the
|
265
|
-
# ComplexExpression subclass it is included in, so that
|
266
|
-
# attempting to use boolean input when initializing a NumericExpression
|
267
|
-
# or StringExpression results in an error.
|
268
|
-
module NoBooleanInputMethods
|
269
|
-
# Raise an Error if one of the args would be boolean in an SQL
|
270
|
-
# context, otherwise call super.
|
271
|
-
def initialize(op, *args)
|
272
|
-
args.each do |a|
|
273
|
-
case a
|
274
|
-
when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
|
275
|
-
raise(Error, "cannot apply #{op} to a boolean expression")
|
276
|
-
end
|
277
|
-
end
|
278
|
-
super
|
279
|
-
end
|
280
|
-
end
|
309
|
+
### Modules that include other modules ###
|
281
310
|
|
282
311
|
# This module includes other Sequel::SQL::*Methods modules and is
|
283
312
|
# included in other classes that are could be either booleans,
|
@@ -300,6 +329,16 @@ module Sequel
|
|
300
329
|
include StringMethods
|
301
330
|
include InequalityMethods
|
302
331
|
|
332
|
+
# Extract a datetime_part (e.g. year, month) from self:
|
333
|
+
#
|
334
|
+
# :date.extract(:year) # SQL: extract(year FROM date)
|
335
|
+
#
|
336
|
+
# Also has the benefit of returning the result as a
|
337
|
+
# NumericExpression instead of a generic ComplexExpression.
|
338
|
+
def extract(datetime_part)
|
339
|
+
IrregularFunction.new(:extract, datetime_part.to_s.lit, :FROM, self).sql_number
|
340
|
+
end
|
341
|
+
|
303
342
|
# Return a BooleanExpression representation of self.
|
304
343
|
def sql_boolean
|
305
344
|
BooleanExpression.new(:NOOP, self)
|
@@ -316,6 +355,48 @@ module Sequel
|
|
316
355
|
end
|
317
356
|
end
|
318
357
|
|
358
|
+
module SpecificExpressionMethods
|
359
|
+
include AliasMethods
|
360
|
+
include CastMethods
|
361
|
+
include OrderMethods
|
362
|
+
end
|
363
|
+
|
364
|
+
module GenericExpressionMethods
|
365
|
+
include SpecificExpressionMethods
|
366
|
+
include ComplexExpressionMethods
|
367
|
+
end
|
368
|
+
|
369
|
+
class ComplexExpression
|
370
|
+
include SpecificExpressionMethods
|
371
|
+
end
|
372
|
+
|
373
|
+
class GenericExpression
|
374
|
+
include GenericExpressionMethods
|
375
|
+
end
|
376
|
+
|
377
|
+
### Classes ###
|
378
|
+
|
379
|
+
# Represents an aliasing of an expression/column to a given name.
|
380
|
+
class AliasedExpression < SpecificExpression
|
381
|
+
# The expression to alias
|
382
|
+
attr_reader :expression
|
383
|
+
|
384
|
+
# The alias to use for the expression, not alias since that is
|
385
|
+
# a keyword in ruby.
|
386
|
+
attr_reader :aliaz
|
387
|
+
|
388
|
+
# default value.
|
389
|
+
def initialize(expression, aliaz)
|
390
|
+
@expression, @aliaz = expression, aliaz
|
391
|
+
end
|
392
|
+
|
393
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
394
|
+
# since it may be database dependent.
|
395
|
+
def to_s(ds)
|
396
|
+
ds.aliased_expression_sql(self)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
319
400
|
# Subclass of ComplexExpression where the expression results
|
320
401
|
# in a boolean value in SQL.
|
321
402
|
class BooleanExpression < ComplexExpression
|
@@ -378,49 +459,54 @@ module Sequel
|
|
378
459
|
end
|
379
460
|
end
|
380
461
|
|
381
|
-
#
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
462
|
+
# Represents an SQL CASE expression, used for conditions.
|
463
|
+
class CaseExpression < GenericExpression
|
464
|
+
# An array of all two pairs with the first element specifying the
|
465
|
+
# condition and the second element specifying the result.
|
466
|
+
attr_reader :conditions
|
467
|
+
|
468
|
+
# The default value if no conditions are true
|
469
|
+
attr_reader :default
|
470
|
+
|
471
|
+
# Create an object with the given conditions and
|
472
|
+
# default value.
|
473
|
+
def initialize(conditions, default)
|
474
|
+
raise(Sequel::Error, 'CaseExpression conditions must be an array with all_two_pairs') unless Array === conditions and conditions.all_two_pairs?
|
475
|
+
@conditions, @default = conditions, default
|
476
|
+
end
|
477
|
+
|
478
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
479
|
+
# since it may be database dependent.
|
480
|
+
def to_s(ds)
|
481
|
+
ds.case_expression_sql(self)
|
482
|
+
end
|
387
483
|
end
|
388
484
|
|
389
|
-
#
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
#
|
400
|
-
#
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
#
|
406
|
-
#
|
407
|
-
|
408
|
-
|
409
|
-
# if a case insensitive regular expression is used (//i), that particular
|
410
|
-
# pattern which will always be case insensitive.
|
411
|
-
def self.like(l, *ces)
|
412
|
-
case_insensitive = ces.extract_options![:case_insensitive]
|
413
|
-
ces.collect! do |ce|
|
414
|
-
op, expr = Regexp === ce ? [ce.casefold? || case_insensitive ? :'~*' : :~, ce.source] : [case_insensitive ? :ILIKE : :LIKE, ce.to_s]
|
415
|
-
BooleanExpression.new(op, l, expr)
|
416
|
-
end
|
417
|
-
ces.length == 1 ? ces.at(0) : BooleanExpression.new(:OR, *ces)
|
485
|
+
# Represents all columns in a given table, table.* in SQL
|
486
|
+
class ColumnAll < SpecificExpression
|
487
|
+
# The table containing the columns being selected
|
488
|
+
attr_reader :table
|
489
|
+
|
490
|
+
# Create an object with the given table
|
491
|
+
def initialize(table)
|
492
|
+
@table = table
|
493
|
+
end
|
494
|
+
|
495
|
+
# ColumnAll expressions are considered equivalent if they
|
496
|
+
# have the same class and string representation
|
497
|
+
def ==(x)
|
498
|
+
x.class == self.class && @table == x.table
|
499
|
+
end
|
500
|
+
|
501
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
502
|
+
# since it may be database dependent.
|
503
|
+
def to_s(ds)
|
504
|
+
ds.column_all_sql(self)
|
418
505
|
end
|
419
506
|
end
|
420
507
|
|
421
508
|
# Represents an SQL function call.
|
422
|
-
class Function <
|
423
|
-
include ComplexExpressionMethods
|
509
|
+
class Function < GenericExpression
|
424
510
|
# The array of arguments to pass to the function (may be blank)
|
425
511
|
attr_reader :args
|
426
512
|
|
@@ -445,9 +531,130 @@ module Sequel
|
|
445
531
|
end
|
446
532
|
end
|
447
533
|
|
534
|
+
# IrregularFunction is used for the SQL EXTRACT and CAST functions,
|
535
|
+
# which don't use regular function calling syntax. The IrregularFunction
|
536
|
+
# replaces the commas the regular function uses with a custom
|
537
|
+
# join string.
|
538
|
+
#
|
539
|
+
# This shouldn't be used directly, see CastMethods#cast and
|
540
|
+
# ComplexExpressionMethods#extract.
|
541
|
+
class IrregularFunction < Function
|
542
|
+
# The arguments to pass to the function (may be blank)
|
543
|
+
attr_reader :arg1, :arg2
|
544
|
+
|
545
|
+
# The SQL function to call
|
546
|
+
attr_reader :f
|
547
|
+
|
548
|
+
# The literal string to use in place of a comma to join arguments
|
549
|
+
attr_reader :joiner
|
550
|
+
|
551
|
+
# Set the attributes to the given arguments
|
552
|
+
def initialize(f, arg1, joiner, arg2)
|
553
|
+
@f, @arg1, @joiner, @arg2 = f, arg1, joiner, arg2
|
554
|
+
end
|
555
|
+
|
556
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
557
|
+
# since it may be database dependent.
|
558
|
+
def to_s(ds)
|
559
|
+
ds.irregular_function_sql(self)
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
# Represents an SQL JOIN clause, used for joining tables.
|
564
|
+
class JoinClause < SpecificExpression
|
565
|
+
# The type of join to do
|
566
|
+
attr_reader :join_type
|
567
|
+
|
568
|
+
# The actual table to join
|
569
|
+
attr_reader :table
|
570
|
+
|
571
|
+
# The table alias to use for the join, if any
|
572
|
+
attr_reader :table_alias
|
573
|
+
|
574
|
+
# Create an object with the given conditions and
|
575
|
+
# default value.
|
576
|
+
def initialize(join_type, table, table_alias = nil)
|
577
|
+
@join_type, @table, @table_alias = join_type, table, table_alias
|
578
|
+
end
|
579
|
+
|
580
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
581
|
+
# since it may be database dependent.
|
582
|
+
def to_s(ds)
|
583
|
+
ds.join_clause_sql(self)
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
# Represents an SQL JOIN table ON conditions clause.
|
588
|
+
class JoinOnClause < JoinClause
|
589
|
+
# The conditions for the join
|
590
|
+
attr_reader :on
|
591
|
+
|
592
|
+
# Create an object with the given conditions and
|
593
|
+
# default value.
|
594
|
+
def initialize(on, *args)
|
595
|
+
@on = on
|
596
|
+
super(*args)
|
597
|
+
end
|
598
|
+
|
599
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
600
|
+
# since it may be database dependent.
|
601
|
+
def to_s(ds)
|
602
|
+
ds.join_on_clause_sql(self)
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
# Represents an SQL JOIN table USING (columns) clause.
|
607
|
+
class JoinUsingClause < JoinClause
|
608
|
+
# The columns that appear both tables that should be equal
|
609
|
+
# for the conditions to match.
|
610
|
+
attr_reader :using
|
611
|
+
|
612
|
+
# Create an object with the given conditions and
|
613
|
+
# default value.
|
614
|
+
def initialize(using, *args)
|
615
|
+
@using = using
|
616
|
+
super(*args)
|
617
|
+
end
|
618
|
+
|
619
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
620
|
+
# since it may be database dependent.
|
621
|
+
def to_s(ds)
|
622
|
+
ds.join_using_clause_sql(self)
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
# Subclass of ComplexExpression where the expression results
|
627
|
+
# in a numeric value in SQL.
|
628
|
+
class NumericExpression < ComplexExpression
|
629
|
+
include BitwiseMethods
|
630
|
+
include NumericMethods
|
631
|
+
include InequalityMethods
|
632
|
+
include NoBooleanInputMethods
|
633
|
+
end
|
634
|
+
|
635
|
+
# Represents a column/expression to order the result set by.
|
636
|
+
class OrderedExpression < SpecificExpression
|
637
|
+
# The expression to order the result set by.
|
638
|
+
attr_reader :expression
|
639
|
+
|
640
|
+
# Whether the expression should order the result set in a descening manner
|
641
|
+
attr_reader :descending
|
642
|
+
|
643
|
+
# default value.
|
644
|
+
def initialize(expression, descending = true)
|
645
|
+
@expression, @descending = expression, descending
|
646
|
+
end
|
647
|
+
|
648
|
+
# Delegate the creation of the resulting SQL to the given dataset,
|
649
|
+
# since it may be database dependent.
|
650
|
+
def to_s(ds)
|
651
|
+
ds.ordered_expression_sql(self)
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
448
655
|
# Represents a qualified (column with table) reference. Used when
|
449
656
|
# joining tables to disambiguate columns.
|
450
|
-
class
|
657
|
+
class QualifiedIdentifier < GenericExpression
|
451
658
|
# The table and column to reference
|
452
659
|
attr_reader :table, :column
|
453
660
|
|
@@ -459,12 +666,44 @@ module Sequel
|
|
459
666
|
# Delegate the creation of the resulting SQL to the given dataset,
|
460
667
|
# since it may be database dependent.
|
461
668
|
def to_s(ds)
|
462
|
-
ds.
|
669
|
+
ds.qualified_identifier_sql(self)
|
463
670
|
end
|
464
671
|
end
|
465
672
|
|
673
|
+
# Subclass of ComplexExpression where the expression results
|
674
|
+
# in a text/string/varchar value in SQL.
|
675
|
+
class StringExpression < ComplexExpression
|
676
|
+
include StringMethods
|
677
|
+
include StringConcatenationMethods
|
678
|
+
include InequalityMethods
|
679
|
+
include NoBooleanInputMethods
|
680
|
+
|
681
|
+
# Creates a SQL pattern match exprssion. left (l) is the SQL string we
|
682
|
+
# are matching against, and ces are the patterns we are matching.
|
683
|
+
# The match succeeds if any of the patterns match (SQL OR). Patterns
|
684
|
+
# can be given as strings or regular expressions. Strings will cause
|
685
|
+
# the SQL LIKE operator to be used, and should be supported by most
|
686
|
+
# databases. Regular expressions will probably only work on MySQL
|
687
|
+
# and PostgreSQL, and SQL regular expression syntax is not fully compatible
|
688
|
+
# with ruby regular expression syntax, so be careful if using regular
|
689
|
+
# expressions.
|
690
|
+
#
|
691
|
+
# The pattern match will be case insensitive if the last argument is a hash
|
692
|
+
# with a key of :case_insensitive that is not false or nil. Also,
|
693
|
+
# if a case insensitive regular expression is used (//i), that particular
|
694
|
+
# pattern which will always be case insensitive.
|
695
|
+
def self.like(l, *ces)
|
696
|
+
case_insensitive = ces.extract_options![:case_insensitive]
|
697
|
+
ces.collect! do |ce|
|
698
|
+
op, expr = Regexp === ce ? [ce.casefold? || case_insensitive ? :'~*' : :~, ce.source] : [case_insensitive ? :ILIKE : :LIKE, ce.to_s]
|
699
|
+
BooleanExpression.new(op, l, expr)
|
700
|
+
end
|
701
|
+
ces.length == 1 ? ces.at(0) : BooleanExpression.new(:OR, *ces)
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
466
705
|
# Represents an SQL array access, with multiple possible arguments.
|
467
|
-
class Subscript <
|
706
|
+
class Subscript < GenericExpression
|
468
707
|
# The SQL array column
|
469
708
|
attr_reader :f
|
470
709
|
|
@@ -496,6 +735,7 @@ module Sequel
|
|
496
735
|
# LiteralStrings can use all of the SQL::ColumnMethods and the
|
497
736
|
# SQL::ComplexExpressionMethods.
|
498
737
|
class LiteralString < ::String
|
738
|
+
include SQL::OrderMethods
|
499
739
|
include SQL::ComplexExpressionMethods
|
500
740
|
end
|
501
741
|
end
|