ar-extensions 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -14,8 +14,12 @@ end
14
14
 
15
15
  ADAPTERS = %w( mysql postgresql sqlite sqlite3 oracle )
16
16
 
17
- namespace :db do
17
+ desc "Packages a rubygem"
18
+ task "pkg" do
19
+
20
+ end
18
21
 
22
+ namespace :db do
19
23
  namespace :test do
20
24
  ADAPTERS.each do |adapter|
21
25
  desc "builds test database for #{adapter}"
@@ -25,21 +29,17 @@ namespace :db do
25
29
  end
26
30
  end
27
31
  end
28
-
29
32
  end
30
33
 
31
34
  namespace :test do
32
-
33
35
  ADAPTERS.each do |adapter|
34
36
  desc "test base extensions for #{adapter}"
35
37
  task adapter do |t|
36
38
  ENV['ARE_DB'] = adapter
37
- Rake::Task[ 'boot' ].invoke
38
-
39
39
  task = Rake::Task[ "db:test:prepare_#{adapter}" ]
40
- begin
40
+ begin
41
41
  task = false if SchemaInfo::VERSION == SchemaInfo.find( :first ).version
42
- rescue Exception => ex
42
+ rescue Exception => ex
43
43
  end
44
44
  task.invoke if task
45
45
 
@@ -48,7 +48,6 @@ namespace :test do
48
48
  end
49
49
 
50
50
  namespace :activerecord do
51
-
52
51
  ADAPTERS.each do |adapter|
53
52
  desc "runs ActiveRecord unit tests for #{adapter} with ActiveRecord::Extensions"
54
53
  task adapter.to_sym do |t|
@@ -67,9 +66,6 @@ namespace :test do
67
66
  Dir.chdir( old_dir )
68
67
  ENV['RUBYOPT'] = old_env
69
68
  end
70
-
71
69
  end
72
-
73
70
  end
74
-
75
- end
71
+ end
@@ -5,6 +5,11 @@ ActiveRecord::Schema.define do
5
5
  end
6
6
  SchemaInfo.create :version=>SchemaInfo::VERSION
7
7
 
8
+ create_table :group, :force => true do |t|
9
+ t.column :order, :string
10
+ t.timestamps
11
+ end
12
+
8
13
  create_table :topics, :force=>true do |t|
9
14
  t.column :title, :string, :null=>false
10
15
  t.column :author_name, :string
@@ -48,11 +53,12 @@ ActiveRecord::Schema.define do
48
53
  t.column :title, :string, :null=>false
49
54
  t.column :publisher, :string, :null=>false
50
55
  t.column :author_name, :string, :null=>false
51
- t.column :created_at, :time
56
+ t.column :created_at, :datetime
52
57
  t.column :created_on, :datetime
53
- t.column :updated_at, :time
58
+ t.column :updated_at, :datetime
54
59
  t.column :updated_on, :datetime
55
60
  t.column :topic_id, :integer
61
+ t.column :for_sale, :boolean, :default => true
56
62
  end
57
63
 
58
64
  create_table :languages, :force=>true do |t|
@@ -24,6 +24,7 @@ ActiveRecord::Schema.define do
24
24
  t.column :updated_at, :datetime
25
25
  t.column :updated_on, :datetime
26
26
  t.column :topic_id, :integer
27
+ t.column :for_sale, :boolean, :default => true
27
28
  end
28
29
  execute "ALTER TABLE books ADD FULLTEXT( `title`, `publisher`, `author_name` )"
29
30
 
@@ -0,0 +1,5 @@
1
+ ActiveRecord::Schema.define do
2
+
3
+ execute "CREATE SEQUENCE books_seq START_WITH 1"
4
+
5
+ end
@@ -1,4 +1,4 @@
1
1
  class SchemaInfo < ActiveRecord::Base
2
2
  set_table_name 'schema_info'
3
- VERSION = 8
3
+ VERSION = 10
4
4
  end
data/init.rb CHANGED
@@ -1,34 +1,13 @@
1
1
  require 'ostruct'
2
2
  begin ; require 'active_record' ; rescue LoadError; require 'rubygems'; require 'active_record'; end
3
3
 
4
- dir = File.dirname( __FILE__ )
5
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'version' ) )
6
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'extensions' ) )
7
-
8
- begin
9
- require 'faster_csv'
10
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'csv' ) )
11
- rescue LoadError
12
- STDERR.puts "FasterCSV is not installed. CSV functionality will not be included."
13
- end
14
-
15
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'foreign_keys' ) )
16
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'fulltext' ) )
17
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'fulltext', 'mysql' ) )
18
-
19
- db_adapters_path = File.expand_path( File.join( dir, 'lib/ar-extensions', 'adapters' ) )
20
-
21
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'import' ) )
22
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'import', 'mysql' ) )
23
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'import', 'postgresql' ) )
24
-
25
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'finders' ) )
26
-
27
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'synchronize' ) )
28
-
29
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'temporary_table' ) )
30
- require File.expand_path( File.join( dir, 'lib/ar-extensions', 'temporary_table', 'mysql' ) )
31
-
32
- require File.expand_path( File.join( db_adapters_path, 'abstract_adapter' ) )
33
- require File.expand_path( File.join( db_adapters_path,'mysql_adapter' ) )
34
-
4
+ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
5
+ require 'ar-extensions/version'
6
+ require 'ar-extensions/extensions'
7
+ require 'ar-extensions/foreign_keys'
8
+ require 'ar-extensions/fulltext'
9
+ require 'ar-extensions/import'
10
+ require 'ar-extensions/finders'
11
+ require 'ar-extensions/synchronize'
12
+ require 'ar-extensions/temporary_table'
13
+ require 'ar-extensions/adapters/abstract_adapter'
@@ -4,6 +4,10 @@ module ActiveRecord # :nodoc:
4
4
  NO_MAX_PACKET = 0
5
5
  QUERY_OVERHEAD = 8 #This was shown to be true for MySQL, but it's not clear where the overhead is from.
6
6
 
7
+ def next_value_for_sequence(sequence_name)
8
+ %{#{sequence_name}.nextval}
9
+ end
10
+
7
11
  # +sql+ can be a single string or an array. If it is an array all
8
12
  # elements that are in position >= 1 will be appended to the final SQL.
9
13
  def insert_many( sql, values, *args ) # :nodoc:
@@ -52,6 +56,35 @@ module ActiveRecord # :nodoc:
52
56
  instances.each { |e| e.reload }
53
57
  end
54
58
 
59
+ # Returns an array of post SQL statements given the passed in options.
60
+ def post_sql_statements( table_name, options ) # :nodoc:
61
+ post_sql_statements = []
62
+ if options[:on_duplicate_key_update]
63
+ post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update] )
64
+ end
65
+ post_sql_statements
66
+ end
67
+
68
+
69
+ # Generates the INSERT statement used in insert multiple value sets.
70
+ def multiple_value_sets_insert_sql(table_name, column_names, options) # :nodoc:
71
+ "INSERT #{options[:ignore] ? 'IGNORE ':''}INTO #{table_name} (#{column_names.join(',')}) VALUES "
72
+ end
73
+
74
+ # Returns SQL the VALUES for an INSERT statement given the passed in +columns+
75
+ # and +array_of_attributes+.
76
+ def values_sql_for_column_names_and_attributes( columns, array_of_attributes ) # :nodoc:
77
+ values = []
78
+ array_of_attributes.each do |arr|
79
+ my_values = []
80
+ arr.each_with_index do |val,j|
81
+ my_values << quote( val, columns[j] )
82
+ end
83
+ values << my_values
84
+ end
85
+ values_arr = values.map{ |arr| '(' + arr.join( ',' ) + ')' }
86
+ end
87
+
55
88
  # Returns the sum of the sizes of the passed in objects. This should
56
89
  # probably be moved outside this class, but to where?
57
90
  def self.sum_sizes( *objects ) # :nodoc:
@@ -0,0 +1,8 @@
1
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
2
+ # Returns the maximum number of bytes that the server will allow
3
+ # in a single packet
4
+ def max_allowed_packet # :nodoc:
5
+ result = execute( "SHOW VARIABLES like 'max_allowed_packet';" )
6
+ result.fetch_row[1].to_i
7
+ end
8
+ end
@@ -1,9 +1,14 @@
1
1
  module ActiveRecord # :nodoc:
2
2
  module ConnectionAdapters # :nodoc:
3
3
  class OracleAdapter # :nodoc:
4
- def supports_import?
5
- true
6
- end
4
+
5
+ def next_value_for_sequence(sequence_name)
6
+ %{#{sequence_name}.nextval}
7
+ end
8
+
9
+ def supports_import?
10
+ true
11
+ end
7
12
  end
8
13
  end
9
14
  end
@@ -1,7 +1,9 @@
1
1
  module ActiveRecord # :nodoc:
2
2
  module ConnectionAdapters # :nodoc:
3
3
  class PostgreSQLAdapter # :nodoc:
4
-
4
+ def next_value_for_sequence(sequence_name)
5
+ %{nextval('#{sequence_name}')}
6
+ end
5
7
  end
6
8
  end
7
9
  end
@@ -0,0 +1,7 @@
1
+ module ActiveRecord # :nodoc:
2
+ module ConnectionAdapters # :nodoc:
3
+ class SqliteAdapter # :nodoc:
4
+
5
+ end
6
+ end
7
+ end
@@ -1,6 +1,11 @@
1
+ begin
2
+ require 'faster_csv'
3
+ require 'ar-extensions/csv'
4
+ rescue LoadError => ex
5
+ STDERR.puts "FasterCSV is not installed. CSV functionality will not be included."
6
+ raise ex
7
+ end
1
8
 
2
- require 'faster_csv'
3
- require 'ostruct'
4
9
 
5
10
  # Adds CSV export options to ActiveRecord::Base models.
6
11
  #
@@ -46,7 +46,7 @@ require 'forwardable'
46
46
  # fieldname = caller.connection.quote_column_name( key )
47
47
  # min = caller.connection.quote( val.first, caller.columns_hash[ key ] )
48
48
  # max = caller.connection.quote( val.last, caller.columns_hash[ key ] )
49
- # str = "#{caller.table_name}.#{fieldname} #{match_data ? 'NOT ' : '' } BETWEEN #{min} AND #{max}"
49
+ # str = "#{caller.quoted_table_name}.#{fieldname} #{match_data ? 'NOT ' : '' } BETWEEN #{min} AND #{max}"
50
50
  # Result.new( str, nil )
51
51
  # end
52
52
  #
@@ -180,7 +180,7 @@ module ActiveRecord::Extensions
180
180
  if val.is_a?( Array )
181
181
  match_data = key.to_s.match( NOT_EQUAL_RGX )
182
182
  key = match_data.captures[0] if match_data
183
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( key )} " +
183
+ str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( key )} " +
184
184
  (match_data ? 'NOT ' : '') + "IN( ? )"
185
185
  return Result.new( str, val )
186
186
  end
@@ -206,6 +206,7 @@ module ActiveRecord::Extensions
206
206
  class Comparison
207
207
 
208
208
  SUFFIX_MAP = { 'eq'=>'=', 'lt'=>'<', 'lte'=>'<=', 'gt'=>'>', 'gte'=>'>=', 'ne'=>'!=', 'not'=>'!=' }
209
+ ACCEPTABLE_COMPARISONS = [ String, Numeric, Time, DateTime ]
209
210
 
210
211
  def self.process( key, val, caller )
211
212
  process_without_suffix( key, val, caller ) || process_with_suffix( key, val, caller )
@@ -214,21 +215,21 @@ module ActiveRecord::Extensions
214
215
  def self.process_without_suffix( key, val, caller )
215
216
  return nil unless caller.columns_hash.has_key?( key )
216
217
  if val.nil?
217
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( key )} IS NULL"
218
+ str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( key )} is ?"
218
219
  else
219
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( key )}=?"
220
+ str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( key )}=?"
220
221
  end
221
222
  Result.new( str, val )
222
223
  end
223
224
 
224
- def self.process_with_suffix( key, val, caller )
225
- return nil unless val.is_a?( String ) or val.is_a?( Numeric )
225
+ def self.process_with_suffix( key, val, caller )
226
+ return nil unless ACCEPTABLE_COMPARISONS.find{ |klass| val.is_a?(klass) }
226
227
  SUFFIX_MAP.each_pair do |k,v|
227
228
  match_data = key.to_s.match( /(.+)_#{k}$/ )
228
229
  if match_data
229
230
  fieldname = match_data.captures[0]
230
231
  return nil unless caller.columns_hash.has_key?( fieldname )
231
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( fieldname )} " +
232
+ str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( fieldname )} " +
232
233
  "#{v} #{caller.connection.quote( val, caller.columns_hash[ fieldname ] )} "
233
234
  return Result.new( str, nil )
234
235
  end
@@ -254,30 +255,35 @@ module ActiveRecord::Extensions
254
255
  LIKE_RGX = /(.+)_(like|contains)$/
255
256
  STARTS_WITH_RGX = /(.+)_starts_with$/
256
257
  ENDS_WITH_RGX = /(.+)_ends_with$/
257
-
258
258
  def self.process( key, val, caller )
259
259
  values = [*val]
260
260
  case key.to_s
261
261
  when LIKE_RGX
262
262
  str = values.collect do |v|
263
- "#{caller.table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
263
+ "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
264
264
  "#{caller.connection.quote( '%%' + v + '%%', caller.columns_hash[ $1 ] )} "
265
265
  end
266
266
  when STARTS_WITH_RGX
267
267
  str = values.collect do |v|
268
- "#{caller.table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
268
+ "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
269
269
  "#{caller.connection.quote( v + '%%', caller.columns_hash[ $1 ] )} "
270
270
  end
271
271
  when ENDS_WITH_RGX
272
272
  str = values.collect do |v|
273
- "#{caller.table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
273
+ "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
274
274
  "#{caller.connection.quote( '%%' + v, caller.columns_hash[ $1 ] )} "
275
275
  end
276
276
  else
277
277
  return nil
278
278
  end
279
279
 
280
- return Result.new( str.join(' OR '), nil)
280
+ str = str.join(' OR ')
281
+ result_values = []
282
+ str.gsub!(/'((%%)?([^\?]*\?[^%]*|[^%]*%[^%]*)(%%)?)'/) do |match|
283
+ result_values << $2
284
+ '?'
285
+ end
286
+ return Result.new(str , result_values)
281
287
  end
282
288
  end
283
289
 
@@ -308,7 +314,7 @@ module ActiveRecord::Extensions
308
314
  fieldname = caller.connection.quote_column_name( key )
309
315
  min = caller.connection.quote( val.first, caller.columns_hash[ key ] )
310
316
  max = caller.connection.quote( val.last, caller.columns_hash[ key ] )
311
- str = "#{caller.table_name}.#{fieldname} #{match_data ? 'NOT ' : '' } BETWEEN #{min} AND #{max}"
317
+ str = "#{caller.quoted_table_name}.#{fieldname} #{match_data ? 'NOT ' : '' } BETWEEN #{min} AND #{max}"
312
318
  return Result.new( str, nil )
313
319
  end
314
320
  nil
@@ -375,7 +381,7 @@ module ActiveRecord::Extensions
375
381
  def self.process( key, val, caller )
376
382
  return nil unless val.is_a?( Regexp )
377
383
  r = field_result( key, caller )
378
- Result.new( "#{caller.table_name}.#{r.fieldname} #{r.negate? ? 'NOT ':''} REGEXP ?", val )
384
+ Result.new( "#{caller.quoted_table_name}.#{r.fieldname} #{r.negate? ? 'NOT ':''} REGEXP ?", val )
379
385
  end
380
386
 
381
387
  end
@@ -390,7 +396,7 @@ module ActiveRecord::Extensions
390
396
  def self.process( key, val, caller )
391
397
  return nil unless val.is_a?( Regexp )
392
398
  r = field_result( key, caller )
393
- return Result.new( "#{caller.table_name}.#{r.fieldname} #{r.negate? ? '!~ ':'~'} ?", val )
399
+ return Result.new( "#{caller.quoted_table_name}.#{r.fieldname} #{r.negate? ? '!~ ':'~'} ?", val )
394
400
  end
395
401
 
396
402
  end
@@ -403,7 +409,7 @@ module ActiveRecord::Extensions
403
409
  def self.process( key, val, caller )
404
410
  return nil unless val.is_a?( Regexp )
405
411
  r = field_result( key, caller )
406
- return Result.new( "#{r.negate? ? ' NOT ':''} REGEXP_LIKE(#{caller.table_name}.#{r.fieldname} , ?)", val )
412
+ return Result.new( "#{r.negate? ? ' NOT ':''} REGEXP_LIKE(#{caller.quoted_table_name}.#{r.fieldname} , ?)", val )
407
413
  end
408
414
 
409
415
  end
@@ -453,9 +459,9 @@ module ActiveRecord::Extensions
453
459
  def self.process_without_suffix( key, val, caller )
454
460
  return nil unless caller.columns_hash.has_key?( key )
455
461
  if val.nil?
456
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( key )} IS NULL"
462
+ str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( key )} IS NULL"
457
463
  else
458
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( key )}=" +
464
+ str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( key )}=" +
459
465
  "#{caller.connection.quote( val.to_s(:db), caller.columns_hash[ key ] )} "
460
466
  end
461
467
  Result.new( str, nil )
@@ -467,7 +473,7 @@ module ActiveRecord::Extensions
467
473
  if match_data
468
474
  fieldname = match_data.captures[0]
469
475
  return nil unless caller.columns_hash.has_key?( fieldname )
470
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( fieldname )} " +
476
+ str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( fieldname )} " +
471
477
  "#{v} #{caller.connection.quote( val.to_s(:db), caller.columns_hash[ fieldname ] )} "
472
478
  return Result.new( str, nil )
473
479
  end
@@ -19,7 +19,7 @@ class ActiveRecord::Base
19
19
 
20
20
  alias :sanitize_sql_orig :sanitize_sql
21
21
  def sanitize_sql( arg ) # :nodoc:
22
- return sanitize_sql_orig( arg ) if arg.nil?
22
+ return if arg.blank? # don't process arguments like [], {}, "" or nil
23
23
  if arg.respond_to?( :to_sql )
24
24
  arg = sanitize_sql_by_way_of_duck_typing( arg )
25
25
  elsif arg.is_a?( Hash )
@@ -35,7 +35,8 @@ class ActiveRecord::Base
35
35
  end
36
36
 
37
37
  def sanitize_sql_from_string_and_hash( arr ) # :nodoc:
38
- return arr if arr.first =~ /\:[\w]+/
38
+ return arr if arr.first =~ /\:[\w]+/
39
+ return arr if arr.last.empty? # skip empty hash conditions, ie: :conditions => ["", {}]
39
40
  arr2 = sanitize_sql_from_hash( arr.last )
40
41
  if arr2.empty?
41
42
  conditions = arr.first
@@ -48,7 +49,8 @@ class ActiveRecord::Base
48
49
 
49
50
  def sanitize_sql_from_hash( hsh ) #:nodoc:
50
51
  conditions, values = [], []
51
-
52
+ hsh = expand_hash_conditions_for_aggregates(hsh) # introduced in Rails 2.0.2
53
+
52
54
  hsh.each_pair do |key,val|
53
55
  if val.respond_to?( :to_sql )
54
56
  conditions << sanitize_sql_by_way_of_duck_typing( val )
@@ -57,10 +59,19 @@ class ActiveRecord::Base
57
59
  sql = nil
58
60
  result = ActiveRecord::Extensions.process( key, val, self )
59
61
  if result
60
- conditions << result.sql if result.sql
61
- values.push( result.value ) if result.value
62
+ conditions << result.sql
63
+ values.push( result.value )
62
64
  else
63
- conditions << "#{table_name}.#{connection.quote_column_name(key.to_s)} #{attribute_condition( val )} "
65
+ # Extract table name from qualified attribute names.
66
+ attr = key.to_s
67
+ if attr.include?('.')
68
+ table_name, attr = attr.split('.', 2)
69
+ table_name = connection.quote_table_name(table_name)
70
+ else
71
+ table_name = quoted_table_name
72
+ end
73
+
74
+ conditions << "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition( val )} "
64
75
  values << val
65
76
  end
66
77
  end
@@ -51,7 +51,6 @@ class ActiveRecord::Base
51
51
  rescue NoMethodError
52
52
  false
53
53
  end
54
-
55
54
  end
56
55
 
57
56
  end
@@ -35,7 +35,7 @@ class ActiveRecord::Extensions::FullTextSearching::MySQLFullTextExtension
35
35
  end
36
36
  ActiveRecord::Extensions.register ActiveRecord::Extensions::FullTextSearching::MySQLFullTextExtension.new, :adapters=>[:mysql]
37
37
 
38
- class ActiveRecord::ConnectionAdapters::MysqlAdapter # :nodoc:
38
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
39
39
  include ActiveRecord::Extensions::FullTextSearching::FullTextSupport
40
40
 
41
41
  def register_fulltext_extension( fulltext_key, options ) # :nodoc:
@@ -262,29 +262,29 @@ class ActiveRecord::Base
262
262
  array_of_attributes.each do |arr|
263
263
  my_values = []
264
264
  arr.each_with_index do |val,j|
265
- if sequence_name && column_names[j] == primary_key && val.nil?
266
- my_values << "#{sequence_name}.nextval"
265
+ if !sequence_name.blank? && column_names[j] == primary_key && val.nil?
266
+ my_values << connection.next_value_for_sequence(sequence_name)
267
267
  else
268
268
  my_values << connection.quote( val, columns[j] )
269
269
  end
270
270
  end
271
- insert_statements << "INSERT INTO #{self.table_name} #{columns_sql} VALUES(" + my_values.join( ',' ) + ")"
272
- number_inserted = number_inserted + connection.execute( insert_statements.last )
271
+ insert_statements << "INSERT INTO #{quoted_table_name} #{columns_sql} VALUES(" + my_values.join( ',' ) + ")"
272
+ connection.execute( insert_statements.last )
273
+ number_inserted += 1
273
274
  end
274
- return number_inserted
275
275
  else
276
-
277
276
  # generate the sql
278
- insert_sql = connection.multiple_value_sets_insert_sql( table_name, escaped_column_names, options )
277
+ insert_sql = connection.multiple_value_sets_insert_sql( quoted_table_name, escaped_column_names, options )
279
278
  values_sql = connection.values_sql_for_column_names_and_attributes( columns, array_of_attributes )
280
- post_sql_statements = connection.post_sql_statements( table_name, options )
279
+ post_sql_statements = connection.post_sql_statements( quoted_table_name, options )
281
280
 
282
281
  # perform the inserts
283
- number_of_inserts = connection.insert_many(
284
- [ insert_sql, post_sql_statements ].flatten,
285
- values_sql,
286
- "#{self.class.name} Create Many Without Validations Or Callbacks" )
282
+ number_inserted = connection.insert_many( [ insert_sql, post_sql_statements ].flatten,
283
+ values_sql,
284
+ "#{self.class.name} Create Many Without Validations Or Callbacks" )
287
285
  end
286
+
287
+ number_inserted
288
288
  end
289
289
 
290
290
  # Returns an array of quoted column names
@@ -2,20 +2,7 @@ module ActiveRecord::Extensions::ConnectionAdapters::MysqlAdapter # :nodoc:
2
2
 
3
3
  include ActiveRecord::Extensions::Import::ImportSupport
4
4
  include ActiveRecord::Extensions::Import::OnDuplicateKeyUpdateSupport
5
-
6
- # Returns an array of post SQL statements given the passed in options.
7
- def post_sql_statements( table_name, options ) # :nodoc:
8
- post_sql_statements = []
9
- if options[:on_duplicate_key_update]
10
- post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update] )
11
- end
12
- post_sql_statements
13
- end
14
-
15
- def multiple_value_sets_insert_sql( table_name, column_names, options ) # :nodoc:
16
- "INSERT #{options[:ignore] ? 'IGNORE ':''} INTO #{table_name} (#{column_names.join(',')}) VALUES "
17
- end
18
-
5
+
19
6
  # Returns a generated ON DUPLICATE KEY UPDATE statement given the passed
20
7
  # in +args+.
21
8
  def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
@@ -32,39 +19,25 @@ module ActiveRecord::Extensions::ConnectionAdapters::MysqlAdapter # :nodoc:
32
19
  end
33
20
 
34
21
  def sql_for_on_duplicate_key_update_as_array( table_name, arr ) # :nodoc:
35
- qt = quote_column_name( table_name )
36
22
  results = arr.map do |column|
37
23
  qc = quote_column_name( column )
38
- "#{qt}.#{qc}=VALUES(#{qc})"
24
+ "#{table_name}.#{qc}=VALUES(#{qc})"
39
25
  end
40
26
  results.join( ',' )
41
27
  end
42
28
 
43
29
  def sql_for_on_duplicate_key_update_as_hash( table_name, hsh ) # :nodoc:
44
30
  sql = ' ON DUPLICATE KEY UPDATE '
45
- qt = quote_column_name( table_name )
46
31
  results = hsh.map do |column1, column2|
47
32
  qc1 = quote_column_name( column1 )
48
33
  qc2 = quote_column_name( column2 )
49
- "#{qt}.#{qc1}=VALUES( #{qc2} )"
34
+ "#{table_name}.#{qc1}=VALUES( #{qc2} )"
50
35
  end
51
36
  results.join( ',')
52
37
  end
53
38
 
54
- # Returns SQL the VALUES for an INSERT statement given the passed in +columns+
55
- # and +array_of_attributes+.
56
- def values_sql_for_column_names_and_attributes( columns, array_of_attributes ) # :nodoc:
57
- values = []
58
- array_of_attributes.each do |arr|
59
- my_values = []
60
- arr.each_with_index do |val,j|
61
- my_values << quote( val, columns[j] )
62
- end
63
- values << my_values
64
- end
65
- values_arr = values.map{ |arr| '(' + arr.join( ',' ) + ')' }
66
- end
67
-
68
39
  end
69
40
 
70
- ActiveRecord::ConnectionAdapters::MysqlAdapter.send( 'include', ActiveRecord::Extensions::ConnectionAdapters::MysqlAdapter )
41
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
42
+ include ActiveRecord::Extensions::ConnectionAdapters::MysqlAdapter
43
+ end
@@ -0,0 +1,22 @@
1
+ module ActiveRecord::Extensions::ConnectionAdapters::SQLiteAdapter # :nodoc:
2
+ include ActiveRecord::Extensions::Import::ImportSupport
3
+
4
+ def post_sql_statements( table_name, options )
5
+ []
6
+ end
7
+
8
+ def insert_many( sql, values, *args ) # :nodoc:
9
+ sql2insert = []
10
+ values.each do |value|
11
+ sql2insert << "#{sql} #{value};"
12
+ end
13
+
14
+ raw_connection.transaction { |db| db.execute_batch(sql2insert.join("\n")) }
15
+ number_of_rows_inserted = sql2insert.size
16
+ end
17
+
18
+ end
19
+
20
+ ActiveRecord::ConnectionAdapters::SQLiteAdapter.class_eval do
21
+ include ActiveRecord::Extensions::ConnectionAdapters::SQLiteAdapter
22
+ end
@@ -8,7 +8,7 @@ module ActiveRecord # :nodoc:
8
8
  #
9
9
  # This uses one query for all instance updates and then updates existing
10
10
  # instances rather sending one query for each instance
11
- def self.synchronize(instances, key=ActiveRecord::Base.primary_key)
11
+ def self.synchronize(instances, key=self.primary_key)
12
12
  return if instances.empty?
13
13
 
14
14
  keys = instances.map(&"#{key}".to_sym)
@@ -87,7 +87,6 @@ class ActiveRecord::Base
87
87
  end"
88
88
 
89
89
  @@temporary_table_hsh[ model = Object.const_get( model_name ) ] = true
90
-
91
90
  if block_given?
92
91
  yield model
93
92
  model.drop
@@ -1,3 +1,3 @@
1
- class ActiveRecord::ConnectionAdapters::MysqlAdapter # :nodoc:
1
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
2
2
  include ActiveRecord::Extensions::TemporaryTableSupport
3
3
  end
metadata CHANGED
@@ -1,39 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.2
3
- specification_version: 1
4
2
  name: ar-extensions
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.7.0
7
- date: 2007-07-21 00:00:00 -04:00
8
- summary: Extends ActiveRecord functionality.
9
- require_paths:
10
- - lib
11
- email: zach.dennis@gmail.com
12
- homepage: http://www.continuousthinking.com/tags/arext
13
- rubyforge_project: arext
14
- description: Extends ActiveRecord functionality by adding better finder/query support, as well as supporting mass data import, foreign key, CSV and temporary tables
15
- autorequire: ar-extensions.rb
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.8.0
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Zach Dennis
31
8
  - Mark Van Holstyn
9
+ autorequire: ar-extensions.rb
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2008-08-06 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.14.1
24
+ version:
25
+ description: Extends ActiveRecord functionality by adding better finder/query support, as well as supporting mass data import, foreign key, CSV and temporary tables
26
+ email: zach.dennis@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
32
33
  files:
33
34
  - init.rb
34
35
  - db/migrate
35
36
  - db/migrate/generic_schema.rb
36
37
  - db/migrate/mysql_schema.rb
38
+ - db/migrate/oracle_schema.rb
37
39
  - db/migrate/version.rb
38
40
  - Rakefile
39
41
  - ChangeLog
@@ -43,9 +45,10 @@ files:
43
45
  - config/mysql.schema
44
46
  - config/postgresql.schema
45
47
  - lib/ar-extensions/adapters/abstract_adapter.rb
46
- - lib/ar-extensions/adapters/mysql_adapter.rb
48
+ - lib/ar-extensions/adapters/mysql.rb
47
49
  - lib/ar-extensions/adapters/oracle.rb
48
50
  - lib/ar-extensions/adapters/postgresql.rb
51
+ - lib/ar-extensions/adapters/sqlite.rb
49
52
  - lib/ar-extensions/csv.rb
50
53
  - lib/ar-extensions/extensions.rb
51
54
  - lib/ar-extensions/finders.rb
@@ -54,32 +57,39 @@ files:
54
57
  - lib/ar-extensions/fulltext.rb
55
58
  - lib/ar-extensions/import/mysql.rb
56
59
  - lib/ar-extensions/import/postgresql.rb
60
+ - lib/ar-extensions/import/sqlite.rb
57
61
  - lib/ar-extensions/import.rb
58
62
  - lib/ar-extensions/synchronize.rb
59
63
  - lib/ar-extensions/temporary_table/mysql.rb
60
64
  - lib/ar-extensions/temporary_table.rb
61
65
  - lib/ar-extensions/version.rb
62
66
  - lib/ar-extensions.rb
63
- test_files: []
64
-
67
+ has_rdoc: true
68
+ homepage: http://www.continuousthinking.com/tags/arext
69
+ post_install_message:
65
70
  rdoc_options:
66
71
  - --main
67
72
  - README
68
- extra_rdoc_files:
69
- - README
70
- executables: []
71
-
72
- extensions: []
73
-
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
74
87
  requirements: []
75
88
 
76
- dependencies:
77
- - !ruby/object:Gem::Dependency
78
- name: activerecord
79
- version_requirement:
80
- version_requirements: !ruby/object:Gem::Version::Requirement
81
- requirements:
82
- - - ">="
83
- - !ruby/object:Gem::Version
84
- version: 1.14.1
85
- version:
89
+ rubyforge_project: arext
90
+ rubygems_version: 1.1.0
91
+ signing_key:
92
+ specification_version: 2
93
+ summary: Extends ActiveRecord functionality.
94
+ test_files: []
95
+
@@ -1,14 +0,0 @@
1
- module ActiveRecord # :nodoc:
2
- module ConnectionAdapters # :nodoc:
3
- class MysqlAdapter # :nodoc:
4
-
5
- # Returns the maximum number of bytes that the server will allow
6
- # in a single packet
7
- def max_allowed_packet # :nodoc:
8
- result = execute( "SHOW VARIABLES like 'max_allowed_packet';" )
9
- result.fetch_row[1].to_i
10
- end
11
-
12
- end #end MysqlAdapter
13
- end #end ConnectionAdapters
14
- end #end ActiveRecord