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
@@ -0,0 +1,378 @@
1
+ require 'sql/maker/util'
2
+ require 'sql/query_maker'
3
+
4
+ class SQL::Maker::Condition
5
+ include SQL::Maker::Util
6
+ attr_accessor :sql, :bind, :strict, :name_sep, :quote_char
7
+
8
+ def initialize(args = {})
9
+ @sql = args[:sql] || []
10
+ @bind = args[:bind] || []
11
+ @strict = args[:strict].nil? ? false : args[:strict]
12
+ @name_sep = args[:name_sep] || ''
13
+ @quote_char = args[:quote_char] || ''
14
+ end
15
+
16
+ def &(other)
17
+ self.compose_and(other)
18
+ end
19
+
20
+ def |(other)
21
+ self.compose_or(other)
22
+ end
23
+
24
+ def _quote(label)
25
+ quote_identifier(label, self.quote_char, self.name_sep)
26
+ end
27
+
28
+ # _make_term(:x => 1)
29
+ def _make_term(*args)
30
+ col, val = parse_args(*args)
31
+ col = col.to_s
32
+
33
+ if val.is_a?(SQL::QueryMaker)
34
+ return [val.as_sql(col, self.method(:_quote)), val.bind]
35
+ elsif self.strict
36
+ croak("can pass only SQL::QueryMaker as an argument in strict mode")
37
+ end
38
+
39
+ if val.is_a?(Array)
40
+ if val.first.is_a?(Hash)
41
+ # {'foo'=>[{'>' => 'bar'},{'<' => 'baz'}]} => (`foo` > ?) OR (`foo` < ?)
42
+ return self._make_or_term(col, 'OR', val)
43
+ else
44
+ # {'foo'=>['bar','baz']} => `foo` IN (?, ?)
45
+ return self._make_in_term(col, 'IN', val)
46
+ end
47
+ elsif val.is_a?(Hash)
48
+ op, v = val.each.first
49
+ op = op.upcase.to_s
50
+ if ( op == 'AND' || op == 'OR' ) && v.is_a?(Array)
51
+ # {'foo'=>[{'>' => 'bar'},{'<' => 'baz'}]} => (`foo` > ?) OR (`foo` < ?)
52
+ return self._make_or_term(col, op, v)
53
+ elsif ( op == 'IN' || op == 'NOT IN' )
54
+ return self._make_in_term(col, op, v)
55
+ elsif ( op == 'BETWEEN' ) && v.is_a?(Array)
56
+ croak("USAGE: make_term(foo => {BETWEEN => [a, b]})") if v.size != 2
57
+ return [self._quote(col) + " BETWEEN ? AND ?", v]
58
+ else
59
+ # make_term(foo => { '<' => \"DATE_SUB(NOW(), INTERVAL 3 DAY)"}) => 'foo < DATE_SUB(NOW(), INTERVAL 3 DAY)'
60
+ # return [self._quote(col) + " op " + v, []]
61
+ # make_term(foo => { '<' => 3 }) => foo < 3
62
+ return [self._quote(col) + " #{op} ?", [v]]
63
+ end
64
+ elsif val
65
+ # make_term(foo => "3") => foo = 3
66
+ return [self._quote(col) + " = ?", [val]]
67
+ else
68
+ # make_term(foo => nil) => foo IS NULL
69
+ return [self._quote(col) + " IS NULL", []]
70
+ end
71
+ end
72
+
73
+ def _make_or_term(col, op, values)
74
+ binds = []
75
+ terms = []
76
+ values.each do |v|
77
+ term, bind = self._make_term(col => v)
78
+ terms.push "(#{term})"
79
+ binds.push bind
80
+ end
81
+ term = terms.join(" #{op} ")
82
+ bind = binds.flatten
83
+ return [term, bind]
84
+ end
85
+
86
+ def _make_in_term(col, op, v)
87
+ if v.respond_to?(:as_sql)
88
+ # make_term(foo => { 'IN' => sql_raw('SELECT foo FROM bar') }) => foo IN (SELECT foo FROM bar)
89
+ term = "#{self._quote(col)} #{op} (#{v.as_sql})"
90
+ [term, v.bind]
91
+ elsif v.is_a?(Array)
92
+ if v.size == 0
93
+ if op == 'IN'
94
+ # make_term(foo => {'IN' => []}) => 0=1
95
+ return ['0=1', []]
96
+ else
97
+ # make_term(foo => {'NOT IN' => []}) => 1=1
98
+ return ['1=1', []]
99
+ end
100
+ else
101
+ # make_term(foo => { 'IN' => [1,2,3] }) => [foo IN (?,?,?), [1,2,3]]
102
+ term = "#{self._quote(col)} #{op} (#{(['?'] * v.size).join(', ')})"
103
+ return [term, v]
104
+ end
105
+ else
106
+ croad("_make_in_term: arguments must be either of query instance or array")
107
+ end
108
+ end
109
+
110
+ def add(*args)
111
+ term, bind = self._make_term(*args)
112
+ self.sql.push "(#{term})" if term
113
+ self.bind += array_wrap(bind) if bind
114
+
115
+ return self # for influent interface
116
+ end
117
+
118
+ def add_raw(*args)
119
+ term, bind = parse_args(*args)
120
+ self.sql.push "(#{term})"
121
+ self.bind += array_wrap(bind) if bind
122
+ return self
123
+ end
124
+
125
+ def compose_and(other)
126
+ if self.sql.empty?
127
+ if other.sql.empty?
128
+ return SQL::Maker::Condition.new
129
+ end
130
+ return SQL::Maker::Condition.new(
131
+ :sql => ['(' + other.as_sql() + ')'],
132
+ :bind => other.bind,
133
+ )
134
+ end
135
+ if other.sql.empty?
136
+ return SQL::Maker::Condition.new(
137
+ :sql => ['(' + self.as_sql() + ')'],
138
+ :bind => self.bind,
139
+ )
140
+ end
141
+
142
+ return SQL::Maker::Condition.new(
143
+ :sql => ['(' + self.as_sql() + ') AND (' + other.as_sql() + ')'],
144
+ :bind => self.bind + other.bind,
145
+ )
146
+ end
147
+
148
+ def compose_or(other)
149
+ if self.sql.empty?
150
+ if other.sql.empty?
151
+ return SQL::Maker::Condition.new
152
+ end
153
+ return SQL::Maker::Condition.new(
154
+ :sql => ['(' + other.as_sql() + ')'],
155
+ :bind => other.bind,
156
+ )
157
+ end
158
+ if other.sql.empty?
159
+ return SQL::Maker::Condition.new(
160
+ :sql => ['(' + self.as_sql() + ')'],
161
+ :bind => self.bind,
162
+ )
163
+ end
164
+
165
+ # return value is enclosed with '()'.
166
+ # because 'OR' operator priority less than 'AND'.
167
+ return SQL::Maker::Condition.new(
168
+ :sql => ['((' + self.as_sql() + ') OR (' + other.as_sql() + '))'],
169
+ :bind => self.bind + other.bind,
170
+ )
171
+ end
172
+
173
+ def as_sql
174
+ self.sql.join(' AND ')
175
+ end
176
+ alias_method :to_s, :as_sql
177
+ end
178
+
179
+ __END__
180
+
181
+ =for test_synopsis
182
+ my (sql, @bind)
183
+
184
+ =head1 NAME
185
+
186
+ SQL::Maker::Condition - condition object for SQL::Maker
187
+
188
+ =head1 SYNOPSIS
189
+
190
+ my condition = SQL::Maker::Condition.new(
191
+ name_sep => '.',
192
+ quote_char => '`',
193
+ )
194
+ condition.add('foo_id' => 3)
195
+ condition.add('bar_id' => 4)
196
+ sql = condition.as_sql() # (`foo_id`=?) AND (`bar_id`=?)
197
+ @bind = condition.bind() # (3, 4)
198
+
199
+ # add_raw
200
+ my condition = SQL::Maker::Condition.new(
201
+ name_sep => '.',
202
+ quote_char => '`',
203
+ )
204
+ condition.add_raw('EXISTS(SELECT * FROM bar WHERE name = ?)' => ['john'])
205
+ condition.add_raw('type IS NOT NULL')
206
+ sql = condition.as_sql() # (EXISTS(SELECT * FROM bar WHERE name = ?)) AND (type IS NOT NULL)
207
+ @bind = condition.bind() # ('john')
208
+
209
+ # composite and
210
+ my other = SQL::Maker::Condition.new(
211
+ name_sep => '.',
212
+ quote_char => '`',
213
+ )
214
+ other.add('name' => 'john')
215
+ my $comp_and = condition & other
216
+ sql = $comp_and.as_sql() # ((`foo_id`=?) AND (`bar_id`=?)) AND (`name`=?)
217
+ @bind = $comp_and.bind() # (3, 4, 'john')
218
+
219
+ # composite or
220
+ my $comp_or = condition | other
221
+ sql = $comp_and.as_sql() # ((`foo_id`=?) AND (`bar_id`=?)) OR (`name`=?)
222
+ @bind = $comp_and.bind() # (3, 4, 'john')
223
+
224
+
225
+ =head1 CONDITION CHEAT SHEET
226
+
227
+ Here is a cheat sheet for conditions.
228
+
229
+ IN: {'foo'=>'bar'}
230
+ OUT QUERY: '`foo` = ?'
231
+ OUT BIND: ['bar']
232
+
233
+ IN: {'foo'=>['bar','baz']}
234
+ OUT QUERY: '`foo` IN (?, ?)'
235
+ OUT BIND: ['bar','baz']
236
+
237
+ IN: {'foo'=>{'IN' => ['bar','baz']}}
238
+ OUT QUERY: '`foo` IN (?, ?)'
239
+ OUT BIND: ['bar','baz']
240
+
241
+ IN: {'foo'=>{'not IN' => ['bar','baz']}}
242
+ OUT QUERY: '`foo` NOT IN (?, ?)'
243
+ OUT BIND: ['bar','baz']
244
+
245
+ IN: {'foo'=>{'!=' => 'bar'}}
246
+ OUT QUERY: '`foo` != ?'
247
+ OUT BIND: ['bar']
248
+
249
+ # IN: {'foo'=>\'IS NOT NULL'}
250
+ # OUT QUERY: '`foo` IS NOT NULL'
251
+ # OUT BIND: []
252
+
253
+ IN: {'foo'=>{'between' => ['1','2']}}
254
+ OUT QUERY: '`foo` BETWEEN ? AND ?'
255
+ OUT BIND: ['1','2']
256
+
257
+ IN: {'foo'=>{'like' => 'xaic%'}}
258
+ OUT QUERY: '`foo` LIKE ?'
259
+ OUT BIND: ['xaic%']
260
+
261
+ IN: {'foo'=>[{'>' => 'bar'},{'<' => 'baz'}]}
262
+ OUT QUERY: '(`foo` > ?) OR (`foo` < ?)'
263
+ OUT BIND: ['bar','baz']
264
+
265
+ IN: {'foo'=>{:AND => [{'>' => 'bar'},{'<' => 'baz'}]}}
266
+ OUT QUERY: '(`foo` > ?) AND (`foo` < ?)'
267
+ OUT BIND: ['bar','baz']
268
+
269
+ IN: {'foo'=>{:AND => ['foo','bar','baz']}}
270
+ OUT QUERY: '(`foo` = ?) AND (`foo` = ?) AND (`foo` = ?)'
271
+ OUT BIND: ['foo','bar','baz']
272
+
273
+ IN: {'foo_id'=>{'IN' => sql_raw('SELECT foo_id FROM bar WHERE t=?',44)}}
274
+ OUT QUERY: '`foo_id` IN (SELECT foo_id FROM bar WHERE t=?)'
275
+ OUT BIND: [44]
276
+
277
+ # IN: ['foo_id',\['MATCH (col1, col2) AGAINST (?)','apples']]
278
+ # OUT QUERY: '`foo_id` MATCH (col1, col2) AGAINST (?)'
279
+ # OUT BIND: ['apples']
280
+
281
+ IN: {'foo_id'=>nil}
282
+ OUT QUERY: '`foo_id` IS NULL'
283
+ OUT BIND: []
284
+
285
+ IN: {'foo_id'=>{'IN' => []}}
286
+ OUT QUERY: '0=1'
287
+ OUT BIND: []
288
+
289
+ IN: {'foo_id'=>{'NOT IN' => []}}
290
+ OUT QUERY: '1=1'
291
+ OUT BIND: []
292
+
293
+ # IN: ['foo_id', [123,sql_type(\3, SQL_INTEGER)]]
294
+ # OUT QUERY: '`foo_id` IN (?, ?)'
295
+ # OUT BIND: (123, sql_type(\3, SQL_INTEGER))
296
+ #
297
+ # IN: ['foo_id', sql_type(\3, SQL_INTEGER)]
298
+ # OUT QUERY: '`foo_id` = ?'
299
+ # OUT BIND: sql_type(\3, SQL_INTEGER)
300
+ #
301
+ # IN: ['created_on', { '>', \'DATE_SUB(NOW(), INTERVAL 1 DAY)' }]
302
+ # OUT QUERY: '`created_on` > DATE_SUB(NOW(), INTERVAL 1 DAY)'
303
+ # OUT BIND:
304
+
305
+ It is also possible to use the functions exported by C<SQL::QueryMaker> to define the conditions.
306
+
307
+ IN: {'foo' => sql_in(['bar','baz'])}
308
+ OUT QUERY: '`foo` IN (?,?)'
309
+ OUT BIND: ['bar','baz']
310
+
311
+ IN: {'foo' => sql_lt(3)}
312
+ OUT QUERY: '`foo` < ?'
313
+ OUT BIND: [3]
314
+
315
+ IN: {'foo' => sql_not_in(['bar','baz'])}
316
+ OUT QUERY: '`foo` NOT IN (?,?)'
317
+ OUT BIND: ['bar','baz']
318
+
319
+ IN: {'foo' => sql_ne('bar')}
320
+ OUT QUERY: '`foo` != ?'
321
+ OUT BIND: ['bar']
322
+
323
+ IN: {'foo' => sql_is_not_null()}
324
+ OUT QUERY: '`foo` IS NOT NULL'
325
+ OUT BIND: []
326
+
327
+ IN: {'foo' => sql_between('1','2')}
328
+ OUT QUERY: '`foo` BETWEEN ? AND ?'
329
+ OUT BIND: ['1','2']
330
+
331
+ IN: {'foo' => sql_like('xaic%')}
332
+ OUT QUERY: '`foo` LIKE ?'
333
+ OUT BIND: ['xaic%']
334
+
335
+ IN: {'foo' => sql_or([sql_gt('bar'), sql_lt('baz')])}
336
+ OUT QUERY: '(`foo` > ?) OR (`foo` < ?)'
337
+ OUT BIND: ['bar','baz']
338
+
339
+ IN: {'foo' => sql_and([sql_gt('bar'), sql_lt('baz')])}
340
+ OUT QUERY: '(`foo` > ?) AND (`foo` < ?)'
341
+ OUT BIND: ['bar','baz']
342
+
343
+ IN: {'foo_id' => sql_op('IN (SELECT foo_id FROM bar WHERE t=?)',[44])}
344
+ OUT QUERY: '`foo_id` IN (SELECT foo_id FROM bar WHERE t=?)'
345
+ OUT BIND: [44]
346
+
347
+ IN: {'foo_id' => sql_in([sql_raw('SELECT foo_id FROM bar WHERE t=?',44)])}
348
+ OUT QUERY: '`foo_id` IN ((SELECT foo_id FROM bar WHERE t=?))'
349
+ OUT BIND: [44]
350
+
351
+ IN: {'foo_id' => sql_op('MATCH (@) AGAINST (?)',['apples'])}
352
+ OUT QUERY: 'MATCH (`foo_id`) AGAINST (?)'
353
+ OUT BIND: ['apples']
354
+
355
+ IN: {'foo_id'=>sql_in([])}
356
+ OUT QUERY: '0=1'
357
+ OUT BIND: []
358
+
359
+ IN: {'foo_id'=>sql_not_in([])}
360
+ OUT QUERY: '1=1'
361
+ OUT BIND: []
362
+
363
+ # IN: ['foo_id', sql_type(\3, SQL_INTEGER)]
364
+ # OUT QUERY: '`foo_id` = ?'
365
+ # OUT BIND: sql_type(\3, SQL_INTEGER)
366
+ #
367
+ # IN: ['foo_id', sql_in([sql_type(\3, SQL_INTEGER)])]
368
+ # OUT QUERY: '`foo_id` IN (?)'
369
+ # OUT BIND: sql_type(\3, SQL_INTEGER)
370
+ #
371
+ # IN: ['created_on', sql_gt(sql_raw('DATE_SUB(NOW(), INTERVAL 1 DAY)')) ]
372
+ # OUT QUERY: '`created_on` > DATE_SUB(NOW(), INTERVAL 1 DAY)'
373
+ # OUT BIND:
374
+
375
+ =head1 SEE ALSO
376
+
377
+ L<SQL::Maker>
378
+
@@ -0,0 +1,3 @@
1
+ class SQL::Maker
2
+ class Error < StandardError; end
3
+ end
@@ -0,0 +1,22 @@
1
+ require 'sql/query_maker'
2
+ require 'sql/maker/select_set'
3
+
4
+ module SQL::Maker::Helper
5
+ # SQL::QueryMaker Helper
6
+ (%w[and or in not_in op raw] + SQL::QueryMaker::FNOP.keys).each do |fn|
7
+ method = "sql_#{fn}" # sql_and
8
+ define_method(method) do |*args|
9
+ SQL::QueryMaker.send(method, *args)
10
+ end
11
+ module_function method
12
+ end
13
+
14
+ # SQL::Maker::SelectSet Helper
15
+ SQL::Maker::SelectSet::FNOP.each do |fn|
16
+ method = "sql_#{fn}" # sql_union
17
+ define_method(method) do |*args|
18
+ SQL::Maker::SelectSet.send(method, *args)
19
+ end
20
+ module_function method
21
+ end
22
+ end
@@ -0,0 +1,138 @@
1
+ # reference: ActiveRecord::ConnectionAdapter::Quoting
2
+ require 'yaml'
3
+
4
+ module SQL::Maker::Quoting
5
+ # Quotes the value rather than column name to help prevent
6
+ # {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
7
+ def self.quote(value, column = nil)
8
+ case value
9
+ when String
10
+ value = value.to_s
11
+ return "'#{quote_string(value)}'" unless column
12
+
13
+ case column.type
14
+ when :integer then value.to_i.to_s
15
+ when :float then value.to_f.to_s
16
+ else
17
+ "'#{quote_string(value)}'"
18
+ end
19
+
20
+ when true, false
21
+ if column && column.type == :integer
22
+ value ? '1' : '0'
23
+ else
24
+ value ? quoted_true : quoted_false
25
+ end
26
+ # BigDecimals need to be put in a non-normalized form and quoted.
27
+ when nil then "NULL"
28
+ when BigDecimal then value.to_s('F')
29
+ when Numeric then value.to_s
30
+ when Date, Time then "'#{quoted_date(value)}'"
31
+ when Symbol then "'#{quote_string(value.to_s)}'"
32
+ when Class then "'#{value.to_s}'"
33
+ else
34
+ "'#{quote_string(YAML.dump(value))}'"
35
+ end
36
+ end
37
+
38
+ # Cast a +value+ to a type that the database understands. For example,
39
+ # SQLite does not understand dates, so this method will convert a Date
40
+ # to a String.
41
+ def self.type_cast(value, column)
42
+ return value.id if value.respond_to?(:quoted_id)
43
+
44
+ case value
45
+ when String
46
+ value = value.to_s
47
+ return value unless column
48
+
49
+ case column.type
50
+ when :integer then value.to_i
51
+ when :float then value.to_f
52
+ else
53
+ value
54
+ end
55
+
56
+ when true, false
57
+ if column && column.type == :integer
58
+ value ? 1 : 0
59
+ else
60
+ value ? 't' : 'f'
61
+ end
62
+ # BigDecimals need to be put in a non-normalized form and quoted.
63
+ when nil then nil
64
+ when BigDecimal then value.to_s('F')
65
+ when Numeric then value
66
+ when Date, Time then quoted_date(value)
67
+ when Symbol then value.to_s
68
+ else
69
+ to_type = column ? " to #{column.type}" : ""
70
+ raise TypeError, "can't cast #{value.class}#{to_type}"
71
+ end
72
+ end
73
+
74
+ # Quotes a string, escaping any ' (single quote) and \ (backslash)
75
+ # characters.
76
+ def self.quote_string(s)
77
+ s.gsub(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
78
+ end
79
+
80
+ # # def quote_string(s)
81
+ # def self.define_quote_string
82
+ # klass = self.singleton_class
83
+ # return if klass.method_defined?(:quote_string)
84
+ # if @driver == 'mysql' and defined?(Mysql2::Client)
85
+ # klass.send(:define_method, :quote_string) do |s|
86
+ # Mysql2::Client.escape(s) if s
87
+ # end
88
+ # elsif @driver == 'postgresql' and defined?(PG::Connection)
89
+ # klass.send(:define_method, :quote_string) do |s|
90
+ # PG::Connection.escape_string(s) if s
91
+ # end
92
+ # else
93
+ # # Escape any ' (single quote) and \ (backslash)
94
+ # # reference: ActiveRecord::ConnectionAdapter::Quoting
95
+ # klass.send(:define_method, :quote_string) do |s|
96
+ # s.gsub(/\\/, '\&\&').gsub(/'/, "''") if s # ' (for ruby-mode)
97
+ # end
98
+ # end
99
+ # end
100
+
101
+ # Quotes the column name. Defaults to no quoting.
102
+ def self.quote_column_name(column_name)
103
+ column_name
104
+ end
105
+
106
+ # Quotes the table name. Defaults to column name quoting.
107
+ def self.quote_table_name(table_name)
108
+ quote_column_name(table_name)
109
+ end
110
+
111
+ # Override to return the quoted table name for assignment. Defaults to
112
+ # table quoting.
113
+ #
114
+ # This works for mysql and mysql2 where table.column can be used to
115
+ # resolve ambiguity.
116
+ #
117
+ # We override this in the sqlite and postgresql adapters to use only
118
+ # the column name (as per syntax requirements).
119
+ def self.quote_table_name_for_assignment(table, attr)
120
+ quote_table_name("#{table}.#{attr}")
121
+ end
122
+
123
+ def self.quoted_true
124
+ "'t'"
125
+ end
126
+
127
+ def self.quoted_false
128
+ "'f'"
129
+ end
130
+
131
+ def self.quoted_date(value)
132
+ if value.is_a?(Time)
133
+ # ToDo: getutc support
134
+ value = value.getlocal
135
+ end
136
+ value.strftime("%Y-%m-%d %H:%M:%S")
137
+ end
138
+ end