ar-extensions 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,3 +1,11 @@
1
+ 2007-05-05 zdennis <zdennis@elijah.local>
2
+
3
+ * Added ActiveRecord::Base::AbstractAdapter#synchronize method which allows a mass re-synchronization of ActiveRecord instances. This is similar to ActiveRecord::Base#reload except that it works on multiple instances at a time rather then one. This sends one query for all instances rather then 1 per instance reloaded.
4
+
5
+ * Fixed bug with URI encoded strings with a workaround in the Comparison extension. ActiveRecord needs to be fixed to not use the String#% method so strings that do contains percentage signs will not fail
6
+
7
+ * Applied patch from Grant Goodale to allow the Like extension to support arrays when using the '_contains' suffix
8
+
1
9
  2007-03-14 zdennis <zdennis@elijah.xrite.com>
2
10
 
3
11
  * Fixed a bug by renaming the alias for the ActiveRecord::Base#quote method in finders.rb. See rubyforge bug #8996
data/README CHANGED
@@ -9,6 +9,13 @@ Email: zach.dennis@gmail.com
9
9
  - For How-To information see http://www.continuousthinking.com/tags/arext
10
10
  - For project information and feedback please consult http://rubyforge.org/projects/arext/
11
11
  - For release information please see below
12
+
13
+ ActiveRecord::Extensions 0.6.0
14
+ ------------------------------
15
+ May 5th, 2007
16
+ - Fixed bug with URI escaped strings and the Comparison better finder extension
17
+ - Added support for arrays with the Like better finder extension when using the '_contains' suffix
18
+ - Added 'synchronize' support for ActiveRecord::Base instances when using Import functionality
12
19
 
13
20
  ActiveRecord::Extensions 0.5.2
14
21
  ------------------------------
@@ -49,6 +49,7 @@ ActiveRecord::Schema.define do
49
49
  t.column :publisher, :string, :null=>false
50
50
  t.column :author_name, :string, :null=>false
51
51
  t.column :created_at, :time
52
+ t.column :topic_id, :integer
52
53
  end
53
54
 
54
55
  create_table :languages, :force=>true do |t|
@@ -20,6 +20,7 @@ ActiveRecord::Schema.define do
20
20
  t.column :publisher, :string, :null=>false
21
21
  t.column :author_name, :string, :null=>false
22
22
  t.column :created_at, :datetime
23
+ t.column :topic_id, :integer
23
24
  end
24
25
  execute "ALTER TABLE books ADD FULLTEXT( `title`, `publisher`, `author_name` )"
25
26
 
@@ -1,4 +1,4 @@
1
1
  class SchemaInfo < ActiveRecord::Base
2
2
  set_table_name 'schema_info'
3
- VERSION = 5
3
+ VERSION = 6
4
4
  end
data/init.rb CHANGED
@@ -24,6 +24,8 @@ require File.expand_path( File.join( dir, 'lib/ar-extensions', 'import', 'postg
24
24
 
25
25
  require File.expand_path( File.join( dir, 'lib/ar-extensions', 'finders' ) )
26
26
 
27
+ require File.expand_path( File.join( dir, 'lib/ar-extensions', 'synchronize' ) )
28
+
27
29
  require File.expand_path( File.join( dir, 'lib/ar-extensions', 'temporary_table' ) )
28
30
  require File.expand_path( File.join( dir, 'lib/ar-extensions', 'temporary_table', 'mysql' ) )
29
31
 
@@ -44,6 +44,12 @@ module ActiveRecord # :nodoc:
44
44
 
45
45
  number_of_inserts
46
46
  end
47
+
48
+ # Synchronizes the passed in ActiveRecord instances with the records in
49
+ # the database by calling +reload+ on each instance.
50
+ def after_import_synchronize( instances )
51
+ instances.each { |e| e.reload }
52
+ end
47
53
 
48
54
  # Returns the sum of the sizes of the passed in objects. This should
49
55
  # probably be moved outside this class, but to where?
@@ -216,10 +216,9 @@ module ActiveRecord::Extensions
216
216
  if val.nil?
217
217
  str = "#{caller.table_name}.#{caller.connection.quote_column_name( key )} IS NULL"
218
218
  else
219
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( key )}=" +
220
- "#{caller.connection.quote( val, caller.columns_hash[ key ] )} "
219
+ str = "#{caller.table_name}.#{caller.connection.quote_column_name( key )}=?"
221
220
  end
222
- Result.new( str, nil )
221
+ Result.new( str, val )
223
222
  end
224
223
 
225
224
  def self.process_with_suffix( key, val, caller )
@@ -257,22 +256,29 @@ module ActiveRecord::Extensions
257
256
  ENDS_WITH_RGX = /(.+)_ends_with$/
258
257
 
259
258
  def self.process( key, val, caller )
260
- if match_data=key.to_s.match( LIKE_RGX )
261
- fieldname = match_data.captures[0]
262
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( fieldname )} LIKE ?"
263
- return Result.new( str, "%#{val}%" )
264
- elsif match_data=key.to_s.match( STARTS_WITH_RGX )
265
- fieldname = match_data.captures[0]
266
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( fieldname )} LIKE ?"
267
- return Result.new( str, "#{val}%" )
268
- elsif match_data=key.to_s.match( ENDS_WITH_RGX )
269
- fieldname = match_data.captures[0]
270
- str = "#{caller.table_name}.#{caller.connection.quote_column_name( fieldname )} LIKE ?"
271
- return Result.new( str, "%#{val}" )
259
+ values = [*val]
260
+ case key.to_s
261
+ when LIKE_RGX
262
+ str = values.collect do |v|
263
+ "#{caller.table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
264
+ "#{caller.connection.quote( '%%' + v + '%%', caller.columns_hash[ $1 ] )} "
265
+ end
266
+ when STARTS_WITH_RGX
267
+ str = values.collect do |v|
268
+ "#{caller.table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
269
+ "#{caller.connection.quote( v + '%%', caller.columns_hash[ $1 ] )} "
270
+ end
271
+ when ENDS_WITH_RGX
272
+ str = values.collect do |v|
273
+ "#{caller.table_name}.#{caller.connection.quote_column_name( $1 )} LIKE " +
274
+ "#{caller.connection.quote( '%%' + v, caller.columns_hash[ $1 ] )} "
275
+ end
276
+ else
277
+ return nil
272
278
  end
273
- nil
279
+
280
+ return Result.new( str.join(' OR '), nil)
274
281
  end
275
-
276
282
  end
277
283
 
278
284
 
@@ -461,8 +467,8 @@ end
461
467
 
462
468
 
463
469
  register Comparison, :adapters=>:all
464
- register Like, :adapters=>:all
465
470
  register ArrayExt, :adapters=>:all
471
+ register Like, :adapters=>:all
466
472
  register RangeExt, :adapters=>:all
467
473
  register MySQLRegexp, :adapters=>[ :mysql ]
468
474
  register PostgreSQLRegexp, :adapters=>[ :postgresql ]
@@ -21,11 +21,11 @@ class ActiveRecord::Base
21
21
  def sanitize_sql( arg ) # :nodoc:
22
22
  return sanitize_sql_orig( arg ) if arg.nil?
23
23
  if arg.respond_to?( :to_sql )
24
- arg = sanitize_sql_by_way_of_duck_typing( arg ) #if arg.respond_to?( :to_sql )
24
+ arg = sanitize_sql_by_way_of_duck_typing( arg )
25
25
  elsif arg.is_a?( Hash )
26
- arg = sanitize_sql_from_hash( arg ) #if arg.is_a?( Hash )
26
+ arg = sanitize_sql_from_hash( arg )
27
27
  elsif arg.size == 2 and arg.first.is_a?( String ) and arg.last.is_a?( Hash )
28
- arg = sanitize_sql_from_string_and_hash( arg ) # if arg.size == 2 and arg.first.is_a?( String ) and arg.last.is_a?( Hash )
28
+ arg = sanitize_sql_from_string_and_hash( arg )
29
29
  end
30
30
  sanitize_sql_orig( arg )
31
31
  end
@@ -80,6 +80,9 @@ class ActiveRecord::Base
80
80
  # * +on_duplicate_key_update+ - an Array or Hash, tells import to \
81
81
  # use MySQL's ON DUPLICATE KEY UPDATE ability. See On Duplicate\
82
82
  # Key Update below.
83
+ # * +synchronize+ - an array of ActiveRecord instances for the model
84
+ # that you are currently importing data into. This synchronizes
85
+ # existing model instances in memory with updates from the import.
83
86
  #
84
87
  # == Examples
85
88
  # class BlogPost < ActiveRecord::Base ; end
@@ -100,6 +103,14 @@ class ActiveRecord::Base
100
103
  # values = [ [ 'zdennis', 'test post' ], [ 'jdoe', 'another test post' ] ]
101
104
  # BlogPost.import( columns, values, :validate => false )
102
105
  #
106
+ # # Example synchronizing existing instances in memory
107
+ # post = BlogPost.find_by_author_name( 'zdennis' )
108
+ # puts post.author_name # => 'zdennis'
109
+ # columns = [ :author_name, :title ]
110
+ # values = [ [ 'yoda', 'test post' ] ]
111
+ # BlogPost.import posts, :synchronize=>[ post ]
112
+ # puts post.author_name # => 'yoda'
113
+ #
103
114
  # == On Duplicate Key Update (MySQL only)
104
115
  #
105
116
  # The :on_duplicate_key_update option can be either an Array or a Hash.
@@ -154,11 +165,17 @@ class ActiveRecord::Base
154
165
 
155
166
  # dup the passed in array so we don't modify it unintentionally
156
167
  array_of_attributes = array_of_attributes.dup
157
- if is_validating
168
+ number_of_inserts = if is_validating
158
169
  import_with_validations( column_names, array_of_attributes, options )
159
170
  else
160
171
  import_without_validations_or_callbacks( column_names, array_of_attributes, options )
161
172
  end
173
+
174
+ if options[:synchronize]
175
+ synchronize( options[:synchronize] )
176
+ end
177
+
178
+ number_of_inserts
162
179
  end
163
180
 
164
181
  # TODO import_from_table needs to be implemented.
@@ -12,8 +12,8 @@ module ActiveRecord::Extensions::ConnectionAdapters::MysqlAdapter # :nodoc:
12
12
  post_sql_statements
13
13
  end
14
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 "
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
17
  end
18
18
 
19
19
  # Returns a generated ON DUPLICATE KEY UPDATE statement given the passed
@@ -64,7 +64,7 @@ module ActiveRecord::Extensions::ConnectionAdapters::MysqlAdapter # :nodoc:
64
64
  end
65
65
  values_arr = values.map{ |arr| '(' + arr.join( ',' ) + ')' }
66
66
  end
67
-
67
+
68
68
  end
69
69
 
70
70
  ActiveRecord::ConnectionAdapters::MysqlAdapter.send( 'include', ActiveRecord::Extensions::ConnectionAdapters::MysqlAdapter )
@@ -0,0 +1,30 @@
1
+ module ActiveRecord # :nodoc:
2
+ class Base # :nodoc:
3
+
4
+ # Synchronizes the passed in ActiveRecord instances with data
5
+ # from the database. This is like calling reload
6
+ # on an individual ActiveRecord instance but it is intended for use on
7
+ # multiple instances.
8
+ #
9
+ # This uses one query for all instance updates and then updates existing
10
+ # instances rather sending one query for each instance
11
+ def self.synchronize(instances, key=ActiveRecord::Base.primary_key)
12
+ return if instances.empty?
13
+
14
+ keys = instances.map(&"#{key}".to_sym)
15
+ klass = instances.first.class
16
+ fresh_instances = klass.find( :all, :conditions=>{ key=>keys }, :order=>"#{key} ASC" )
17
+
18
+ instances.each_with_index do |instance, index|
19
+ instance.clear_aggregation_cache
20
+ instance.clear_association_cache
21
+ instance.instance_variable_set '@attributes', fresh_instances[index].attributes
22
+ end
23
+ end
24
+
25
+ # See ActiveRecord::ConnectionAdapters::AbstractAdapter.synchronize
26
+ def synchronize(instances, key=ActiveRecord::Base.primary_key)
27
+ self.class.synchronize(instances, key)
28
+ end
29
+ end
30
+ end
@@ -117,7 +117,7 @@ class ActiveRecord::TemporaryTable < ActiveRecord::Base
117
117
  Object.send( :remove_const, self.name.to_sym )
118
118
  @@temporary_table_hsh.delete( self )
119
119
  else
120
- raise StandardError.new "Trying to drop nonexistance temporary table: #{self.name}"
120
+ raise StandardError.new( "Trying to drop nonexistance temporary table: #{self.name}" )
121
121
  end
122
122
  end
123
123
 
@@ -2,7 +2,7 @@
2
2
  module ActiveRecord # :nodoc:
3
3
  module Extensions # :nodoc:
4
4
  module VERSION
5
- MAJOR, MINOR, REVISION = %W( 0 5 2 )
5
+ MAJOR, MINOR, REVISION = %W( 0 6 0 )
6
6
  STRING = [ MAJOR, MINOR, REVISION ].join( '.' )
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.1
2
+ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: ar-extensions
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.5.2
7
- date: 2007-03-15 00:00:00 -04:00
6
+ version: 0.6.0
7
+ date: 2007-05-05 00:00:00 -04:00
8
8
  summary: Extends ActiveRecord functionality.
9
9
  require_paths:
10
10
  - lib
@@ -42,22 +42,23 @@ files:
42
42
  - config/database.yml.template
43
43
  - config/mysql.schema
44
44
  - config/postgresql.schema
45
- - lib/ar-extensions.rb
45
+ - lib/ar-extensions/adapters/abstract_adapter.rb
46
+ - lib/ar-extensions/adapters/mysql_adapter.rb
47
+ - lib/ar-extensions/adapters/postgresql.rb
46
48
  - lib/ar-extensions/csv.rb
47
49
  - lib/ar-extensions/extensions.rb
48
50
  - lib/ar-extensions/finders.rb
49
51
  - lib/ar-extensions/foreign_keys.rb
50
- - lib/ar-extensions/fulltext.rb
51
- - lib/ar-extensions/import.rb
52
- - lib/ar-extensions/temporary_table.rb
53
- - lib/ar-extensions/version.rb
54
- - lib/ar-extensions/adapters/abstract_adapter.rb
55
- - lib/ar-extensions/adapters/mysql_adapter.rb
56
- - lib/ar-extensions/adapters/postgresql.rb
57
52
  - lib/ar-extensions/fulltext/mysql.rb
53
+ - lib/ar-extensions/fulltext.rb
58
54
  - lib/ar-extensions/import/mysql.rb
59
55
  - lib/ar-extensions/import/postgresql.rb
56
+ - lib/ar-extensions/import.rb
57
+ - lib/ar-extensions/synchronize.rb
60
58
  - lib/ar-extensions/temporary_table/mysql.rb
59
+ - lib/ar-extensions/temporary_table.rb
60
+ - lib/ar-extensions/version.rb
61
+ - lib/ar-extensions.rb
61
62
  test_files: []
62
63
 
63
64
  rdoc_options: