sequel_core 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +74 -0
- data/COPYING +1 -0
- data/README +17 -6
- data/Rakefile +16 -21
- data/lib/sequel_core.rb +18 -28
- data/lib/sequel_core/adapters/ado.rb +3 -15
- data/lib/sequel_core/adapters/dbi.rb +1 -14
- data/lib/sequel_core/adapters/informix.rb +3 -3
- data/lib/sequel_core/adapters/jdbc.rb +2 -2
- data/lib/sequel_core/adapters/mysql.rb +39 -59
- data/lib/sequel_core/adapters/odbc.rb +18 -38
- data/lib/sequel_core/adapters/openbase.rb +1 -17
- data/lib/sequel_core/adapters/oracle.rb +1 -19
- data/lib/sequel_core/adapters/postgres.rb +20 -60
- data/lib/sequel_core/adapters/sqlite.rb +4 -8
- data/lib/sequel_core/connection_pool.rb +150 -0
- data/lib/sequel_core/core_ext.rb +41 -0
- data/lib/sequel_core/core_sql.rb +35 -38
- data/lib/sequel_core/database.rb +20 -17
- data/lib/sequel_core/dataset.rb +49 -80
- data/lib/sequel_core/dataset/callback.rb +11 -13
- data/lib/sequel_core/dataset/convenience.rb +18 -136
- data/lib/sequel_core/dataset/pagination.rb +81 -0
- data/lib/sequel_core/dataset/sequelizer.rb +5 -4
- data/lib/sequel_core/dataset/sql.rb +43 -33
- data/lib/sequel_core/deprecated.rb +200 -0
- data/lib/sequel_core/exceptions.rb +0 -14
- data/lib/sequel_core/object_graph.rb +199 -0
- data/lib/sequel_core/pretty_table.rb +27 -24
- data/lib/sequel_core/schema/generator.rb +16 -4
- data/lib/sequel_core/schema/sql.rb +5 -3
- data/lib/sequel_core/worker.rb +1 -1
- data/spec/adapters/informix_spec.rb +1 -47
- data/spec/adapters/mysql_spec.rb +85 -54
- data/spec/adapters/oracle_spec.rb +1 -57
- data/spec/adapters/postgres_spec.rb +66 -49
- data/spec/adapters/sqlite_spec.rb +4 -29
- data/spec/connection_pool_spec.rb +358 -0
- data/spec/core_sql_spec.rb +24 -19
- data/spec/database_spec.rb +13 -9
- data/spec/dataset_spec.rb +59 -78
- data/spec/object_graph_spec.rb +202 -0
- data/spec/pretty_table_spec.rb +1 -9
- data/spec/schema_generator_spec.rb +7 -1
- data/spec/schema_spec.rb +27 -0
- data/spec/sequelizer_spec.rb +2 -2
- data/spec/spec_helper.rb +4 -2
- metadata +16 -57
- data/lib/sequel_core/array_keys.rb +0 -322
- data/lib/sequel_core/model.rb +0 -8
- data/spec/array_keys_spec.rb +0 -682
@@ -1,19 +1,17 @@
|
|
1
1
|
module Sequel
|
2
2
|
class Dataset
|
3
|
+
# Module with empty methods that can be
|
4
|
+
# override to provide callback behavior
|
3
5
|
module Callback
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
return unless cbs = @opts[:callbacks]
|
14
|
-
return unless cb = cbs[name]
|
15
|
-
cb.each{|sym| send(sym, *args)}
|
16
|
-
end
|
6
|
+
private
|
7
|
+
# This is run inside .all, after all
|
8
|
+
# of the records have been loaded
|
9
|
+
# via .each, but before any block passed
|
10
|
+
# to all is called. It is called with
|
11
|
+
# a single argument, an array of all
|
12
|
+
# returned records.
|
13
|
+
def post_load(all_records)
|
14
|
+
end
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
@@ -3,15 +3,9 @@ require 'enumerator'
|
|
3
3
|
module Sequel
|
4
4
|
class Dataset
|
5
5
|
module Convenience
|
6
|
-
# Iterates through each record, converting it into a hash.
|
7
|
-
def each_hash(&block)
|
8
|
-
each {|a| block[a.to_hash]}
|
9
|
-
end
|
10
|
-
|
11
6
|
# Returns true if no records exists in the dataset
|
12
7
|
def empty?
|
13
8
|
db.dataset.where(exists).get(1) == nil
|
14
|
-
# count == 0
|
15
9
|
end
|
16
10
|
|
17
11
|
# Returns the first record in the dataset.
|
@@ -23,10 +17,10 @@ module Sequel
|
|
23
17
|
NAKED_HASH = {:naked => true}.freeze
|
24
18
|
|
25
19
|
# Returns the first value of the first reecord in the dataset.
|
26
|
-
# Returns
|
20
|
+
# Returns nil if dataset is empty.
|
27
21
|
def single_value(opts = nil)
|
28
22
|
opts = opts ? NAKED_HASH.merge(opts) : NAKED_HASH
|
29
|
-
#
|
23
|
+
# don't cache the columns
|
30
24
|
each(opts) {|r| @columns = nil; return r.values.first}
|
31
25
|
nil
|
32
26
|
end
|
@@ -104,97 +98,27 @@ module Sequel
|
|
104
98
|
end
|
105
99
|
end
|
106
100
|
|
107
|
-
# Returns a paginated dataset. The resulting dataset also provides the
|
108
|
-
# total number of pages (Dataset#page_count) and the current page number
|
109
|
-
# (Dataset#current_page), as well as Dataset#prev_page and Dataset#next_page
|
110
|
-
# for implementing pagination controls.
|
111
|
-
def paginate(page_no, page_size)
|
112
|
-
record_count = count
|
113
|
-
total_pages = (record_count / page_size.to_f).ceil
|
114
|
-
paginated = limit(page_size, (page_no - 1) * page_size)
|
115
|
-
paginated.set_pagination_info(page_no, page_size, record_count)
|
116
|
-
paginated
|
117
|
-
end
|
118
|
-
|
119
|
-
# Sets the pagination info
|
120
|
-
def set_pagination_info(page_no, page_size, record_count)
|
121
|
-
@current_page = page_no
|
122
|
-
@page_size = page_size
|
123
|
-
@pagination_record_count = record_count
|
124
|
-
@page_count = (record_count / page_size.to_f).ceil
|
125
|
-
end
|
126
|
-
|
127
|
-
def each_page(page_size)
|
128
|
-
record_count = count
|
129
|
-
total_pages = (record_count / page_size.to_f).ceil
|
130
|
-
|
131
|
-
(1..total_pages).each do |page_no|
|
132
|
-
paginated = limit(page_size, (page_no - 1) * page_size)
|
133
|
-
paginated.set_pagination_info(page_no, page_size, record_count)
|
134
|
-
yield paginated
|
135
|
-
end
|
136
|
-
|
137
|
-
self
|
138
|
-
end
|
139
|
-
|
140
|
-
attr_accessor :page_size, :page_count, :current_page, :pagination_record_count
|
141
|
-
|
142
|
-
# Returns the previous page number or nil if the current page is the first
|
143
|
-
def prev_page
|
144
|
-
current_page > 1 ? (current_page - 1) : nil
|
145
|
-
end
|
146
|
-
|
147
|
-
# Returns the next page number or nil if the current page is the last page
|
148
|
-
def next_page
|
149
|
-
current_page < page_count ? (current_page + 1) : nil
|
150
|
-
end
|
151
|
-
|
152
|
-
# Returns the page range
|
153
|
-
def page_range
|
154
|
-
1..page_count
|
155
|
-
end
|
156
|
-
|
157
|
-
# Returns the record range for the current page
|
158
|
-
def current_page_record_range
|
159
|
-
return (0..0) if @current_page > @page_count
|
160
|
-
|
161
|
-
a = 1 + (@current_page - 1) * @page_size
|
162
|
-
b = a + @page_size - 1
|
163
|
-
b = @pagination_record_count if b > @pagination_record_count
|
164
|
-
a..b
|
165
|
-
end
|
166
|
-
|
167
|
-
# Returns the number of records in the current page
|
168
|
-
def current_page_record_count
|
169
|
-
return 0 if @current_page > @page_count
|
170
|
-
|
171
|
-
a = 1 + (@current_page - 1) * @page_size
|
172
|
-
b = a + @page_size - 1
|
173
|
-
b = @pagination_record_count if b > @pagination_record_count
|
174
|
-
b - a + 1
|
175
|
-
end
|
176
|
-
|
177
101
|
# Returns the minimum value for the given column.
|
178
102
|
def min(column)
|
179
|
-
single_value(:select => [column.
|
103
|
+
single_value(:select => [:min[column].as(:v)])
|
180
104
|
end
|
181
105
|
|
182
106
|
# Returns the maximum value for the given column.
|
183
107
|
def max(column)
|
184
|
-
single_value(:select => [column.
|
108
|
+
single_value(:select => [:max[column].as(:v)])
|
185
109
|
end
|
186
110
|
|
187
111
|
# Returns the sum for the given column.
|
188
112
|
def sum(column)
|
189
|
-
single_value(:select => [column.
|
113
|
+
single_value(:select => [:sum[column].as(:v)])
|
190
114
|
end
|
191
115
|
|
192
116
|
# Returns the average value for the given column.
|
193
117
|
def avg(column)
|
194
|
-
single_value(:select => [column.
|
118
|
+
single_value(:select => [:avg[column].as(:v)])
|
195
119
|
end
|
196
120
|
|
197
|
-
COUNT_OF_ALL_AS_COUNT = :count['*'.lit].
|
121
|
+
COUNT_OF_ALL_AS_COUNT = :count['*'.lit].as(:count)
|
198
122
|
|
199
123
|
# Returns a dataset grouped by the given column with count by group.
|
200
124
|
def group_and_count(*columns)
|
@@ -204,15 +128,17 @@ module Sequel
|
|
204
128
|
# Returns a Range object made from the minimum and maximum values for the
|
205
129
|
# given column.
|
206
130
|
def range(column)
|
207
|
-
r = select(column.
|
208
|
-
|
131
|
+
if r = select(:min[column].as(:v1), :max[column].as(:v2)).first
|
132
|
+
(r[:v1]..r[:v2])
|
133
|
+
end
|
209
134
|
end
|
210
135
|
|
211
136
|
# Returns the interval between minimum and maximum values for the given
|
212
137
|
# column.
|
213
138
|
def interval(column)
|
214
|
-
r = select("(max(#{literal(column)}) - min(#{literal(column)})) AS v".lit).first
|
215
|
-
|
139
|
+
if r = select("(max(#{literal(column)}) - min(#{literal(column)})) AS v".lit).first
|
140
|
+
r[:v]
|
141
|
+
end
|
216
142
|
end
|
217
143
|
|
218
144
|
# Pretty prints the records in the dataset as plain-text table.
|
@@ -227,12 +153,11 @@ module Sequel
|
|
227
153
|
# first line. You can turn that off by passing false as the
|
228
154
|
# include_column_titles argument.
|
229
155
|
def to_csv(include_column_titles = true)
|
230
|
-
|
156
|
+
n = naked
|
157
|
+
cols = n.columns
|
231
158
|
csv = ''
|
232
|
-
if include_column_titles
|
233
|
-
|
234
|
-
end
|
235
|
-
records.each {|r| csv << "#{r.join(COMMA_SEPARATOR)}\r\n"}
|
159
|
+
csv << "#{cols.join(COMMA_SEPARATOR)}\r\n" if include_column_titles
|
160
|
+
n.each{|r| csv << "#{cols.collect{|c| r[c]}.join(COMMA_SEPARATOR)}\r\n"}
|
236
161
|
csv
|
237
162
|
end
|
238
163
|
|
@@ -317,49 +242,6 @@ module Sequel
|
|
317
242
|
clone(copy.opts)
|
318
243
|
end
|
319
244
|
|
320
|
-
MUTATION_RE = /^(.+)!$/.freeze
|
321
|
-
|
322
|
-
# Provides support for mutation methods (filter!, order!, etc.) and magic
|
323
|
-
# methods.
|
324
|
-
def method_missing(m, *args, &block)
|
325
|
-
if m.to_s =~ MUTATION_RE
|
326
|
-
m = $1.to_sym
|
327
|
-
super unless respond_to?(m)
|
328
|
-
copy = send(m, *args, &block)
|
329
|
-
super if copy.class != self.class
|
330
|
-
@opts.merge!(copy.opts)
|
331
|
-
self
|
332
|
-
elsif magic_method_missing(m)
|
333
|
-
send(m, *args)
|
334
|
-
else
|
335
|
-
super
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
MAGIC_METHODS = {
|
340
|
-
/^order_by_(.+)$/ => proc {|c| proc {order(c)}},
|
341
|
-
/^first_by_(.+)$/ => proc {|c| proc {order(c).first}},
|
342
|
-
/^last_by_(.+)$/ => proc {|c| proc {order(c).last}},
|
343
|
-
/^filter_by_(.+)$/ => proc {|c| proc {|v| filter(c => v)}},
|
344
|
-
/^all_by_(.+)$/ => proc {|c| proc {|v| filter(c => v).all}},
|
345
|
-
/^find_by_(.+)$/ => proc {|c| proc {|v| filter(c => v).first}},
|
346
|
-
/^group_by_(.+)$/ => proc {|c| proc {group(c)}},
|
347
|
-
/^count_by_(.+)$/ => proc {|c| proc {group_and_count(c)}}
|
348
|
-
}
|
349
|
-
|
350
|
-
# Checks if the given method name represents a magic method and
|
351
|
-
# defines it. Otherwise, nil is returned.
|
352
|
-
def magic_method_missing(m)
|
353
|
-
method_name = m.to_s
|
354
|
-
MAGIC_METHODS.each_pair do |r, p|
|
355
|
-
if method_name =~ r
|
356
|
-
impl = p[$1.to_sym]
|
357
|
-
return Dataset.class_def(m, &impl)
|
358
|
-
end
|
359
|
-
end
|
360
|
-
nil
|
361
|
-
end
|
362
|
-
|
363
245
|
def create_view(name)
|
364
246
|
@db.create_view(name, self)
|
365
247
|
end
|
@@ -386,4 +268,4 @@ module Sequel
|
|
386
268
|
end
|
387
269
|
end
|
388
270
|
end
|
389
|
-
end
|
271
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
class Dataset
|
5
|
+
# Returns a paginated dataset. The resulting dataset also provides the
|
6
|
+
# total number of pages (Dataset#page_count) and the current page number
|
7
|
+
# (Dataset#current_page), as well as Dataset#prev_page and Dataset#next_page
|
8
|
+
# for implementing pagination controls.
|
9
|
+
def paginate(page_no, page_size)
|
10
|
+
raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
|
11
|
+
record_count = count
|
12
|
+
total_pages = (record_count / page_size.to_f).ceil
|
13
|
+
paginated = limit(page_size, (page_no - 1) * page_size)
|
14
|
+
paginated.extend(Pagination)
|
15
|
+
paginated.set_pagination_info(page_no, page_size, record_count)
|
16
|
+
paginated
|
17
|
+
end
|
18
|
+
|
19
|
+
def each_page(page_size)
|
20
|
+
raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
|
21
|
+
record_count = count
|
22
|
+
total_pages = (record_count / page_size.to_f).ceil
|
23
|
+
|
24
|
+
(1..total_pages).each do |page_no|
|
25
|
+
paginated = limit(page_size, (page_no - 1) * page_size)
|
26
|
+
paginated.extend(Pagination)
|
27
|
+
paginated.set_pagination_info(page_no, page_size, record_count)
|
28
|
+
yield paginated
|
29
|
+
end
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
module Pagination
|
35
|
+
attr_accessor :page_size, :page_count, :current_page, :pagination_record_count
|
36
|
+
|
37
|
+
# Sets the pagination info
|
38
|
+
def set_pagination_info(page_no, page_size, record_count)
|
39
|
+
@current_page = page_no
|
40
|
+
@page_size = page_size
|
41
|
+
@pagination_record_count = record_count
|
42
|
+
@page_count = (record_count / page_size.to_f).ceil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the previous page number or nil if the current page is the first
|
46
|
+
def prev_page
|
47
|
+
current_page > 1 ? (current_page - 1) : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the next page number or nil if the current page is the last page
|
51
|
+
def next_page
|
52
|
+
current_page < page_count ? (current_page + 1) : nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the page range
|
56
|
+
def page_range
|
57
|
+
1..page_count
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the record range for the current page
|
61
|
+
def current_page_record_range
|
62
|
+
return (0..0) if @current_page > @page_count
|
63
|
+
|
64
|
+
a = 1 + (@current_page - 1) * @page_size
|
65
|
+
b = a + @page_size - 1
|
66
|
+
b = @pagination_record_count if b > @pagination_record_count
|
67
|
+
a..b
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the number of records in the current page
|
71
|
+
def current_page_record_count
|
72
|
+
return 0 if @current_page > @page_count
|
73
|
+
|
74
|
+
a = 1 + (@current_page - 1) * @page_size
|
75
|
+
b = a + @page_size - 1
|
76
|
+
b = @pagination_record_count if b > @pagination_record_count
|
77
|
+
b - a + 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -4,7 +4,7 @@ class Sequel::Dataset
|
|
4
4
|
# blocks, e.g.:
|
5
5
|
#
|
6
6
|
# DB[:items].filter {:price < 100}
|
7
|
-
# DB[:items].filter {:category == 'ruby' && :date <
|
7
|
+
# DB[:items].filter {:category == 'ruby' && :date < Date.today - 7}
|
8
8
|
#
|
9
9
|
# Block filters can refer to literals, variables, constants, arguments,
|
10
10
|
# instance variables or anything else in order to create parameterized
|
@@ -20,6 +20,7 @@ class Sequel::Dataset
|
|
20
20
|
# sudo gem install parsetree
|
21
21
|
# sudo gem install ruby2ruby
|
22
22
|
module Sequelizer
|
23
|
+
private
|
23
24
|
# Formats an comparison expression involving a left value and a right
|
24
25
|
# value. Comparison expressions differ according to the class of the right
|
25
26
|
# value. The stock implementation supports Range (inclusive and exclusive),
|
@@ -311,7 +312,7 @@ class Sequel::Dataset
|
|
311
312
|
|
312
313
|
JOIN_AND = " AND ".freeze
|
313
314
|
JOIN_COMMA = ", ".freeze
|
314
|
-
|
315
|
+
|
315
316
|
def pt_expr(e, b, opts = {}) #:nodoc:
|
316
317
|
case e[0]
|
317
318
|
when :not # negation: !x, (x != y), (x !~ y)
|
@@ -346,7 +347,7 @@ end
|
|
346
347
|
|
347
348
|
class Proc
|
348
349
|
def to_sql(dataset, opts = {})
|
349
|
-
dataset.pt_expr
|
350
|
+
dataset.send(:pt_expr, to_sexp[2], self.binding, opts)
|
350
351
|
end
|
351
352
|
end
|
352
353
|
|
@@ -379,4 +380,4 @@ class Proc
|
|
379
380
|
c = Class.new {define_method(:m, &block)}
|
380
381
|
ParseTree.translate(c, :m)[2]
|
381
382
|
end
|
382
|
-
end
|
383
|
+
end
|
@@ -8,8 +8,8 @@ module Sequel
|
|
8
8
|
# behavior.
|
9
9
|
def quote_column_ref(name); name.to_s; end
|
10
10
|
|
11
|
-
ALIASED_REGEXP =
|
12
|
-
QUALIFIED_REGEXP =
|
11
|
+
ALIASED_REGEXP = /\A(.*)\s(.*)\z/.freeze
|
12
|
+
QUALIFIED_REGEXP = /\A(.*)\.(.*)\z/.freeze
|
13
13
|
|
14
14
|
# Returns a qualified column name (including a table name) if the column
|
15
15
|
# name isn't already qualified.
|
@@ -100,7 +100,7 @@ module Sequel
|
|
100
100
|
# Time (as an SQL TIMESTAMP), Date (as an SQL DATE), Dataset (as a
|
101
101
|
# subquery) and nil (AS NULL).
|
102
102
|
#
|
103
|
-
# dataset.literal("abc'def") #=> "'abc''def'"
|
103
|
+
# dataset.literal("abc'def\\") #=> "'abc''def\\\\'"
|
104
104
|
# dataset.literal(:items__id) #=> "items.id"
|
105
105
|
# dataset.literal([1, 2, 3]) => "(1, 2, 3)"
|
106
106
|
# dataset.literal(DB[:items]) => "(SELECT * FROM items)"
|
@@ -111,7 +111,7 @@ module Sequel
|
|
111
111
|
when LiteralString
|
112
112
|
v
|
113
113
|
when String
|
114
|
-
"'#{v.gsub(/'/, "''")}'"
|
114
|
+
"'#{v.gsub(/\\/, "\\\\\\\\").gsub(/'/, "''")}'"
|
115
115
|
when Integer, Float
|
116
116
|
v.to_s
|
117
117
|
when BigDecimal
|
@@ -161,6 +161,7 @@ module Sequel
|
|
161
161
|
end
|
162
162
|
parenthesize ? "(#{fmt})" : fmt
|
163
163
|
end
|
164
|
+
private :qualified_column_name, :column_list, :table_ref, :source_list, :expression_list
|
164
165
|
|
165
166
|
# Returns a copy of the dataset with the source changed.
|
166
167
|
def from(*source)
|
@@ -407,24 +408,18 @@ module Sequel
|
|
407
408
|
}
|
408
409
|
|
409
410
|
# Returns a join clause based on the specified join type and condition.
|
410
|
-
def join_expr(type, table, expr)
|
411
|
-
join_type = JOIN_TYPES[type || :inner]
|
412
|
-
unless join_type
|
413
|
-
raise Error::InvalidJoinType, "Invalid join type: #{type}"
|
414
|
-
end
|
411
|
+
def join_expr(type, table, expr, options)
|
412
|
+
raise(Error::InvalidJoinType, "Invalid join type: #{type}") unless join_type = JOIN_TYPES[type || :inner]
|
415
413
|
|
416
|
-
|
414
|
+
table_alias = options[:table_alias]
|
417
415
|
|
418
416
|
join_conditions = {}
|
419
417
|
expr.each do |k, v|
|
420
|
-
k = qualified_column_name(k, table) if k.is_a?(Symbol)
|
418
|
+
k = qualified_column_name(k, table_alias || table) if k.is_a?(Symbol)
|
421
419
|
v = qualified_column_name(v, @opts[:last_joined_table] || first_source) if v.is_a?(Symbol)
|
422
420
|
join_conditions[k] = v
|
423
421
|
end
|
424
|
-
if
|
425
|
-
table = "(#{table.sql}) t1"
|
426
|
-
end
|
427
|
-
" #{join_type} #{table} ON #{expression_list(join_conditions)}"
|
422
|
+
" #{join_type} #{table} #{"#{table_alias} " if table_alias}ON #{expression_list(join_conditions)}"
|
428
423
|
end
|
429
424
|
|
430
425
|
# Returns a joined dataset with the specified join type and condition.
|
@@ -432,9 +427,20 @@ module Sequel
|
|
432
427
|
unless expr.is_a?(Hash)
|
433
428
|
expr = {expr => :id}
|
434
429
|
end
|
435
|
-
|
436
|
-
|
437
|
-
|
430
|
+
options = {}
|
431
|
+
|
432
|
+
if Dataset === table
|
433
|
+
table = "(#{table.sql})"
|
434
|
+
table_alias_num = @opts[:num_dataset_joins] || 1
|
435
|
+
options[:table_alias] = "t#{table_alias_num}"
|
436
|
+
elsif table.respond_to?(:table_name)
|
437
|
+
table = table.table_name
|
438
|
+
end
|
439
|
+
|
440
|
+
clause = join_expr(type, table, expr, options)
|
441
|
+
opts = {:join => @opts[:join] ? @opts[:join] + clause : clause, :last_joined_table => options[:table_alias] || table}
|
442
|
+
opts[:num_dataset_joins] = table_alias_num + 1 if table_alias_num
|
443
|
+
clone(opts)
|
438
444
|
end
|
439
445
|
|
440
446
|
# Returns a LEFT OUTER joined dataset.
|
@@ -525,6 +531,11 @@ module Sequel
|
|
525
531
|
end
|
526
532
|
alias_method :sql, :select_sql
|
527
533
|
|
534
|
+
# Returns the SQL for formatting an insert statement with default values
|
535
|
+
def insert_default_values_sql
|
536
|
+
"INSERT INTO #{source_list(@opts[:from])} DEFAULT VALUES"
|
537
|
+
end
|
538
|
+
|
528
539
|
# Formats an INSERT statement using the given values. If a hash is given,
|
529
540
|
# the resulting statement includes column names. If no values are given,
|
530
541
|
# the resulting statement includes a DEFAULT VALUES clause.
|
@@ -535,7 +546,7 @@ module Sequel
|
|
535
546
|
# 'INSERT INTO items (a, b) VALUES (1, 2)'
|
536
547
|
def insert_sql(*values)
|
537
548
|
if values.empty?
|
538
|
-
|
549
|
+
insert_default_values_sql
|
539
550
|
else
|
540
551
|
values = values[0] if values.size == 1
|
541
552
|
|
@@ -543,32 +554,31 @@ module Sequel
|
|
543
554
|
if @transform && (values.is_a?(Hash) || (values.is_a?(Array) && values.keys))
|
544
555
|
values = transform_save(values)
|
545
556
|
end
|
557
|
+
from = source_list(@opts[:from])
|
546
558
|
|
547
559
|
case values
|
548
|
-
when Sequel::Model
|
549
|
-
insert_sql(values.values)
|
550
560
|
when Array
|
551
561
|
if values.empty?
|
552
|
-
|
553
|
-
elsif values.keys
|
554
|
-
fl = values.keys.map {|f| literal(f.is_a?(String) ? f.to_sym : f)}
|
555
|
-
vl = values.values.map {|v| literal(v)}
|
556
|
-
"INSERT INTO #{@opts[:from]} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
|
562
|
+
insert_default_values_sql
|
557
563
|
else
|
558
|
-
"INSERT INTO #{
|
564
|
+
"INSERT INTO #{from} VALUES (#{literal(values)})"
|
559
565
|
end
|
560
566
|
when Hash
|
561
567
|
if values.empty?
|
562
|
-
|
568
|
+
insert_default_values_sql
|
563
569
|
else
|
564
570
|
fl, vl = [], []
|
565
571
|
values.each {|k, v| fl << literal(k.is_a?(String) ? k.to_sym : k); vl << literal(v)}
|
566
|
-
"INSERT INTO #{
|
572
|
+
"INSERT INTO #{from} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
|
567
573
|
end
|
568
574
|
when Dataset
|
569
|
-
"INSERT INTO #{
|
575
|
+
"INSERT INTO #{from} #{literal(values)}"
|
570
576
|
else
|
571
|
-
|
577
|
+
if values.respond_to?(:values)
|
578
|
+
insert_sql(values.values)
|
579
|
+
else
|
580
|
+
"INSERT INTO #{from} VALUES (#{literal(values)})"
|
581
|
+
end
|
572
582
|
end
|
573
583
|
end
|
574
584
|
end
|
@@ -599,7 +609,7 @@ module Sequel
|
|
599
609
|
raise Error::InvalidOperation, "A joined dataset cannot be updated"
|
600
610
|
end
|
601
611
|
|
602
|
-
sql = "UPDATE #{@opts[:from]} SET "
|
612
|
+
sql = "UPDATE #{source_list(@opts[:from])} SET "
|
603
613
|
if block
|
604
614
|
sql << block.to_sql(self, :comma_separated => true)
|
605
615
|
else
|
@@ -639,7 +649,7 @@ module Sequel
|
|
639
649
|
raise Error::InvalidOperation, "Joined datasets cannot be deleted from"
|
640
650
|
end
|
641
651
|
|
642
|
-
sql = "DELETE FROM #{opts[:from]}"
|
652
|
+
sql = "DELETE FROM #{source_list(opts[:from])}"
|
643
653
|
|
644
654
|
if where = opts[:where]
|
645
655
|
sql << " WHERE #{where}"
|