ar-extensions 0.7.0 → 0.8.0
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.
- 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
|