sql-maker 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  # reference: ActiveRecord::ConnectionAdapter::Quoting
2
2
  require 'yaml'
3
+ require 'bigdecimal'
3
4
 
4
5
  module SQL::Maker::Quoting
5
6
  # Quotes the value rather than column name to help prevent
@@ -302,7 +302,7 @@ class SQL::Maker::Select
302
302
  col, val = parse_args(*args)
303
303
  col = col.to_s
304
304
  if orig = self.select_map_reverse[col]
305
- col = orig
305
+ col = orig.respond_to?(:as_sql) ? orig.as_sql : orig
306
306
  end
307
307
 
308
308
  self.having ||= self.new_condition()
@@ -332,214 +332,3 @@ class SQL::Maker::Select
332
332
  return quoted
333
333
  end
334
334
  end
335
-
336
- __END__
337
-
338
- =head1 NAME
339
-
340
- SQL::Maker::Select - dynamic SQL generator
341
-
342
- =head1 SYNOPSIS
343
-
344
- sql = SQL::Maker::Select.new
345
- .add_select('foo')
346
- .add_select('bar')
347
- .add_select('baz')
348
- .add_from('table_name' => 't')
349
- .as_sql
350
- # => "SELECT foo, bar, baz FROM table_name t"
351
-
352
- =head1 DESCRIPTION
353
-
354
- =head1 METHODS
355
-
356
- =over 4
357
-
358
- =item C<< sql = stmt.as_sql(); >>
359
-
360
- Render the SQL string.
361
-
362
- =item C<< @bind = stmt.bind(); >>
363
-
364
- Get the bind variables.
365
-
366
- =item C<< stmt.add_select('*') >>
367
-
368
- =item C<< stmt.add_select(:col => alias) >>
369
-
370
- =item C<< stmt.add_select(\'COUNT(*)' => 'cnt') >>
371
-
372
- Add a new select term. It's automatically quoted.
373
-
374
- =item C<< stmt.add_from(table :Str | select :SQL::Maker::Select) : SQL::Maker::Select >>
375
-
376
- Add a new FROM clause. You can specify the table name or an instance of L<SQL::Maker::Select> for a sub-query.
377
-
378
- I<Return:> stmt itself.
379
-
380
- =item C<< stmt.add_join(:user => {:type => 'inner', :table => 'config', :condition => 'user.user_id = config.user_id'}); >>
381
-
382
- =item C<< stmt.add_join(:user => {:type => 'inner', :table => 'config', :condition => {'user.user_id' => 'config.user_id'}); >>
383
-
384
- =item C<< stmt.add_join(:user => {:type => 'inner', :table => 'config', :condition => ['user_id']}); >>
385
-
386
- Add a new JOIN clause. If you pass an arrayref for 'condition' then it uses 'USING'. If 'type' is omitted
387
- it falls back to plain JOIN.
388
-
389
- stmt = SQL::Maker::Select.new
390
- stmt.add_join(
391
- :user => {
392
- :type => 'inner',
393
- :table => 'config',
394
- :condition => 'user.user_id = config.user_id',
395
- }
396
- )
397
- stmt.as_sql
398
- # => 'FROM user INNER JOIN config ON user.user_id = config.user_id'
399
-
400
- stmt = SQL::Maker::Select.new(:quote_char => '`', :name_sep => '.')
401
- stmt.add_join(
402
- :user => {
403
- :type => 'inner',
404
- :table => 'config',
405
- :condition => {'user.user_id' => 'config.user_id'},
406
- }
407
- )
408
- stmt.as_sql
409
- # => 'FROM `user` INNER JOIN `config` ON `user`.`user_id` = `config`.`user_id`'
410
-
411
- stmt = SQL::Maker::Select.new
412
- stmt.add_select('name')
413
- stmt.add_join(
414
- :user => {
415
- :type => 'inner',
416
- :table => 'config',
417
- :condition => ['user_id'],
418
- }
419
- )
420
- stmt.as_sql
421
- # => 'SELECT name FROM user INNER JOIN config USING (user_id)'
422
-
423
- subquery = SQL::Maker::Select.new
424
- subquery.add_select('*')
425
- subquery.add_from( 'foo' )
426
- subquery.add_where( 'hoge' => 'fuga' )
427
- stmt = SQL::Maker::Select.new
428
- stmt.add_join(
429
- [ subquery, 'bar' ] => {
430
- :type => 'inner',
431
- :table => 'baz',
432
- :alias => 'b1',
433
- :condition => 'bar.baz_id = b1.baz_id'
434
- },
435
- )
436
- stmt.as_sql
437
- # => "FROM (SELECT * FROM foo WHERE (hoge = ?)) bar INNER JOIN baz b1 ON bar.baz_id = b1.baz_id"
438
-
439
- =item C<< stmt.add_index_hint(:foo => {:type => 'USE', :list => ['index_hint']}); >>
440
-
441
- =item C<< stmt.add_index_hint(:foo => 'index_hint'); >>
442
-
443
- =item C<< stmt.add_index_hint(:foo => ['index_hint']); >>
444
-
445
- stmt = SQL::Maker::Select.new
446
- stmt.add_select('name')
447
- stmt.add_from('user')
448
- stmt.add_index_hint(:user => {:type => 'USE', :list => ['index_hint']})
449
- stmt.as_sql
450
- # => "SELECT name FROM user USE INDEX (index_hint)"
451
-
452
- =item C<< stmt.add_where('foo_id' => 'bar'); >>
453
-
454
- Add a new WHERE clause.
455
-
456
- stmt = SQL::Maker::Select.new.add_select('c')
457
- .add_from('foo')
458
- .add_where('name' => 'john')
459
- .add_where('type' => {:IN => %w/1 2 3/})
460
- .as_sql
461
- # => "SELECT c FROM foo WHERE (name = ?) AND (type IN (?, ?, ?))"
462
-
463
- =item C<< stmt.add_where_raw('id = ?', [1]) >>
464
-
465
- Add a new WHERE clause from raw placeholder string and bind variables.
466
-
467
- stmt = SQL::Maker::Select.new.add_select('c')
468
- .add_from('foo')
469
- .add_where_raw('EXISTS(SELECT * FROM bar WHERE name = ?)' => ['john'])
470
- .add_where_raw('type IS NOT NULL')
471
- .as_sql
472
- # => "SELECT c FROM foo WHERE (EXISTS(SELECT * FROM bar WHERE name = ?)) AND (type IS NOT NULL)"
473
-
474
-
475
- =item C<< stmt.set_where(condition) >>
476
-
477
- Set the WHERE clause.
478
-
479
- condition should be instance of L<SQL::Maker::Condition>.
480
-
481
- cond1 = SQL::Maker::Condition.new.add("name" => "john")
482
- cond2 = SQL::Maker::Condition.new.add("type" => {:IN => %w/1 2 3/})
483
- stmt = SQL::Maker::Select.new.add_select('c')
484
- .add_from('foo')
485
- .set_where(cond1 & cond2)
486
- .as_sql
487
- # => "SELECT c FROM foo WHERE ((name = ?)) AND ((type IN (?, ?, ?)))"
488
-
489
- =item C<< stmt.add_order_by('foo'); >>
490
-
491
- =item C<< stmt.add_order_by({'foo' => 'DESC'}); >>
492
-
493
- Add a new ORDER BY clause.
494
-
495
- stmt = SQL::Maker::Select.new.add_select('c')
496
- .add_from('foo')
497
- .add_order_by('name' => 'DESC')
498
- .add_order_by('id')
499
- .as_sql
500
- # => "SELECT c FROM foo ORDER BY name DESC, id"
501
-
502
- =item C<< stmt.add_group_by('foo'); >>
503
-
504
- Add a new GROUP BY clause.
505
-
506
- stmt = SQL::Maker::Select.new.add_select('c')
507
- .add_from('foo')
508
- .add_group_by('id')
509
- .as_sql
510
- # => "SELECT c FROM foo GROUP BY id"
511
-
512
- stmt = SQL::Maker::Select.new.add_select('c')
513
- .add_from('foo')
514
- .add_group_by('id' => 'DESC')
515
- .as_sql
516
- # => "SELECT c FROM foo GROUP BY id DESC"
517
-
518
- =item C<< stmt.limit(30) >>
519
-
520
- =item C<< stmt.offset(5) >>
521
-
522
- Add LIMIT and OFFSET.
523
-
524
- stmt = SQL::Maker::Select.new.add_select('c')
525
- .add_from('foo')
526
- .limit(30)
527
- .offset(5)
528
- .as_sql
529
- # => "SELECT c FROM foo LIMIT 30 OFFSET 5"
530
-
531
- =item C<< stmt.add_having(:cnt => 2) >>
532
-
533
- Add a HAVING clause.
534
-
535
- # stmt = SQL::Maker::Select.new.add_from('foo')
536
- # .add_select(\'COUNT(*)' => 'cnt')
537
- # .add_having(:cnt => 2)
538
- # .as_sql
539
- # # => "SELECT COUNT(*) AS cnt FROM foo HAVING (COUNT(*) = ?)"
540
-
541
- =back
542
-
543
- =head1 SEE ALSO
544
-
545
- L<Data::ObjectDriver::SQL>
@@ -76,119 +76,3 @@ class SQL::Maker::SelectSet
76
76
  self # method chain
77
77
  end
78
78
  end
79
-
80
- __END__
81
-
82
- =head1 NAME
83
-
84
- SQL::Maker::SelectSet - provides set functions
85
-
86
- =head1 SYNOPSIS
87
-
88
- use SQL::Maker::SelectSet qw(union_all except)
89
- s1 = SQL::Maker::Select .new()
90
- .add_select('foo')
91
- .add_from('t1')
92
- s2 = SQL::Maker::Select .new()
93
- .add_select('bar')
94
- .add_from('t2')
95
- union_all( s1, s2 ).as_sql
96
- # =>
97
- # SQL::Maker::SelectSet.new_set(
98
- # :operator => 'UNION ALL',
99
- # :new_line => s1.new_line
100
- # ).add_statement(s1)
101
- # .add_statement(s2)
102
- # .as_sql
103
- # => "SELECT foo FROM t1 UNION ALL SELECT bar FROM t2"
104
- except( s1, s2 ).as_sql
105
- # => SQL::Maker::SelectSet.new_set( :operator => 'EXCEPT', :new_line => s1.new_line )
106
- # .add_statement( s1 )
107
- # .add_statement( s2 )
108
- # .as_sql
109
- # => "SELECT foo FROM t1 EXCEPT SELECT bar FROM t2"
110
-
111
- =head1 DESCRIPTION
112
-
113
- This module provides some set functions which return a SQL::Maker::SelectSet object
114
- inherited from L<SQL::Maker::Select>.
115
-
116
- =head1 FUNCTION
117
-
118
- =over 4
119
-
120
- =item C<< union(select :SQL::Maker::Select | set :SQL::Maker::SelectSet) : SQL::Maker::SelectSet >>
121
-
122
- Tow statements are combined by C<UNION>.
123
-
124
- =item C<< union_all(select :SQL::Maker::Select | set :SQL::Maker::SelectSet) : SQL::Maker::SelectSet >>
125
-
126
- Tow statements are combined by C<UNION ALL>.
127
-
128
- =item C<< intersect(select :SQL::Maker::Select | set :SQL::Maker::SelectSet) : SQL::Maker::SelectSet >>
129
-
130
- Tow statements are combined by C<INTERSECT>.
131
-
132
- =item C<< intersect_all(select :SQL::Maker::Select | set :SQL::Maker::SelectSet) : SQL::Maker::SelectSet >>
133
-
134
- Tow statements are combined by C<INTERSECT ALL>.
135
-
136
- =item C<< except(select :SQL::Maker::Select | set :SQL::Maker::SelectSet) : SQL::Maker::SelectSet >>
137
-
138
- Tow statements are combined by C<EXCEPT>.
139
-
140
- =item C<< except(select :SQL::Maker::Select | set :SQL::Maker::SelectSet) : SQL::Maker::SelectSet >>
141
-
142
- Tow statements are combined by C<EXCEPT ALL>.
143
-
144
- =back
145
-
146
- =head1 Class Method
147
-
148
- =over 4
149
-
150
- =item stmt = SQL::Maker::SelectSet.new( %args )
151
-
152
- opretaor is a set operator (ex. C<UNION>).
153
- one and another are SQL::Maker::Select object or SQL::Maker::SelectSet object.
154
- It returns a SQL::Maker::SelectSet object.
155
-
156
- The parameters are:
157
-
158
- =over 4
159
-
160
- =item new_line
161
-
162
- Default values is "\n".
163
-
164
- =item operator : Str
165
-
166
- The operator. This parameter is required.
167
-
168
- =back
169
-
170
- =back
171
-
172
- =head1 Instance Methods
173
-
174
- =over 4
175
-
176
- =item C<< sql = set.as_sql() : Str >>
177
-
178
- Returns a new select statement.
179
-
180
- =item C<< @bind = set.bind() : Array[Str] >>
181
-
182
- Returns bind variables.
183
-
184
- =item C<< set.add_statement(stmt : stmt.can('as_sql')) : SQL::Maker::SelectSet >>
185
-
186
- This method adds new statement object. C<< stmt >> must provides 'as_sql' method.
187
-
188
- I<Return Value> is the set itself.
189
-
190
- =back
191
-
192
- =head1 SEE ALSO
193
-
194
- L<SQL::Maker::Select>
@@ -161,6 +161,8 @@ class SQL::QueryMaker
161
161
  }, bind)
162
162
  end
163
163
 
164
+ # sql_raw('SELECT foo_id FROM bar WHERE t=44')
165
+ # sql_raw('SELECT foo_id FROM bar WHERE t=?', [44])
164
166
  def sql_raw(*args)
165
167
  sql, bind = parse_args(*args)
166
168
  return SQL::QueryMaker.new(nil, Proc.new { sql }, bind)
@@ -206,224 +208,3 @@ class SQL::QueryMaker
206
208
  label.to_s.split(/\./).map {|e| "`#{e}`"}.join('.')
207
209
  end
208
210
  end
209
-
210
- __END__
211
-
212
- =head1 NAME
213
-
214
- SQL::QueryMaker - helper functions for SQL query generation
215
-
216
- =head1 SYNOPSIS
217
-
218
- query = sql_eq(:foo => v)
219
- query.as_sql # `foo`=?
220
- query.bind # (v)
221
-
222
- query = sql_lt(:foo => v)
223
- query.as_sql # `foo`<?
224
- query.bind # (v)
225
-
226
- query = sql_in(:foo => [
227
- v1, v2, v3,
228
- ])
229
- query.as_sql # `foo` IN (?,?,?)
230
- query.bind # (v1,v2,v3)
231
-
232
- query = sql_and(:foo => [
233
- sql_ge(min),
234
- sql_lt(max)
235
- ])
236
- query.as_sql # `foo`>=? AND `foo`<?
237
- query.bind # (min,max)
238
-
239
- query = sql_and([
240
- sql_eq(:foo => v1),
241
- sql_eq(:bar => v2)
242
- ]
243
- query.as_sql # `foo`=? AND `bar`=?
244
- query.bind # (v1,v2)
245
-
246
- query = sql_and([
247
- :foo => v1,
248
- :bar => sql_lt(v2),
249
- ])
250
- query.as_sql # `foo`=? AND `bar`<?
251
- query.bind # (v1,v2)
252
-
253
- =head1 DESCRIPTION
254
-
255
- This module concentrates on providing an expressive, concise way to declare SQL
256
- expressions by exporting carefully-designed functions.
257
- It is possible to use the module to generate SQL query conditions and pass them
258
- as arguments to other more versatile query builders such as L<SQL::Maker>.
259
-
260
- The functions exported by the module instantiate comparator objects that build
261
- SQL expressions when their C<as_sql> method are being invoked.
262
- There are two ways to specify the names of the columns to the comparator; to
263
- pass in the names as argument or to specify then as an argument to the
264
- C<as_sql> method.
265
-
266
- =head1 FUNCTIONS
267
-
268
- =head2 C<< sql_eq([column,] value) >>
269
-
270
- =head2 C<< sql_lt([column,] value) >>
271
-
272
- =head2 C<< sql_gt([column,] value) >>
273
-
274
- =head2 C<< sql_le([column,] value) >>
275
-
276
- =head2 C<< sql_ge([column,] value) >>
277
-
278
- =head2 C<< sql_like([column,] value) >>
279
-
280
- =head2 C<< sql_is_null([column]) >>
281
-
282
- =head2 C<< sql_is_not_null([column]) >>
283
-
284
- =head2 C<< sql_not([column]) >>
285
-
286
- =head2 C<< sql_between([column,] min_value, max_value) >>
287
-
288
- =head2 C<< sql_not_between([column,] min_value, max_value) >>
289
-
290
- =head2 C<< sql_in([column,] \@values) >>
291
-
292
- =head2 C<< sql_not_in([column,] \@values) >>
293
-
294
- Instantiates a comparator object that tests a column against given value(s).
295
-
296
- =head2 C<< sql_and([column,] \@conditions) >>
297
-
298
- =head2 C<< sql_or([$ column,] \@conditions) >>
299
-
300
- Aggregates given comparator objects into a logical expression.
301
-
302
- If specified, the column name is pushed down to the arguments when the
303
- C<as_sql> method is being called, as show in the second example below.
304
-
305
- sql_and([ # => `foo`=? AND `bar`<?
306
- sql_eq("foo" => v1),
307
- sql_lt("bar" => v2)
308
- ])
309
-
310
- sql_and("foo" => [ # => `foo`>=min OR `foo`<max
311
- sql_ge(min),
312
- sql_lt(max),
313
- ])
314
-
315
- =head2 C<< sql_and(\%conditions) >>
316
-
317
- =head2 C<< sql_or(\%conditions) >>
318
-
319
- Aggregates given pairs of column names and comparators into a logical
320
- expression.
321
-
322
- The value part is composed of as the argument to the C<=> operator if it is
323
- not a blessed reference.
324
-
325
- query = sql_and({
326
- :foo => 'abc',
327
- :bar => sql_lt(123),
328
- })
329
- query.as_sql # => `foo`=? AND bar<?
330
- query.bind # => ('abc', 123)
331
-
332
-
333
- =head2 C<< sql_op([column,] op_sql, \@bind_values) >>
334
-
335
- Generates a comparator object that tests a column using the given SQL and
336
- values. C<<@>> in the given SQL are replaced by the column name (specified
337
- either by the argument to the function or later by the call to the C<<as_sql>>
338
- method), and C<<?>> are substituted by the given bind values.
339
-
340
- =head2 C<< sql_raw(sql, @bind_values) >>
341
-
342
- Generates a comparator object from raw SQL and bind values. C<<?>> in the
343
- given SQL are replaced by the bind values.
344
-
345
- =head2 C<< obj.as_sql() >>
346
-
347
- =head2 C<< obj.as_sql(column_name) >>
348
-
349
- =head2 C<< obj.as_sql(column_name, quote_identifier_cb) >>
350
-
351
- Compiles given comparator object and returns an SQL expression.
352
- Corresponding bind values should be obtained by calling the C<bind> method.
353
-
354
- The function optionally accepts a column name to which the comparator object
355
- should be bound; an error is thrown if the comparator object is already bound
356
- to another column.
357
-
358
- The function also accepts a callback for quoting the identifiers. If omitted,
359
- the identifiers are quoted using C<`> after being splitted using C<.>; i.e. a
360
- column designated as C<foo.bar> is quoted as C<`foo`.`bar`>.
361
-
362
- =head2 C<< obj.bind() >>
363
-
364
- Returns a list of bind values corresponding to the SQL expression returned by
365
- the C<as_sql> method.
366
-
367
- =head1 CHEAT SHEET
368
-
369
- IN: sql_eq('foo' => 'bar')
370
- OUT QUERY: '`foo` = ?'
371
- OUT BIND: ['bar']
372
-
373
- IN: sql_in('foo' => ['bar', 'baz'])
374
- OUT QUERY: '`foo` IN (?,?)'
375
- OUT BIND: ['bar','baz']
376
-
377
- IN: sql_and([sql_eq('foo' => 'bar'), sql_eq('baz' => 123)])
378
- OUT QUERY: '(`foo` = ?) AND (`baz` = ?)'
379
- OUT BIND: ['bar',123]
380
-
381
- IN: sql_and('foo' => [sql_ge(3), sql_lt(5)])
382
- OUT QUERY: '(`foo` >= ?) AND (`foo` < ?)'
383
- OUT BIND: [3,5]
384
-
385
- IN: sql_or([sql_eq('foo' => 'bar'), sql_eq('baz' => 123)])
386
- OUT QUERY: '(`foo` = ?) OR (`baz` = ?)'
387
- OUT BIND: ['bar',123]
388
-
389
- IN: sql_or('foo' => ['bar', 'baz'])
390
- OUT QUERY: '(`foo` = ?) OR (`foo` = ?)'
391
- OUT BIND: ['bar','baz']
392
-
393
- IN: sql_is_null('foo')
394
- OUT QUERY: '`foo` IS NULL'
395
- OUT BIND: []
396
-
397
- IN: sql_is_not_null('foo')
398
- OUT QUERY: '`foo` IS NOT NULL'
399
- OUT BIND: []
400
-
401
- IN: sql_between('foo', 1, 2)
402
- OUT QUERY: '`foo` BETWEEN ? AND ?'
403
- OUT BIND: [1,2]
404
-
405
- IN: sql_not('foo')
406
- OUT QUERY: 'NOT `foo`'
407
- OUT BIND: []
408
-
409
- IN: sql_op('apples', 'MATCH (@) AGAINST (?)', ['oranges'])
410
- OUT QUERY: 'MATCH (`apples`) AGAINST (?)'
411
- OUT BIND: ['oranges']
412
-
413
- IN: sql_raw('SELECT * FROM t WHERE id=?',123)
414
- OUT QUERY: 'SELECT * FROM t WHERE id=?'
415
- OUT BIND: [123]
416
-
417
- IN: sql_in('foo' => [123,sql_raw('SELECT id FROM t WHERE cat=?',5)])
418
- OUT QUERY: '`foo` IN (?,(SELECT id FROM t WHERE cat=?))'
419
- OUT BIND: [123,5]
420
-
421
- =head1 AUTHOR
422
-
423
- Natoshi Seo (Originally designed by Kazuho Oku as a Perl module)
424
-
425
- =head1 LICENSE
426
-
427
- This library is free software; you can redistribute it and/or modify it under the MIT License.
428
-
429
- =cut