sql-maker 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +23 -0
- data/Rakefile +14 -0
- data/lib/sql-maker.rb +5 -0
- data/lib/sql/maker.rb +676 -0
- data/lib/sql/maker/condition.rb +378 -0
- data/lib/sql/maker/error.rb +3 -0
- data/lib/sql/maker/helper.rb +22 -0
- data/lib/sql/maker/quoting.rb +138 -0
- data/lib/sql/maker/select.rb +544 -0
- data/lib/sql/maker/select/oracle.rb +30 -0
- data/lib/sql/maker/select_set.rb +194 -0
- data/lib/sql/maker/util.rb +54 -0
- data/lib/sql/query_maker.rb +429 -0
- data/scripts/perl2ruby.rb +34 -0
- data/spec/maker/bind_param_spec.rb +62 -0
- data/spec/maker/condition/add_raw_spec.rb +29 -0
- data/spec/maker/condition/compose_empty_spec.rb +72 -0
- data/spec/maker/condition/empty_values_spec.rb +25 -0
- data/spec/maker/condition/make_term_spec.rb +38 -0
- data/spec/maker/condition/where_spec.rb +35 -0
- data/spec/maker/delete_spec.rb +116 -0
- data/spec/maker/insert_empty_spec.rb +23 -0
- data/spec/maker/insert_spec.rb +61 -0
- data/spec/maker/new_line_spec.rb +9 -0
- data/spec/maker/select/oracle/oracle_spec.rb +16 -0
- data/spec/maker/select/pod_select_spec.rb +34 -0
- data/spec/maker/select/statement_spec.rb +805 -0
- data/spec/maker/select_set_spec.rb +294 -0
- data/spec/maker/select_spec.rb +470 -0
- data/spec/maker/simple_spec.rb +54 -0
- data/spec/maker/strict_spec.rb +45 -0
- data/spec/maker/subquery_spec.rb +77 -0
- data/spec/maker/update_spec.rb +138 -0
- data/spec/maker/util_spec.rb +6 -0
- data/spec/maker/where_spec.rb +28 -0
- data/spec/query_maker/and_using_hash_spec.rb +13 -0
- data/spec/query_maker/cheatsheet_spec.rb +32 -0
- data/spec/query_maker/column_bind_spec.rb +55 -0
- data/spec/query_maker/refs_in_bind_spec.rb +19 -0
- data/spec/spec_helper.rb +15 -0
- data/sql-maker.gemspec +25 -0
- metadata +185 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 913d95f6a4b16c768820651f43606bad4a1e6d48
|
4
|
+
data.tar.gz: a9a05ffd8835ac0626bfc69f440df1f666f25c8e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aeb4c999c4a6482778cf33c1a4434c6e3bbcfd9562e14c07873a5da7dd700dbe0d380d0b0bd223df094ce5e1463a36ad9db2d9e59ef953bbf67ca6f9cba61d19
|
7
|
+
data.tar.gz: ce05861fe69d9aa7557b1b0491a5f2191ed711ad2435467a9b2edc1debee6a98e17f4845c68bfb7400eae6f8014c48654675ef1400100b0fe49c9ce120763968
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Naotoshi Seo
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# ruby-sql-maker
|
2
|
+
|
3
|
+
[](http://travis-ci.org/sonots/ruby-sql-maker)
|
4
|
+
[](https://coveralls.io/r/sonots/ruby-sql-maker?branch=master)
|
5
|
+
|
6
|
+
SQL Builder for Ruby
|
7
|
+
|
8
|
+
## ChangeLog
|
9
|
+
|
10
|
+
See [CHANGELOG.md](CHANGELOG.md) for details.
|
11
|
+
|
12
|
+
## Contributing
|
13
|
+
|
14
|
+
1. Fork it
|
15
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
16
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
17
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
18
|
+
5. Create new [Pull Request](../../pull/new/master)
|
19
|
+
|
20
|
+
## Copyright
|
21
|
+
|
22
|
+
Copyright (c) 2014 Naotoshi Seo. See [LICENSE.txt](LICENSE.txt) for details.
|
23
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rspec/core'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
6
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
7
|
+
end
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
desc 'Open an irb session preloaded with the gem library'
|
11
|
+
task :console do
|
12
|
+
sh 'irb -rubygems -I lib -r sql-maker'
|
13
|
+
end
|
14
|
+
task :c => :console
|
data/lib/sql-maker.rb
ADDED
data/lib/sql/maker.rb
ADDED
@@ -0,0 +1,676 @@
|
|
1
|
+
require 'sql/maker/select'
|
2
|
+
require 'sql/maker/select/oracle'
|
3
|
+
require 'sql/maker/condition'
|
4
|
+
require 'sql/maker/util'
|
5
|
+
|
6
|
+
class SQL::Maker
|
7
|
+
include SQL::Maker::Util
|
8
|
+
|
9
|
+
# todo
|
10
|
+
# def self.load_plugin(role)
|
11
|
+
# load "sql/maker/plugin/#{role}.rb"
|
12
|
+
# self.include "SQL::Maker::Plugin::#{role.camelize}"
|
13
|
+
# end
|
14
|
+
|
15
|
+
attr_accessor :quote_char, :select_class, :name_sep, :new_line, :strict, :driver, :auto_bind
|
16
|
+
|
17
|
+
def initialize(args)
|
18
|
+
unless @driver = args[:driver].to_s.downcase
|
19
|
+
croak(":driver is required for creating new instance of SQL::Maker")
|
20
|
+
end
|
21
|
+
unless @quote_char = args[:quote_char]
|
22
|
+
@quote_char =
|
23
|
+
if driver.to_s == 'mysql'
|
24
|
+
%q{`}
|
25
|
+
else
|
26
|
+
%q{"}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@select_class = @driver == 'oracle' ? SQL::Maker::Select::Oracle : SQL::Maker::Select
|
30
|
+
|
31
|
+
@name_sep = args[:name_sep] || ','
|
32
|
+
@new_line = args[:new_line] || "\n"
|
33
|
+
@strict = args[:strict] || false
|
34
|
+
@auto_bind = args[:auto_bind] || false # apply client-side prepared statement binding autocatically
|
35
|
+
end
|
36
|
+
|
37
|
+
def new_condition
|
38
|
+
SQL::Maker::Condition.new(
|
39
|
+
:quote_char => self.quote_char,
|
40
|
+
:name_sep => self.name_sep,
|
41
|
+
:strict => self.strict,
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def new_select(args = {})
|
46
|
+
return self.select_class.new({
|
47
|
+
:name_sep => self.name_sep,
|
48
|
+
:quote_char => self.quote_char,
|
49
|
+
:new_line => self.new_line,
|
50
|
+
:strict => self.strict,
|
51
|
+
}.merge(args))
|
52
|
+
end
|
53
|
+
|
54
|
+
def insert(*args)
|
55
|
+
table, values, opt =
|
56
|
+
if args.size == 1 and args.first.is_a?(Hash)
|
57
|
+
args = args.first.dup
|
58
|
+
[args.delete(:table), args.delete(:values) || {}, args]
|
59
|
+
else
|
60
|
+
[args[0], args[1] || {}, args[2] || {}]
|
61
|
+
end
|
62
|
+
|
63
|
+
prefix = opt[:prefix] || 'INSERT INTO'
|
64
|
+
|
65
|
+
quoted_table = self._quote(table)
|
66
|
+
quoted_columns = []
|
67
|
+
columns = []
|
68
|
+
bind_columns = []
|
69
|
+
|
70
|
+
while true
|
71
|
+
col, val =
|
72
|
+
if values.is_a?(Hash)
|
73
|
+
values.shift
|
74
|
+
elsif values.is_a?(Array)
|
75
|
+
values.slice!(0, 2)
|
76
|
+
elsif values.nil?
|
77
|
+
[nil, nil]
|
78
|
+
else
|
79
|
+
[values.first, nil]
|
80
|
+
end
|
81
|
+
break unless col
|
82
|
+
quoted_columns += [self._quote(col)]
|
83
|
+
if val.respond_to?(:as_sql)
|
84
|
+
columns += [val.as_sql(nil, Proc.new {|e| self._quote(e) })]
|
85
|
+
bind_columns += val.bind
|
86
|
+
else
|
87
|
+
croak("cannot pass in an unblessed ref as an argument in strict mode") if self.strict
|
88
|
+
if val.is_a?(Hash)
|
89
|
+
# builder.insert(:foo => { :created_on => ["NOW()"] })
|
90
|
+
columns += [val]
|
91
|
+
elsif val.is_a?(Array)
|
92
|
+
# builder.insert( :foo => [ 'UNIX_TIMESTAMP(?)', '2011-04-12 00:34:12' ] )
|
93
|
+
stmt, sub_bind = [val.first, val[1..-1]]
|
94
|
+
columns += [stmt]
|
95
|
+
bind_columns += sub_bind
|
96
|
+
else
|
97
|
+
# normal values
|
98
|
+
columns += ['?']
|
99
|
+
bind_columns += [val]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Insert an empty record in SQLite.
|
105
|
+
# ref. https://github.com/tokuhirom/SQL-Maker/issues/11
|
106
|
+
if self.driver == 'sqlite' && columns.empty?
|
107
|
+
sql = "#{prefix} #{quoted_table}" + self.new_line + 'DEFAULT VALUES'
|
108
|
+
return [sql, []]
|
109
|
+
end
|
110
|
+
|
111
|
+
sql = "#{prefix} #{quoted_table}" + self.new_line
|
112
|
+
sql += '(' + quoted_columns.join(', ') + ')' + self.new_line +
|
113
|
+
'VALUES (' + columns.join(', ') + ')'
|
114
|
+
|
115
|
+
@auto_bind ? bind_param(sql, bind_columns) : [sql, bind_columns]
|
116
|
+
end
|
117
|
+
|
118
|
+
def _quote(label)
|
119
|
+
SQL::Maker::Util::quote_identifier(label, self.quote_char, self.name_sep)
|
120
|
+
end
|
121
|
+
|
122
|
+
def delete(*args)
|
123
|
+
table, where, opt =
|
124
|
+
if args.size == 1 and args.first.is_a?(Hash)
|
125
|
+
args = args.first.dup
|
126
|
+
[args.delete(:table), args.delete(:where) || {}, args]
|
127
|
+
else
|
128
|
+
[args[0], args[1] || {}, args[2] || {}]
|
129
|
+
end
|
130
|
+
|
131
|
+
w = self._make_where_clause(where)
|
132
|
+
quoted_table = self._quote(table)
|
133
|
+
sql = "DELETE FROM #{quoted_table}"
|
134
|
+
if opt[:using]
|
135
|
+
# bulder.delete('foo', \%where, { :using => 'bar' })
|
136
|
+
# bulder.delete('foo', \%where, { :using => ['bar', 'qux'] })
|
137
|
+
tables = array_wrap(opt[:using])
|
138
|
+
sql += " USING " + tables.map {|t| self._quote(t) }.join(', ')
|
139
|
+
end
|
140
|
+
sql += w[0]
|
141
|
+
|
142
|
+
@auto_bind ? bind_param(sql, w[1]) : [sql, w[1]]
|
143
|
+
end
|
144
|
+
|
145
|
+
def update(*args)
|
146
|
+
table, values, where, opt =
|
147
|
+
if args.size == 1 and args.first.is_a?(Hash)
|
148
|
+
args = args.first.dup
|
149
|
+
[args.delete(:table), args.delete(:set) || {}, args.delete(:where) || {}, args]
|
150
|
+
else
|
151
|
+
[args[0], args[1] || {}, args[2] || {}, args[3] || {}]
|
152
|
+
end
|
153
|
+
|
154
|
+
columns, bind_columns = self.make_set_clause(values)
|
155
|
+
|
156
|
+
w = self._make_where_clause(where)
|
157
|
+
bind_columns += array_wrap(w[1])
|
158
|
+
|
159
|
+
quoted_table = self._quote(table)
|
160
|
+
sql = "UPDATE #{quoted_table} SET " + columns.join(', ') + w[0]
|
161
|
+
|
162
|
+
@auto_bind ? bind_param(sql, bind_columns) : [sql, bind_columns]
|
163
|
+
end
|
164
|
+
|
165
|
+
# make "SET" clause.
|
166
|
+
def make_set_clause(args)
|
167
|
+
columns = []
|
168
|
+
bind_columns = []
|
169
|
+
while true
|
170
|
+
col, val =
|
171
|
+
if args.is_a?(Hash)
|
172
|
+
args.shift
|
173
|
+
elsif args.is_a?(Array)
|
174
|
+
args.slice!(0, 2)
|
175
|
+
else
|
176
|
+
[args, nil]
|
177
|
+
end
|
178
|
+
break unless col
|
179
|
+
quoted_col = self._quote(col)
|
180
|
+
if val.respond_to?(:as_sql)
|
181
|
+
columns += ["#{quoted_col} = " + val.as_sql(nil, Proc.new {|label| self._quote(label) })]
|
182
|
+
bind_columns += val.bind
|
183
|
+
else
|
184
|
+
if self.strict
|
185
|
+
croak("cannot pass in an unblessed ref as an argument in strict mode")
|
186
|
+
if val.is_a?(Hash)
|
187
|
+
# builder.update(:foo => { :created_on => \"NOW()" })
|
188
|
+
# columns += ["quoted_col = " + $val
|
189
|
+
end
|
190
|
+
elsif val.is_a?(Array)
|
191
|
+
# builder.update( :foo => \[ 'VALUES(foo) + ?', 10 ] )
|
192
|
+
stmt, sub_bind = [val.first, val[1..-1]]
|
193
|
+
columns += ["#{quoted_col} = " + stmt]
|
194
|
+
bind_columns += sub_bind
|
195
|
+
else
|
196
|
+
# normal values
|
197
|
+
columns += ["#{quoted_col} = ?"]
|
198
|
+
bind_columns += [val]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
return [columns, bind_columns]
|
203
|
+
end
|
204
|
+
|
205
|
+
def where(where)
|
206
|
+
cond = self._make_where_condition(where)
|
207
|
+
return [cond.as_sql, cond.bind]
|
208
|
+
end
|
209
|
+
|
210
|
+
def _make_where_condition(where = nil)
|
211
|
+
return self.new_condition unless where
|
212
|
+
if where.respond_to?(:as_sql)
|
213
|
+
return where
|
214
|
+
end
|
215
|
+
|
216
|
+
cond = self.new_condition
|
217
|
+
while true
|
218
|
+
col, val =
|
219
|
+
if where.is_a?(Hash)
|
220
|
+
where.shift
|
221
|
+
elsif where.is_a?(Array)
|
222
|
+
where.slice!(0, 2)
|
223
|
+
else
|
224
|
+
[where, nil]
|
225
|
+
end
|
226
|
+
break unless col
|
227
|
+
cond.add(col => val)
|
228
|
+
end
|
229
|
+
return cond
|
230
|
+
end
|
231
|
+
|
232
|
+
def _make_where_clause(where = nil)
|
233
|
+
return ['', []] unless where
|
234
|
+
|
235
|
+
w = self._make_where_condition(where)
|
236
|
+
sql = w.as_sql
|
237
|
+
return [sql.empty? ? "" : " WHERE #{sql}", array_wrap(w.bind)]
|
238
|
+
end
|
239
|
+
|
240
|
+
# my(stmt, @bind) = sql−>select(table, \@fields, \%where, \%opt)
|
241
|
+
def select(*args)
|
242
|
+
stmt = self.select_query(*args)
|
243
|
+
|
244
|
+
@auto_bind ? bind_param(stmt.as_sql, stmt.bind) : [stmt.as_sql, stmt.bind]
|
245
|
+
end
|
246
|
+
|
247
|
+
def select_query(*args)
|
248
|
+
table, fields, where, opt =
|
249
|
+
if args.size == 1 and args.first.is_a?(Hash)
|
250
|
+
args = args.first.dup
|
251
|
+
[args.delete(:table), args.delete(:fields) || [], args.delete(:where) || {}, args]
|
252
|
+
else
|
253
|
+
[args[0], args[1] || [], args[2] || {}, args[3] || {}]
|
254
|
+
end
|
255
|
+
|
256
|
+
unless fields.is_a?(Array)
|
257
|
+
croak("SQL::Maker::select_query: fields should be Array")
|
258
|
+
end
|
259
|
+
|
260
|
+
stmt = self.new_select
|
261
|
+
fields.each do |field|
|
262
|
+
stmt.add_select(field)
|
263
|
+
end
|
264
|
+
|
265
|
+
if table
|
266
|
+
if table.is_a?(Array)
|
267
|
+
table.each do |t|
|
268
|
+
stmt.add_from(t)
|
269
|
+
end
|
270
|
+
else
|
271
|
+
stmt.add_from( table )
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
stmt.prefix(opt[:prefix]) if opt[:prefix]
|
276
|
+
|
277
|
+
if where
|
278
|
+
stmt.set_where(self._make_where_condition(where))
|
279
|
+
end
|
280
|
+
|
281
|
+
if joins = opt[:joins]
|
282
|
+
joins.each do |join|
|
283
|
+
stmt.add_join(join)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
if o = opt[:order_by]
|
288
|
+
if o.is_a?(Array)
|
289
|
+
o.each do |order|
|
290
|
+
if order.is_a?(Hash)
|
291
|
+
# Skinny-ish [{:foo => 'DESC'}, {:bar => 'ASC'}]
|
292
|
+
stmt.add_order_by(order)
|
293
|
+
else
|
294
|
+
# just ['foo DESC', 'bar ASC']
|
295
|
+
stmt.add_order_by(order)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
elsif o.is_a?(Hash)
|
299
|
+
# Skinny-ish {:foo => 'DESC'}
|
300
|
+
stmt.add_order_by(o)
|
301
|
+
else
|
302
|
+
# just 'foo DESC, bar ASC'
|
303
|
+
stmt.add_order_by(o)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
if o = opt[:group_by]
|
307
|
+
if o.is_a?(Array)
|
308
|
+
o.each do | group|
|
309
|
+
if group.is_a?(Hash)
|
310
|
+
# Skinny-ish [{:foo => 'DESC'}, {:bar => 'ASC'}]
|
311
|
+
stmt.add_group_by(group)
|
312
|
+
else
|
313
|
+
# just ['foo DESC', 'bar ASC']
|
314
|
+
stmt.add_group_by(group)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
elsif o.is_a?(Hash)
|
318
|
+
# Skinny-ish {:foo => 'DESC'end
|
319
|
+
stmt.add_group_by(o)
|
320
|
+
else
|
321
|
+
# just 'foo DESC, bar ASC'
|
322
|
+
stmt.add_group_by(o)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
if o = opt[:index_hint]
|
326
|
+
stmt.add_index_hint(table, o)
|
327
|
+
end
|
328
|
+
|
329
|
+
stmt.limit(opt[:limit]) if opt[:limit]
|
330
|
+
stmt.offset(opt[:offset]) if opt[:offset]
|
331
|
+
|
332
|
+
if terms = opt[:having]
|
333
|
+
term.each do |col, val|
|
334
|
+
stmt.add_having(:col => val)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
stmt.for_update(1) if opt[:for_update]
|
339
|
+
return stmt
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
__END__
|
344
|
+
|
345
|
+
=encoding utf8
|
346
|
+
|
347
|
+
=head1 NAME
|
348
|
+
|
349
|
+
SQL::Maker - Yet another SQL builder
|
350
|
+
|
351
|
+
=head1 SYNOPSIS
|
352
|
+
|
353
|
+
use SQL::Maker
|
354
|
+
|
355
|
+
builder = SQL::Maker.new(
|
356
|
+
:driver => 'SQLite', # or your favorite driver
|
357
|
+
)
|
358
|
+
|
359
|
+
# SELECT
|
360
|
+
sql, bind = builder.select(table, fields, where, opt)
|
361
|
+
|
362
|
+
# INSERT
|
363
|
+
sql, bind = builder.insert(table, values, opt)
|
364
|
+
|
365
|
+
# DELETE
|
366
|
+
sql, bind = builder.delete(table, where, opt)
|
367
|
+
|
368
|
+
# UPDATE
|
369
|
+
sql, bind = builder.update(table, set, where)
|
370
|
+
sql, bind = builder.update(table, set, where)
|
371
|
+
|
372
|
+
=head1 DESCRIPTION
|
373
|
+
|
374
|
+
SQL::Maker is yet another SQL builder class.
|
375
|
+
|
376
|
+
=head1 METHODS
|
377
|
+
|
378
|
+
=over 4
|
379
|
+
|
380
|
+
=item C<< builder = SQL::Maker.new(args) >>
|
381
|
+
|
382
|
+
Create new instance of SQL::Maker.
|
383
|
+
|
384
|
+
Attributes are the following:
|
385
|
+
|
386
|
+
=over 4
|
387
|
+
|
388
|
+
=item driver: Str
|
389
|
+
|
390
|
+
Driver name is required. The driver type is needed to create SQL string.
|
391
|
+
|
392
|
+
=item quote_char: Str
|
393
|
+
|
394
|
+
This is the character that a table or column name will be quoted with.
|
395
|
+
|
396
|
+
Default: auto detect from driver.
|
397
|
+
|
398
|
+
=item name_sep: Str
|
399
|
+
|
400
|
+
This is the character that separates a table and column name.
|
401
|
+
|
402
|
+
Default: '.'
|
403
|
+
|
404
|
+
=item new_line: Str
|
405
|
+
|
406
|
+
This is the character that separates a part of statements.
|
407
|
+
|
408
|
+
Default: '\n'
|
409
|
+
|
410
|
+
=item strict: Bool
|
411
|
+
|
412
|
+
In strict mode, all the expressions must be declared by using instances of SQL::QueryMaker
|
413
|
+
|
414
|
+
Default: false
|
415
|
+
|
416
|
+
=back
|
417
|
+
|
418
|
+
=item C<< select = builder.new_select(args) >>
|
419
|
+
|
420
|
+
Create new instance of L<SQL::Maker::Select> using the settings from B<builder>.
|
421
|
+
|
422
|
+
This method returns an instance of L<SQL::Maker::Select>.
|
423
|
+
|
424
|
+
=item C<< sql, bind = builder.select(table|tables, fields, where, opt) >>
|
425
|
+
|
426
|
+
sql, bind = builder.select('user', ['*'], {:name => 'john'}, {:order_by => 'user_id DESC'})
|
427
|
+
# =>
|
428
|
+
# SELECT * FROM `user` WHERE (`name` = ?) ORDER BY user_id DESC
|
429
|
+
# ['john']
|
430
|
+
|
431
|
+
This method returns the SQL string and bind variables for a SELECT statement.
|
432
|
+
|
433
|
+
=over 4
|
434
|
+
|
435
|
+
=item C<< table >>
|
436
|
+
|
437
|
+
=item C<< \@tables >>
|
438
|
+
|
439
|
+
Table name for the B<FROM> clause as scalar or arrayref. You can specify the instance of B<SQL::Maker::Select> for a sub-query.
|
440
|
+
|
441
|
+
If you are using C<< opt.joins >> this should be I<< undef >> since it's passed via the first join.
|
442
|
+
|
443
|
+
=item C<< \@fields >>
|
444
|
+
|
445
|
+
This is a list for retrieving fields from database.
|
446
|
+
|
447
|
+
Each element of the C<@fields> is normally a scalar or a scalar ref containing the column name.
|
448
|
+
If you want to specify an alias of the field, you can use an arrayref containing a pair
|
449
|
+
of column and alias names (e.g. C<< ['foo.id' => 'foo_id'] >>).
|
450
|
+
|
451
|
+
=item C<< \%where >>
|
452
|
+
|
453
|
+
=item C<< \@where >>
|
454
|
+
|
455
|
+
=item C<< where >>
|
456
|
+
|
457
|
+
where clause from hashref or arrayref via L<SQL::Maker::Condition>, or L<SQL::Maker::Condition> object.
|
458
|
+
|
459
|
+
=item C<< \%opt >>
|
460
|
+
|
461
|
+
These are the options for the SELECT statement
|
462
|
+
|
463
|
+
=over 4
|
464
|
+
|
465
|
+
=item C<< opt.prefix >>
|
466
|
+
|
467
|
+
This is a prefix for the SELECT statement.
|
468
|
+
|
469
|
+
For example, you can provide the 'SELECT SQL_CALC_FOUND_ROWS '. It's useful for MySQL.
|
470
|
+
|
471
|
+
Default Value: 'SELECT '
|
472
|
+
|
473
|
+
=item C<< opt.limit >>
|
474
|
+
|
475
|
+
This option adds a 'LIMIT n' clause.
|
476
|
+
|
477
|
+
=item C<< opt.offset >>
|
478
|
+
|
479
|
+
This option adds an 'OFFSET n' clause.
|
480
|
+
|
481
|
+
=item C<< opt.order_by >>
|
482
|
+
|
483
|
+
This option adds an B<ORDER BY> clause
|
484
|
+
|
485
|
+
You can write it in any of the following forms:
|
486
|
+
|
487
|
+
builder.select(..., {:order_by => 'foo DESC, bar ASC'})
|
488
|
+
builder.select(..., {:order_by => ['foo DESC', 'bar ASC']})
|
489
|
+
builder.select(..., {:order_by => {:foo => 'DESC'}})
|
490
|
+
builder.select(..., {:order_by => [{:foo => 'DESC'}, {:bar => 'ASC'}]})
|
491
|
+
|
492
|
+
=item C<< opt.group_by >>
|
493
|
+
|
494
|
+
This option adds a B<GROUP BY> clause
|
495
|
+
|
496
|
+
You can write it in any of the following forms:
|
497
|
+
|
498
|
+
builder.select(..., {:group_by => 'foo DESC, bar ASC'})
|
499
|
+
builder.select(..., {:group_by => ['foo DESC', 'bar ASC']})
|
500
|
+
builder.select(..., {:group_by => {:foo => 'DESC'}})
|
501
|
+
builder.select(..., {:group_by => [{:foo => 'DESC'}, {:bar => 'ASC'}]})
|
502
|
+
|
503
|
+
=item C<< opt.having >>
|
504
|
+
|
505
|
+
This option adds a HAVING clause
|
506
|
+
|
507
|
+
=item C<< opt.for_update >>
|
508
|
+
|
509
|
+
This option adds a 'FOR UPDATE" clause.
|
510
|
+
|
511
|
+
=item C<< opt.joins >>
|
512
|
+
|
513
|
+
This option adds a 'JOIN' via L<SQL::Maker::Select>.
|
514
|
+
|
515
|
+
You can write it as follows:
|
516
|
+
|
517
|
+
builder.select(undef, ..., {:joins => [[:user => {:table => 'group', :condition => 'user.gid = group.gid'}], ...]})
|
518
|
+
|
519
|
+
=item C<< opt.index_hint >>
|
520
|
+
|
521
|
+
This option adds an INDEX HINT like as 'USE INDEX' clause for MySQL via L<SQL::Maker::Select>.
|
522
|
+
|
523
|
+
You can write it as follows:
|
524
|
+
|
525
|
+
builder.select(..., { :index_hint => 'foo' })
|
526
|
+
builder.select(..., { :index_hint => ['foo', 'bar'] })
|
527
|
+
builder.select(..., { :index_hint => { :list => 'foo' })
|
528
|
+
builder.select(..., { :index_hint => { :type => 'FORCE', :list => ['foo', 'bar'] })
|
529
|
+
|
530
|
+
=back
|
531
|
+
|
532
|
+
=back
|
533
|
+
|
534
|
+
=item C<< sql, bind = builder.insert(table, \%values|\@values, \%opt); >>
|
535
|
+
|
536
|
+
sql, bind = builder.insert(:user => {:name => 'john'})
|
537
|
+
# =>
|
538
|
+
# INSERT INTO `user` (`name`) VALUES (?)
|
539
|
+
# ['john']
|
540
|
+
|
541
|
+
Generate an INSERT query.
|
542
|
+
|
543
|
+
=over 4
|
544
|
+
|
545
|
+
=item C<< table >>
|
546
|
+
|
547
|
+
Table name in scalar.
|
548
|
+
|
549
|
+
=item C<< \%values >>
|
550
|
+
|
551
|
+
These are the values for the INSERT statement.
|
552
|
+
|
553
|
+
=item C<< \%opt >>
|
554
|
+
|
555
|
+
These are the options for the INSERT statement
|
556
|
+
|
557
|
+
=over 4
|
558
|
+
|
559
|
+
=item C<< opt.prefix >>
|
560
|
+
|
561
|
+
This is a prefix for the INSERT statement.
|
562
|
+
|
563
|
+
For example, you can provide 'INSERT IGNORE INTO' for MySQL.
|
564
|
+
|
565
|
+
Default Value: 'INSERT INTO'
|
566
|
+
|
567
|
+
=back
|
568
|
+
|
569
|
+
=back
|
570
|
+
|
571
|
+
=item C<< sql, bind = builder.delete(table, \%where|\@where|where, \%opt); >>
|
572
|
+
|
573
|
+
sql, bind = builder.delete(table, \%where)
|
574
|
+
# =>
|
575
|
+
# DELETE FROM `user` WHERE (`name` = ?)
|
576
|
+
# ['john']
|
577
|
+
|
578
|
+
Generate a DELETE query.
|
579
|
+
|
580
|
+
=over 4
|
581
|
+
|
582
|
+
=item C<< table >>
|
583
|
+
|
584
|
+
Table name in scalar.
|
585
|
+
|
586
|
+
=item C<< \%where >>
|
587
|
+
|
588
|
+
=item C<< \@where >>
|
589
|
+
|
590
|
+
=item C<< where >>
|
591
|
+
|
592
|
+
where clause from hashref or arrayref via L<SQL::Maker::Condition>, or L<SQL::Maker::Condition> object.
|
593
|
+
|
594
|
+
=item C<< \%opt >>
|
595
|
+
|
596
|
+
These are the options for the DELETE statement
|
597
|
+
|
598
|
+
=over 4
|
599
|
+
|
600
|
+
=item C<< opt.using >>
|
601
|
+
|
602
|
+
This option adds a USING clause. It takes a scalar or an arrayref of table names as argument:
|
603
|
+
|
604
|
+
(sql, bind) = bulder.delete(table, \%where, { :using => 'group' })
|
605
|
+
# =>
|
606
|
+
# DELETE FROM `user` USING `group` WHERE (`group`.`name` = ?)
|
607
|
+
# ['doe']
|
608
|
+
bulder.delete(..., { :using => ['bar', 'qux'] })
|
609
|
+
|
610
|
+
=back
|
611
|
+
|
612
|
+
=back
|
613
|
+
|
614
|
+
=item C<< sql, bind = builder.update(table, \%set|@set, \%where|\@where|where); >>
|
615
|
+
|
616
|
+
Generate a UPDATE query.
|
617
|
+
|
618
|
+
sql, bind = builder.update('user', ['name' => 'john', :email => 'john@example.com'], {:user_id => 3})
|
619
|
+
# =>
|
620
|
+
# 'UPDATE `user` SET `name` = ?, `email` = ? WHERE (`user_id` = ?)'
|
621
|
+
# ['john','john@example.com',3]
|
622
|
+
|
623
|
+
=over 4
|
624
|
+
|
625
|
+
=item table
|
626
|
+
|
627
|
+
Table name in scalar.
|
628
|
+
|
629
|
+
=item \%set
|
630
|
+
|
631
|
+
Setting values.
|
632
|
+
|
633
|
+
=item \%where
|
634
|
+
|
635
|
+
=item \@where
|
636
|
+
|
637
|
+
=item where
|
638
|
+
|
639
|
+
where clause from a hashref or arrayref via L<SQL::Maker::Condition>, or L<SQL::Maker::Condition> object.
|
640
|
+
|
641
|
+
=back
|
642
|
+
|
643
|
+
=item C<< builder.new_condition() >>
|
644
|
+
|
645
|
+
Create new L<SQL::Maker::Condition> object from C< builder > settings.
|
646
|
+
|
647
|
+
=item C<< sql, bind = builder.where(where) >>
|
648
|
+
|
649
|
+
Where clause from a hashref or arrayref via L<SQL::Maker::Condition>, or L<SQL::Maker::Condition> object.
|
650
|
+
|
651
|
+
=back
|
652
|
+
|
653
|
+
=head1 PLUGINS
|
654
|
+
|
655
|
+
SQL::Maker features a plugin system. Write the code as follows:
|
656
|
+
|
657
|
+
require 'sql/maker'
|
658
|
+
SQL::Maker.load_plugin('insert_multi')
|
659
|
+
|
660
|
+
=head1 FAQ
|
661
|
+
|
662
|
+
=over 4
|
663
|
+
|
664
|
+
=item Why don't you use Arel or ActiveRecord?
|
665
|
+
|
666
|
+
I wanted a query builder rather than ORM.
|
667
|
+
|
668
|
+
I wanted simpler one than Arel.
|
669
|
+
|
670
|
+
=back
|
671
|
+
|
672
|
+
=head1 SEE ALSO
|
673
|
+
|
674
|
+
https://github.com/tokuhirom/SQL-Maker
|
675
|
+
|
676
|
+
=cut
|