sql-maker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/CHANGELOG.md +3 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +23 -0
  7. data/Rakefile +14 -0
  8. data/lib/sql-maker.rb +5 -0
  9. data/lib/sql/maker.rb +676 -0
  10. data/lib/sql/maker/condition.rb +378 -0
  11. data/lib/sql/maker/error.rb +3 -0
  12. data/lib/sql/maker/helper.rb +22 -0
  13. data/lib/sql/maker/quoting.rb +138 -0
  14. data/lib/sql/maker/select.rb +544 -0
  15. data/lib/sql/maker/select/oracle.rb +30 -0
  16. data/lib/sql/maker/select_set.rb +194 -0
  17. data/lib/sql/maker/util.rb +54 -0
  18. data/lib/sql/query_maker.rb +429 -0
  19. data/scripts/perl2ruby.rb +34 -0
  20. data/spec/maker/bind_param_spec.rb +62 -0
  21. data/spec/maker/condition/add_raw_spec.rb +29 -0
  22. data/spec/maker/condition/compose_empty_spec.rb +72 -0
  23. data/spec/maker/condition/empty_values_spec.rb +25 -0
  24. data/spec/maker/condition/make_term_spec.rb +38 -0
  25. data/spec/maker/condition/where_spec.rb +35 -0
  26. data/spec/maker/delete_spec.rb +116 -0
  27. data/spec/maker/insert_empty_spec.rb +23 -0
  28. data/spec/maker/insert_spec.rb +61 -0
  29. data/spec/maker/new_line_spec.rb +9 -0
  30. data/spec/maker/select/oracle/oracle_spec.rb +16 -0
  31. data/spec/maker/select/pod_select_spec.rb +34 -0
  32. data/spec/maker/select/statement_spec.rb +805 -0
  33. data/spec/maker/select_set_spec.rb +294 -0
  34. data/spec/maker/select_spec.rb +470 -0
  35. data/spec/maker/simple_spec.rb +54 -0
  36. data/spec/maker/strict_spec.rb +45 -0
  37. data/spec/maker/subquery_spec.rb +77 -0
  38. data/spec/maker/update_spec.rb +138 -0
  39. data/spec/maker/util_spec.rb +6 -0
  40. data/spec/maker/where_spec.rb +28 -0
  41. data/spec/query_maker/and_using_hash_spec.rb +13 -0
  42. data/spec/query_maker/cheatsheet_spec.rb +32 -0
  43. data/spec/query_maker/column_bind_spec.rb +55 -0
  44. data/spec/query_maker/refs_in_bind_spec.rb +19 -0
  45. data/spec/spec_helper.rb +15 -0
  46. data/sql-maker.gemspec +25 -0
  47. 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
@@ -0,0 +1,3 @@
1
+ ## 0.0.1 (2014/06/18)
2
+
3
+ First version
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sql-maker.gemspec
4
+ gemspec
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
+ [![Build Status](https://secure.travis-ci.org/sonots/ruby-sql-maker.png?branch=master)](http://travis-ci.org/sonots/ruby-sql-maker)
4
+ [![Coverage Status](https://coveralls.io/repos/sonots/ruby-sql-maker/badge.png?branch=master)](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
@@ -0,0 +1,5 @@
1
+ module SQL; end
2
+
3
+ require 'sql/query_maker'
4
+ require 'sql/maker'
5
+ require 'sql/maker/helper'
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