activerecord-import 0.20.2 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aedb604a103a355bb35e3373239fb12e1e9877cd
4
- data.tar.gz: 235a13a5819d9181aaa478686ec42596c54806fe
3
+ metadata.gz: d4441271287712d8e44b9cac793f2b8b8d315988
4
+ data.tar.gz: ec27555ffefb8a071bcf3c54b354a8b56b6e68c2
5
5
  SHA512:
6
- metadata.gz: 8e9349db11dd48246fb292215d4dd43efd2c8fe0c2e544e6fa585d4ad0aa7eb2ba612d8b7a84bbbaf991958b8c7897135314c6e73b4520d05a31861ec68ba5e7
7
- data.tar.gz: 58de95004307eb2cfe48d0a6e534313612ed90c69df08e1bdb0372cb065d857189d23fa12552d652d0fbfb4a7ba91cedcba8c7c14c44dfd72c5bff26442bf0bd
6
+ metadata.gz: fbafbd6476a5f7c3681b26e85e3f4960fb69b6065697a173426392f91f1a89c188dd83b1b16c1639645ba33b8a1fbba97a91dea7e20186692c8ca3e33b9eaf41
7
+ data.tar.gz: 54f3499be94b3c1b44a99128c39bb9f964e5bcb8da8549dbd66fe5d568a14f195d8b60f2c17a8dab9b5745ba7efb9db58950b433377aee510f4586e1a3cf2074
@@ -17,7 +17,7 @@ env:
17
17
 
18
18
  matrix:
19
19
  include:
20
- - rvm: jruby-9.1.9.0
20
+ - rvm: jruby-9.1.14.0
21
21
  env: AR_VERSION=4.2
22
22
  before_install:
23
23
  - gem update --system
@@ -1,3 +1,21 @@
1
+ ## Changes in 0.21.0
2
+
3
+ ### New Features
4
+
5
+ * Allow SQL subqueries (objects that respond to .to_sql) to be passed as values. Thanks
6
+ to @jalada, @jkowens via \#471
7
+ * Raise an ArgumentError when importing an array of hashes if any of the
8
+ hash objects have different keys. Thanks to @mbell697 via \#465.
9
+
10
+ ### Fixes
11
+
12
+ * Fix issue loading incorrect foreign key value when syncing belongs_to
13
+ associations with custom foreign key columns. Thanks to @marcgreenstock, @jkowens via \#470.
14
+ * Fix issue importing models with polymorphic belongs_to associations.
15
+ Thanks to @zorab47, @jkowens via \#476.
16
+ * Fix issue importing STI models with ActiveRecord 4.0. Thanks to
17
+ @kazuki-st, @jkowens via \#478.
18
+
1
19
  ## Changes in 0.20.2
2
20
 
3
21
  ### Fixes
data/Gemfile CHANGED
@@ -18,9 +18,9 @@ end
18
18
  platforms :jruby do
19
19
  gem "jdbc-mysql"
20
20
  gem "jdbc-postgres"
21
- gem "activerecord-jdbcsqlite3-adapter"
22
- gem "activerecord-jdbcmysql-adapter"
23
- gem "activerecord-jdbcpostgresql-adapter"
21
+ gem "activerecord-jdbcsqlite3-adapter", "~> 1.3"
22
+ gem "activerecord-jdbcmysql-adapter", "~> 1.3"
23
+ gem "activerecord-jdbcpostgresql-adapter", "~> 1.3"
24
24
  end
25
25
 
26
26
  # Support libs
@@ -1 +1,2 @@
1
1
  gem 'activerecord', '~> 5.1.0'
2
+ gem 'composite_primary_keys', '~> 10.0'
@@ -247,6 +247,9 @@ class ActiveRecord::Base
247
247
  # BlogPost.import posts
248
248
  #
249
249
  # # Example using array_of_hash_objects
250
+ # # NOTE: column_names will be determined by using the keys of the first hash in the array. If later hashes in the
251
+ # # array have different keys an exception will be raised. If you have hashes to import with different sets of keys
252
+ # # we recommend grouping these into batches before importing.
250
253
  # values = [ {author_name: 'zdennis', title: 'test post'} ], [ {author_name: 'jdoe', title: 'another test post'} ] ]
251
254
  # BlogPost.import values
252
255
  #
@@ -470,12 +473,18 @@ class ActiveRecord::Base
470
473
  if args.length == 2
471
474
  array_of_hashes = args.last
472
475
  column_names = args.first.dup
476
+ allow_extra_hash_keys = true
473
477
  else
474
478
  array_of_hashes = args.first
475
479
  column_names = array_of_hashes.first.keys
480
+ allow_extra_hash_keys = false
476
481
  end
477
482
 
478
483
  array_of_attributes = array_of_hashes.map do |h|
484
+ error_message = validate_hash_import(h, column_names, allow_extra_hash_keys)
485
+
486
+ raise ArgumentError, error_message if error_message
487
+
479
488
  column_names.map do |key|
480
489
  h[key]
481
490
  end
@@ -613,7 +622,7 @@ class ActiveRecord::Base
613
622
  next if column_names.include?(name_as_sym)
614
623
 
615
624
  is_sti = (name_as_sym == inheritance_column.to_sym && self < base_class)
616
- value = value.first if is_sti
625
+ value = Array(value).first if is_sti
617
626
 
618
627
  column_names << name_as_sym
619
628
  array_of_attributes.each { |attrs| attrs << value }
@@ -711,10 +720,12 @@ class ActiveRecord::Base
711
720
  def load_association_ids(model)
712
721
  association_reflections = model.class.reflect_on_all_associations(:belongs_to)
713
722
  association_reflections.each do |association_reflection|
723
+ next if association_reflection.options[:polymorphic]
714
724
  association = model.association(association_reflection.name)
715
725
  association = association.target
716
- if association && association.id
717
- model.public_send("#{association_reflection.foreign_key}=", association.id)
726
+ if association
727
+ association_primary_key = association_reflection.association_primary_key
728
+ model.public_send("#{association_reflection.foreign_key}=", association.send(association_primary_key))
718
729
  end
719
730
  end
720
731
  end
@@ -782,6 +793,8 @@ class ActiveRecord::Base
782
793
  # be sure to query sequence_name *last*, only if cheaper tests fail, because it's costly
783
794
  if val.nil? && column.name == primary_key && !sequence_name.blank?
784
795
  connection_memo.next_value_for_sequence(sequence_name)
796
+ elsif val.respond_to?(:to_sql)
797
+ "(#{val.to_sql})"
785
798
  elsif column
786
799
  if respond_to?(:type_caster) # Rails 5.0 and higher
787
800
  type = type_for_attribute(column.name)
@@ -846,5 +859,42 @@ class ActiveRecord::Base
846
859
  def validations_array_for_column_names_and_attributes( column_names, array_of_attributes ) # :nodoc:
847
860
  array_of_attributes.map { |values| Hash[column_names.zip(values)] }
848
861
  end
862
+
863
+ # Checks that the imported hash has the required_keys, optionally also checks that the hash has
864
+ # no keys beyond those required when `allow_extra_keys` is false.
865
+ # returns `nil` if validation passes, or an error message if it fails
866
+ def validate_hash_import(hash, required_keys, allow_extra_keys) # :nodoc:
867
+ extra_keys = allow_extra_keys ? [] : hash.keys - required_keys
868
+ missing_keys = required_keys - hash.keys
869
+
870
+ return nil if extra_keys.empty? && missing_keys.empty?
871
+
872
+ if allow_extra_keys
873
+ <<-EOS
874
+ Hash key mis-match.
875
+
876
+ When importing an array of hashes with provided columns_names, each hash must contain keys for all column_names.
877
+
878
+ Required keys: #{column_names}
879
+ Missing keys: #{missing_keys}
880
+
881
+ Hash: #{hash}
882
+ EOS
883
+ else
884
+ <<-EOS
885
+ Hash key mis-match.
886
+
887
+ When importing an array of hashes, all hashes must have the same keys.
888
+ If you have records that are missing some values, we recommend you either set default values
889
+ for the missing keys or group these records into batches by key set before importing.
890
+
891
+ Required keys: #{column_names}
892
+ Extra keys: #{extra_keys}
893
+ Missing keys: #{missing_keys}
894
+
895
+ Hash: #{hash}
896
+ EOS
897
+ end
898
+ end
849
899
  end
850
900
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Import
3
- VERSION = "0.20.2".freeze
3
+ VERSION = "0.21.0".freeze
4
4
  end
5
5
  end
@@ -86,6 +86,54 @@ describe "#import" do
86
86
  assert_nil t.author_email_address
87
87
  end
88
88
  end
89
+
90
+ context "with extra keys" do
91
+ let(:values) do
92
+ [
93
+ { title: "LDAP", author_name: "Jerry Carter" },
94
+ { title: "Rails Recipes", author_name: "Chad Fowler", author_email_address: "cfowler@test.com" } # author_email_address is unknown
95
+ ]
96
+ end
97
+
98
+ it "should fail when column names are not specified" do
99
+ err = assert_raises ArgumentError do
100
+ Topic.import values, validate: false
101
+ end
102
+
103
+ assert err.message.include? 'Extra keys: [:author_email_address]'
104
+ end
105
+
106
+ it "should succeed when column names are specified" do
107
+ assert_difference "Topic.count", +2 do
108
+ Topic.import columns, values, validate: false
109
+ end
110
+ end
111
+ end
112
+
113
+ context "with missing keys" do
114
+ let(:values) do
115
+ [
116
+ { title: "LDAP", author_name: "Jerry Carter" },
117
+ { title: "Rails Recipes" } # author_name is missing
118
+ ]
119
+ end
120
+
121
+ it "should fail when column names are not specified" do
122
+ err = assert_raises ArgumentError do
123
+ Topic.import values, validate: false
124
+ end
125
+
126
+ assert err.message.include? 'Missing keys: [:author_name]'
127
+ end
128
+
129
+ it "should fail on missing hash key from specified column names" do
130
+ err = assert_raises ArgumentError do
131
+ Topic.import %i(author_name), values, validate: false
132
+ end
133
+
134
+ assert err.message.include? 'Missing keys: [:author_name]'
135
+ end
136
+ end
89
137
  end
90
138
 
91
139
  unless ENV["SKIP_COMPOSITE_PK"]
@@ -545,6 +593,17 @@ describe "#import" do
545
593
  end
546
594
  end
547
595
 
596
+ context "importing model with polymorphic belongs_to" do
597
+ it "works without error" do
598
+ book = FactoryGirl.create :book
599
+ discount = Discount.new(discountable: book)
600
+
601
+ Discount.import([discount])
602
+
603
+ assert_equal 1, Discount.count
604
+ end
605
+ end
606
+
548
607
  context 'When importing models with Enum fields' do
549
608
  it 'should be able to import enum fields' do
550
609
  Book.delete_all if Book.count > 0
@@ -760,5 +819,19 @@ describe "#import" do
760
819
  end
761
820
  end
762
821
  end
822
+
823
+ context "with objects that respond to .to_sql as values" do
824
+ let(:columns) { %w(title author_name) }
825
+ let(:valid_values) { [["LDAP", Book.select("'Jerry Carter'").limit(1)], ["Rails Recipes", Book.select("'Chad Fowler'").limit(1)]] }
826
+
827
+ it "should import data" do
828
+ assert_difference "Topic.count", +2 do
829
+ Topic.import! columns, valid_values
830
+ topics = Topic.all
831
+ assert_equal "Jerry Carter", topics.first.author_name
832
+ assert_equal "Chad Fowler", topics.last.author_name
833
+ end
834
+ end
835
+ end
763
836
  end
764
837
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-import
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.2
4
+ version: 0.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Dennis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-02 00:00:00.000000000 Z
11
+ date: 2017-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -176,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
176
  version: '0'
177
177
  requirements: []
178
178
  rubyforge_project:
179
- rubygems_version: 2.6.11
179
+ rubygems_version: 2.6.13
180
180
  signing_key:
181
181
  specification_version: 4
182
182
  summary: Bulk insert extension for ActiveRecord