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.
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