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 +8 -12
- data/db/migrate/generic_schema.rb +8 -2
- data/db/migrate/mysql_schema.rb +1 -0
- data/db/migrate/oracle_schema.rb +5 -0
- data/db/migrate/version.rb +1 -1
- data/init.rb +10 -31
- data/lib/ar-extensions/adapters/abstract_adapter.rb +33 -0
- data/lib/ar-extensions/adapters/mysql.rb +8 -0
- data/lib/ar-extensions/adapters/oracle.rb +8 -3
- data/lib/ar-extensions/adapters/postgresql.rb +3 -1
- data/lib/ar-extensions/adapters/sqlite.rb +7 -0
- data/lib/ar-extensions/csv.rb +7 -2
- data/lib/ar-extensions/extensions.rb +25 -19
- data/lib/ar-extensions/finders.rb +17 -6
- data/lib/ar-extensions/fulltext.rb +0 -1
- data/lib/ar-extensions/fulltext/mysql.rb +1 -1
- data/lib/ar-extensions/import.rb +12 -12
- data/lib/ar-extensions/import/mysql.rb +6 -33
- data/lib/ar-extensions/import/sqlite.rb +22 -0
- data/lib/ar-extensions/synchronize.rb +1 -1
- data/lib/ar-extensions/temporary_table.rb +0 -1
- data/lib/ar-extensions/temporary_table/mysql.rb +1 -1
- metadata +53 -43
- data/lib/ar-extensions/adapters/mysql_adapter.rb +0 -14
data/Rakefile
CHANGED
@@ -14,8 +14,12 @@ end
|
|
14
14
|
|
15
15
|
ADAPTERS = %w( mysql postgresql sqlite sqlite3 oracle )
|
16
16
|
|
17
|
-
|
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
|
-
|
40
|
+
begin
|
41
41
|
task = false if SchemaInfo::VERSION == SchemaInfo.find( :first ).version
|
42
|
-
|
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, :
|
56
|
+
t.column :created_at, :datetime
|
52
57
|
t.column :created_on, :datetime
|
53
|
-
t.column :updated_at, :
|
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|
|
data/db/migrate/mysql_schema.rb
CHANGED
@@ -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
|
|
data/db/migrate/version.rb
CHANGED
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
|
-
|
5
|
-
require
|
6
|
-
require
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
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
|
data/lib/ar-extensions/csv.rb
CHANGED
@@ -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.
|
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.
|
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.
|
218
|
+
str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( key )} is ?"
|
218
219
|
else
|
219
|
-
str = "#{caller.
|
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
|
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.
|
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
|
-
|
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.
|
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.
|
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
|
-
|
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.
|
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.
|
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.
|
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.
|
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.
|
462
|
+
str = "#{caller.quoted_table_name}.#{caller.connection.quote_column_name( key )} IS NULL"
|
457
463
|
else
|
458
|
-
str = "#{caller.
|
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.
|
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
|
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
|
61
|
-
values.push( result.value )
|
62
|
+
conditions << result.sql
|
63
|
+
values.push( result.value )
|
62
64
|
else
|
63
|
-
|
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
|
@@ -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
|
-
|
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:
|
data/lib/ar-extensions/import.rb
CHANGED
@@ -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 <<
|
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 #{
|
272
|
-
|
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(
|
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(
|
279
|
+
post_sql_statements = connection.post_sql_statements( quoted_table_name, options )
|
281
280
|
|
282
281
|
# perform the inserts
|
283
|
-
|
284
|
-
|
285
|
-
|
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
|
-
"#{
|
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
|
-
"#{
|
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.
|
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=
|
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)
|
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
|
-
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/
|
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
|
-
|
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
|
-
|
69
|
-
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|