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