activerecord-import 1.2.0 → 1.5.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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +51 -11
  3. data/.rubocop.yml +74 -8
  4. data/.rubocop_todo.yml +6 -16
  5. data/Brewfile +3 -1
  6. data/CHANGELOG.md +37 -0
  7. data/Gemfile +8 -10
  8. data/README.markdown +14 -11
  9. data/Rakefile +2 -0
  10. data/activerecord-import.gemspec +4 -3
  11. data/benchmarks/benchmark.rb +10 -4
  12. data/benchmarks/lib/base.rb +4 -2
  13. data/benchmarks/lib/cli_parser.rb +4 -2
  14. data/benchmarks/lib/float.rb +2 -0
  15. data/benchmarks/lib/mysql2_benchmark.rb +2 -0
  16. data/benchmarks/lib/output_to_csv.rb +2 -0
  17. data/benchmarks/lib/output_to_html.rb +4 -2
  18. data/benchmarks/models/test_innodb.rb +2 -0
  19. data/benchmarks/models/test_memory.rb +2 -0
  20. data/benchmarks/models/test_myisam.rb +2 -0
  21. data/benchmarks/schema/mysql2_schema.rb +2 -0
  22. data/gemfiles/4.2.gemfile +2 -0
  23. data/gemfiles/5.0.gemfile +2 -0
  24. data/gemfiles/5.1.gemfile +2 -0
  25. data/gemfiles/5.2.gemfile +2 -0
  26. data/gemfiles/6.0.gemfile +2 -0
  27. data/gemfiles/6.1.gemfile +3 -0
  28. data/gemfiles/7.0.gemfile +4 -0
  29. data/lib/activerecord-import/active_record/adapters/abstract_adapter.rb +2 -0
  30. data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +2 -0
  31. data/lib/activerecord-import/active_record/adapters/jdbcpostgresql_adapter.rb +2 -0
  32. data/lib/activerecord-import/active_record/adapters/jdbcsqlite3_adapter.rb +2 -0
  33. data/lib/activerecord-import/active_record/adapters/mysql2_adapter.rb +2 -0
  34. data/lib/activerecord-import/active_record/adapters/postgresql_adapter.rb +2 -0
  35. data/lib/activerecord-import/active_record/adapters/seamless_database_pool_adapter.rb +2 -0
  36. data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +2 -0
  37. data/lib/activerecord-import/adapters/abstract_adapter.rb +8 -5
  38. data/lib/activerecord-import/adapters/em_mysql2_adapter.rb +2 -0
  39. data/lib/activerecord-import/adapters/mysql2_adapter.rb +2 -0
  40. data/lib/activerecord-import/adapters/mysql_adapter.rb +27 -19
  41. data/lib/activerecord-import/adapters/postgresql_adapter.rb +66 -47
  42. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +36 -30
  43. data/lib/activerecord-import/base.rb +3 -1
  44. data/lib/activerecord-import/import.rb +85 -44
  45. data/lib/activerecord-import/mysql2.rb +2 -0
  46. data/lib/activerecord-import/postgresql.rb +2 -0
  47. data/lib/activerecord-import/sqlite3.rb +2 -0
  48. data/lib/activerecord-import/synchronize.rb +3 -1
  49. data/lib/activerecord-import/value_sets_parser.rb +3 -0
  50. data/lib/activerecord-import/version.rb +3 -1
  51. data/lib/activerecord-import.rb +3 -1
  52. data/test/adapters/jdbcmysql.rb +2 -0
  53. data/test/adapters/jdbcpostgresql.rb +2 -0
  54. data/test/adapters/jdbcsqlite3.rb +2 -0
  55. data/test/adapters/makara_postgis.rb +2 -0
  56. data/test/adapters/mysql2.rb +2 -0
  57. data/test/adapters/mysql2_makara.rb +2 -0
  58. data/test/adapters/mysql2spatial.rb +2 -0
  59. data/test/adapters/postgis.rb +2 -0
  60. data/test/adapters/postgresql.rb +2 -0
  61. data/test/adapters/postgresql_makara.rb +2 -0
  62. data/test/adapters/seamless_database_pool.rb +2 -0
  63. data/test/adapters/spatialite.rb +2 -0
  64. data/test/adapters/sqlite3.rb +2 -0
  65. data/test/import_test.rb +26 -1
  66. data/test/jdbcmysql/import_test.rb +5 -3
  67. data/test/jdbcpostgresql/import_test.rb +4 -2
  68. data/test/jdbcsqlite3/import_test.rb +4 -2
  69. data/test/makara_postgis/import_test.rb +4 -2
  70. data/test/models/account.rb +2 -0
  71. data/test/models/alarm.rb +2 -0
  72. data/test/models/animal.rb +2 -0
  73. data/test/models/bike_maker.rb +3 -0
  74. data/test/models/book.rb +2 -0
  75. data/test/models/car.rb +2 -0
  76. data/test/models/card.rb +2 -0
  77. data/test/models/chapter.rb +2 -0
  78. data/test/models/customer.rb +8 -0
  79. data/test/models/deck.rb +2 -0
  80. data/test/models/dictionary.rb +2 -0
  81. data/test/models/discount.rb +2 -0
  82. data/test/models/end_note.rb +2 -0
  83. data/test/models/group.rb +2 -0
  84. data/test/models/order.rb +8 -0
  85. data/test/models/playing_card.rb +2 -0
  86. data/test/models/promotion.rb +2 -0
  87. data/test/models/question.rb +2 -0
  88. data/test/models/rule.rb +2 -0
  89. data/test/models/tag.rb +3 -0
  90. data/test/models/tag_alias.rb +5 -0
  91. data/test/models/topic.rb +7 -0
  92. data/test/models/user.rb +2 -0
  93. data/test/models/user_token.rb +2 -0
  94. data/test/models/vendor.rb +2 -0
  95. data/test/models/widget.rb +2 -0
  96. data/test/mysql2/import_test.rb +5 -3
  97. data/test/mysql2_makara/import_test.rb +5 -3
  98. data/test/mysqlspatial2/import_test.rb +5 -3
  99. data/test/postgis/import_test.rb +4 -2
  100. data/test/postgresql/import_test.rb +4 -2
  101. data/test/schema/generic_schema.rb +20 -0
  102. data/test/schema/jdbcpostgresql_schema.rb +3 -1
  103. data/test/schema/mysql2_schema.rb +2 -0
  104. data/test/schema/postgis_schema.rb +3 -1
  105. data/test/schema/postgresql_schema.rb +2 -0
  106. data/test/schema/sqlite3_schema.rb +2 -0
  107. data/test/schema/version.rb +2 -0
  108. data/test/sqlite3/import_test.rb +4 -2
  109. data/test/support/active_support/test_case_extensions.rb +2 -0
  110. data/test/support/assertions.rb +2 -0
  111. data/test/support/factories.rb +2 -0
  112. data/test/support/generate.rb +4 -2
  113. data/test/support/mysql/import_examples.rb +2 -1
  114. data/test/support/postgresql/import_examples.rb +65 -2
  115. data/test/support/shared_examples/on_duplicate_key_ignore.rb +2 -0
  116. data/test/support/shared_examples/on_duplicate_key_update.rb +41 -10
  117. data/test/support/shared_examples/recursive_import.rb +23 -1
  118. data/test/support/sqlite3/import_examples.rb +2 -1
  119. data/test/synchronize_test.rb +2 -0
  120. data/test/test_helper.rb +21 -5
  121. data/test/value_sets_bytes_parser_test.rb +3 -1
  122. data/test/value_sets_records_parser_test.rb +3 -1
  123. metadata +16 -12
  124. data/gemfiles/3.2.gemfile +0 -2
  125. data/gemfiles/4.0.gemfile +0 -2
  126. data/gemfiles/4.1.gemfile +0 -2
@@ -1,18 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "ostruct"
2
4
 
3
5
  module ActiveRecord::Import::ConnectionAdapters; end
4
6
 
5
- module ActiveRecord::Import #:nodoc:
7
+ module ActiveRecord::Import # :nodoc:
6
8
  Result = Struct.new(:failed_instances, :num_inserts, :ids, :results)
7
9
 
8
- module ImportSupport #:nodoc:
9
- def supports_import? #:nodoc:
10
+ module ImportSupport # :nodoc:
11
+ def supports_import? # :nodoc:
10
12
  true
11
13
  end
12
14
  end
13
15
 
14
- module OnDuplicateKeyUpdateSupport #:nodoc:
15
- def supports_on_duplicate_key_update? #:nodoc:
16
+ module OnDuplicateKeyUpdateSupport # :nodoc:
17
+ def supports_on_duplicate_key_update? # :nodoc:
16
18
  true
17
19
  end
18
20
  end
@@ -34,7 +36,7 @@ module ActiveRecord::Import #:nodoc:
34
36
  @validate_callbacks = klass._validate_callbacks.dup
35
37
 
36
38
  @validate_callbacks.each_with_index do |callback, i|
37
- filter = callback.raw_filter
39
+ filter = callback.respond_to?(:raw_filter) ? callback.raw_filter : callback.filter
38
40
  next unless filter.class.name =~ /Validations::PresenceValidator/ ||
39
41
  (!@options[:validate_uniqueness] &&
40
42
  filter.is_a?(ActiveRecord::Validations::UniquenessValidator))
@@ -55,7 +57,7 @@ module ActiveRecord::Import #:nodoc:
55
57
  end
56
58
  end
57
59
 
58
- filter.instance_variable_set(:@attributes, attrs)
60
+ filter.instance_variable_set(:@attributes, attrs.flatten)
59
61
 
60
62
  if @validate_callbacks.respond_to?(:chain, true)
61
63
  @validate_callbacks.send(:chain).tap do |chain|
@@ -71,7 +73,7 @@ module ActiveRecord::Import #:nodoc:
71
73
  end
72
74
 
73
75
  def valid_model?(model)
74
- init_validations(model.class) unless model.class == @validator_class
76
+ init_validations(model.class) unless model.instance_of?(@validator_class)
75
77
 
76
78
  validation_context = @options[:validate_with_context]
77
79
  validation_context ||= (model.new_record? ? :create : :update)
@@ -83,7 +85,11 @@ module ActiveRecord::Import #:nodoc:
83
85
 
84
86
  model.run_callbacks(:validation) do
85
87
  if defined?(ActiveSupport::Callbacks::Filters::Environment) # ActiveRecord >= 4.1
86
- runner = @validate_callbacks.compile
88
+ runner = if @validate_callbacks.method(:compile).arity == 0
89
+ @validate_callbacks.compile
90
+ else # ActiveRecord >= 7.1
91
+ @validate_callbacks.compile(nil)
92
+ end
87
93
  env = ActiveSupport::Callbacks::Filters::Environment.new(model, false, nil)
88
94
  if runner.respond_to?(:call) # ActiveRecord < 5.1
89
95
  runner.call(env)
@@ -163,7 +169,7 @@ class ActiveRecord::Associations::CollectionAssociation
163
169
  m.public_send "#{reflection.type}=", owner.class.name if reflection.type
164
170
  end
165
171
 
166
- return model_klass.bulk_import column_names, models, options
172
+ model_klass.bulk_import column_names, models, options
167
173
 
168
174
  # supports array of hash objects
169
175
  elsif args.last.is_a?( Array ) && args.last.first.is_a?(Hash)
@@ -202,11 +208,11 @@ class ActiveRecord::Associations::CollectionAssociation
202
208
  end
203
209
  end
204
210
 
205
- return model_klass.bulk_import column_names, array_of_attributes, options
211
+ model_klass.bulk_import column_names, array_of_attributes, options
206
212
 
207
213
  # supports empty array
208
214
  elsif args.last.is_a?( Array ) && args.last.empty?
209
- return ActiveRecord::Import::Result.new([], 0, [])
215
+ ActiveRecord::Import::Result.new([], 0, [])
210
216
 
211
217
  # supports 2-element array and array
212
218
  elsif args.size == 2 && args.first.is_a?( Array ) && args.last.is_a?( Array )
@@ -237,7 +243,7 @@ class ActiveRecord::Associations::CollectionAssociation
237
243
  end
238
244
  end
239
245
 
240
- return model_klass.bulk_import column_names, array_of_attributes, options
246
+ model_klass.bulk_import column_names, array_of_attributes, options
241
247
  else
242
248
  raise ArgumentError, "Invalid arguments!"
243
249
  end
@@ -547,7 +553,7 @@ class ActiveRecord::Base
547
553
  alias import! bulk_import! unless ActiveRecord::Base.respond_to? :import!
548
554
 
549
555
  def import_helper( *args )
550
- options = { validate: true, timestamps: true, track_validation_failures: false }
556
+ options = { model: self, validate: true, timestamps: true, track_validation_failures: false }
551
557
  options.merge!( args.pop ) if args.last.is_a? Hash
552
558
  # making sure that current model's primary key is used
553
559
  options[:primary_key] = primary_key
@@ -572,7 +578,7 @@ class ActiveRecord::Base
572
578
 
573
579
  if models.first.id.nil?
574
580
  Array(primary_key).each do |c|
575
- if column_names.include?(c) && columns_hash[c].type == :uuid
581
+ if column_names.include?(c) && schema_columns_hash[c].type == :uuid
576
582
  column_names.delete(c)
577
583
  end
578
584
  end
@@ -695,7 +701,11 @@ class ActiveRecord::Base
695
701
  return_obj = if is_validating
696
702
  import_with_validations( column_names, array_of_attributes, options ) do |failed_instances|
697
703
  if models
698
- models.each { |m| failed_instances << m if m.errors.any? }
704
+ models.each_with_index do |m, i|
705
+ next unless m.errors.any?
706
+
707
+ failed_instances << (options[:track_validation_failures] ? [i, m] : m)
708
+ end
699
709
  else
700
710
  # create instances for each of our column/value sets
701
711
  arr = validations_array_for_column_names_and_attributes( column_names, array_of_attributes )
@@ -734,7 +744,10 @@ class ActiveRecord::Base
734
744
  set_attributes_and_mark_clean(models, return_obj, timestamps, options)
735
745
 
736
746
  # if there are auto-save associations on the models we imported that are new, import them as well
737
- import_associations(models, options.dup.merge(validate: false)) if options[:recursive]
747
+ if options[:recursive]
748
+ options[:on_duplicate_key_update] = on_duplicate_key_update unless on_duplicate_key_update.nil?
749
+ import_associations(models, options.dup.merge(validate: false))
750
+ end
738
751
  end
739
752
 
740
753
  return_obj
@@ -769,7 +782,10 @@ class ActiveRecord::Base
769
782
  def import_without_validations_or_callbacks( column_names, array_of_attributes, options = {} )
770
783
  return ActiveRecord::Import::Result.new([], 0, [], []) if array_of_attributes.empty?
771
784
 
772
- column_names = column_names.map(&:to_sym)
785
+ column_names = column_names.map do |name|
786
+ original_name = attribute_alias?(name) ? attribute_alias(name) : name
787
+ original_name.to_sym
788
+ end
773
789
  scope_columns, scope_values = scope_attributes.to_a.transpose
774
790
 
775
791
  unless scope_columns.blank?
@@ -781,15 +797,13 @@ class ActiveRecord::Base
781
797
  end
782
798
  end
783
799
 
784
- if finder_needs_type_condition?
785
- unless column_names.include?(inheritance_column.to_sym)
786
- column_names << inheritance_column.to_sym
787
- array_of_attributes.each { |attrs| attrs << sti_name }
788
- end
800
+ if finder_needs_type_condition? && !column_names.include?(inheritance_column.to_sym)
801
+ column_names << inheritance_column.to_sym
802
+ array_of_attributes.each { |attrs| attrs << sti_name }
789
803
  end
790
804
 
791
805
  columns = column_names.each_with_index.map do |name, i|
792
- column = columns_hash[name.to_s]
806
+ column = schema_columns_hash[name.to_s]
793
807
  raise ActiveRecord::Import::MissingColumnError.new(name.to_s, i) if column.nil?
794
808
  column
795
809
  end
@@ -854,13 +868,13 @@ class ActiveRecord::Base
854
868
  model.id = id
855
869
 
856
870
  timestamps.each do |attr, value|
857
- model.send(attr + "=", value)
871
+ model.send("#{attr}=", value) if model.send(attr).nil?
858
872
  end
859
873
  end
860
874
  end
861
875
 
862
876
  deserialize_value = lambda do |column, value|
863
- column = columns_hash[column]
877
+ column = schema_columns_hash[column]
864
878
  return value unless column
865
879
  if respond_to?(:type_caster)
866
880
  type = type_for_attribute(column.name)
@@ -872,19 +886,28 @@ class ActiveRecord::Base
872
886
  end
873
887
  end
874
888
 
875
- if models.size == import_result.results.size
876
- columns = Array(options[:returning])
877
- single_column = "#{columns.first}=" if columns.size == 1
878
- import_result.results.each_with_index do |result, index|
889
+ set_value = lambda do |model, column, value|
890
+ val = deserialize_value.call(column, value)
891
+ if model.attribute_names.include?(column)
892
+ model.send("#{column}=", val)
893
+ else
894
+ attributes = attributes_builder.build_from_database(model.attributes.merge(column => val))
895
+ model.instance_variable_set(:@attributes, attributes)
896
+ end
897
+ end
898
+
899
+ columns = Array(options[:returning_columns])
900
+ results = Array(import_result.results)
901
+ if models.size == results.size
902
+ single_column = columns.first if columns.size == 1
903
+ results.each_with_index do |result, index|
879
904
  model = models[index]
880
905
 
881
906
  if single_column
882
- val = deserialize_value.call(columns.first, result)
883
- model.send(single_column, val)
907
+ set_value.call(model, single_column, result)
884
908
  else
885
909
  columns.each_with_index do |column, col_index|
886
- val = deserialize_value.call(column, result[col_index])
887
- model.send("#{column}=", val)
910
+ set_value.call(model, column, result[col_index])
888
911
  end
889
912
  end
890
913
  end
@@ -908,15 +931,19 @@ class ActiveRecord::Base
908
931
  changed_columns = model.changed
909
932
  association_reflections = model.class.reflect_on_all_associations(:belongs_to)
910
933
  association_reflections.each do |association_reflection|
911
- column_name = association_reflection.foreign_key
912
934
  next if association_reflection.options[:polymorphic]
913
- next if changed_columns.include?(column_name)
914
- association = model.association(association_reflection.name)
915
- association = association.target
916
- next if association.blank? || model.public_send(column_name).present?
917
935
 
918
- association_primary_key = association_reflection.association_primary_key
919
- model.public_send("#{column_name}=", association.send(association_primary_key))
936
+ column_names = Array(association_reflection.foreign_key).map(&:to_s)
937
+ column_names.each_with_index do |column_name, column_index|
938
+ next if changed_columns.include?(column_name)
939
+
940
+ association = model.association(association_reflection.name)
941
+ association = association.target
942
+ next if association.blank? || model.public_send(column_name).present?
943
+
944
+ association_primary_key = Array(association_reflection.association_primary_key)[column_index]
945
+ model.public_send("#{column_name}=", association.send(association_primary_key))
946
+ end
920
947
  end
921
948
  end
922
949
 
@@ -929,8 +956,9 @@ class ActiveRecord::Base
929
956
  associated_objects_by_class = {}
930
957
  models.each { |model| find_associated_objects_for_import(associated_objects_by_class, model) }
931
958
 
932
- # :on_duplicate_key_update and :returning not supported for associations
933
- options.delete(:on_duplicate_key_update)
959
+ # :on_duplicate_key_update only supported for all fields
960
+ options.delete(:on_duplicate_key_update) unless options[:on_duplicate_key_update] == :all
961
+ # :returning not supported for associations
934
962
  options.delete(:returning)
935
963
 
936
964
  associated_objects_by_class.each_value do |associations|
@@ -940,6 +968,14 @@ class ActiveRecord::Base
940
968
  end
941
969
  end
942
970
 
971
+ def schema_columns_hash
972
+ @schema_columns_hash ||= if respond_to?(:ignored_columns) && ignored_columns.any?
973
+ connection.schema_cache.columns_hash(table_name)
974
+ else
975
+ columns_hash
976
+ end
977
+ end
978
+
943
979
  # We are eventually going to call Class.import <objects> so we build up a hash
944
980
  # of class => objects to import.
945
981
  def find_associated_objects_for_import(associated_objects_by_class, model)
@@ -1029,7 +1065,12 @@ class ActiveRecord::Base
1029
1065
  end
1030
1066
 
1031
1067
  # use tz as set in ActiveRecord::Base
1032
- timestamp = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
1068
+ default_timezone = if ActiveRecord.respond_to?(:default_timezone)
1069
+ ActiveRecord.default_timezone
1070
+ else
1071
+ ActiveRecord::Base.default_timezone
1072
+ end
1073
+ timestamp = default_timezone == :utc ? Time.now.utc : Time.now
1033
1074
 
1034
1075
  [:create, :update].each do |action|
1035
1076
  timestamp_columns[action].each do |column|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  warn <<-MSG
2
4
  [DEPRECATION] loading activerecord-import via 'require "activerecord-import/<adapter-name>"'
3
5
  is deprecated. Update to autorequire using 'require "activerecord-import"'. See
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  warn <<-MSG
2
4
  [DEPRECATION] loading activerecord-import via 'require "activerecord-import/<adapter-name>"'
3
5
  is deprecated. Update to autorequire using 'require "activerecord-import"'. See
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  warn <<-MSG
2
4
  [DEPRECATION] loading activerecord-import via 'require "activerecord-import/<adapter-name>"'
3
5
  is deprecated. Update to autorequire using 'require "activerecord-import"'. See
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord # :nodoc:
2
4
  class Base # :nodoc:
3
5
  # Synchronizes the passed in ActiveRecord instances with data
@@ -39,7 +41,7 @@ module ActiveRecord # :nodoc:
39
41
 
40
42
  next unless matched_instance
41
43
 
42
- instance.send :clear_association_cache
44
+ instance.instance_variable_set :@association_cache, {}
43
45
  instance.send :clear_aggregation_cache if instance.respond_to?(:clear_aggregation_cache, true)
44
46
  instance.instance_variable_set :@attributes, matched_instance.instance_variable_get(:@attributes)
45
47
 
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/core_ext/array'
2
4
 
3
5
  module ActiveRecord::Import
4
6
  class ValueSetTooLargeError < StandardError
5
7
  attr_reader :size
8
+
6
9
  def initialize(msg = "Value set exceeds max size", size = 0)
7
10
  @size = size
8
11
  super(msg)
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Import
3
- VERSION = "1.2.0".freeze
5
+ VERSION = "1.5.0"
4
6
  end
5
7
  end
@@ -1,4 +1,6 @@
1
- # rubocop:disable Style/FileName
1
+ # rubocop:disable Naming/FileName
2
+ # frozen_string_literal: true
3
+
2
4
  require "active_support/lazy_load_hooks"
3
5
 
4
6
  ActiveSupport.on_load(:active_record) do
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "jdbcmysql"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "jdbcpostgresql"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "jdbcsqlite3"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "postgis"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "mysql2"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "mysql2_makara"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "mysql2spatial"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "postgis"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "postgresql"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "postgresql"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "seamless_database_pool"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "spatialite"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ENV["ARE_DB"] = "sqlite3"
data/test/import_test.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path('../test_helper', __FILE__)
2
4
 
3
5
  describe "#import" do
@@ -159,6 +161,25 @@ describe "#import" do
159
161
  Tag.import columns, values, validate: false
160
162
  end
161
163
  end
164
+
165
+ it "should import models that are required to belong to models with composite primary keys" do
166
+ tag = Tag.create!(tag_id: 1, publisher_id: 1, tag: 'Mystery')
167
+ valid_tag_alias = TagAlias.new(tag_id: tag.tag_id, parent_id: tag.publisher_id, alias: 'Detective')
168
+ invalid_tag_aliases = [
169
+ TagAlias.new(tag_id: nil, parent_id: nil, alias: 'Detective'),
170
+ TagAlias.new(tag_id: tag.tag_id, parent_id: nil, alias: 'Detective'),
171
+ TagAlias.new(tag_id: nil, parent_id: tag.publisher_id, alias: 'Detective'),
172
+ ]
173
+
174
+ assert_difference "TagAlias.count", +1 do
175
+ TagAlias.import [valid_tag_alias]
176
+ end
177
+ invalid_tag_aliases.each do |invalid_tag_alias|
178
+ assert_no_difference "TagAlias.count" do
179
+ TagAlias.import [invalid_tag_alias]
180
+ end
181
+ end
182
+ end
162
183
  end
163
184
  end
164
185
 
@@ -555,7 +576,11 @@ describe "#import" do
555
576
  context "when the timestamps columns are present" do
556
577
  setup do
557
578
  @existing_book = Book.create(title: "Fell", author_name: "Curry", publisher: "Bayer", created_at: 2.years.ago.utc, created_on: 2.years.ago.utc, updated_at: 2.years.ago.utc, updated_on: 2.years.ago.utc)
558
- ActiveRecord::Base.default_timezone = :utc
579
+ if ActiveRecord.respond_to?(:default_timezone)
580
+ ActiveRecord.default_timezone = :utc
581
+ else
582
+ ActiveRecord::Base.default_timezone = :utc
583
+ end
559
584
  Timecop.freeze(time) do
560
585
  assert_difference "Book.count", +2 do
561
586
  Book.import %w(title author_name publisher created_at created_on updated_at updated_on), [["LDAP", "Big Bird", "Del Rey", nil, nil, nil, nil], [@existing_book.title, @existing_book.author_name, @existing_book.publisher, @existing_book.created_at, @existing_book.created_on, @existing_book.updated_at, @existing_book.updated_on]]
@@ -1,5 +1,7 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
3
- require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/assertions")
5
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/mysql/import_examples")
4
6
 
5
7
  should_support_mysql_import_functionality
@@ -1,4 +1,6 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/postgresql/import_examples")
3
5
 
4
6
  should_support_postgresql_import_functionality
@@ -1,4 +1,6 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/sqlite3/import_examples')
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/sqlite3/import_examples")
3
5
 
4
6
  should_support_sqlite3_import_functionality
@@ -1,5 +1,7 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/postgresql/import_examples")
3
5
 
4
6
  should_support_postgresql_import_functionality
5
7
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Account < ActiveRecord::Base
2
4
  self.locking_column = :lock
3
5
  end
data/test/models/alarm.rb CHANGED
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Alarm < ActiveRecord::Base
2
4
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Animal < ActiveRecord::Base
2
4
  after_initialize :validate_name_presence, if: :new_record?
3
5
  def validate_name_presence
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bike
2
4
  def self.table_name_prefix
3
5
  'bike_'
4
6
  end
7
+
5
8
  class Maker < ActiveRecord::Base
6
9
  end
7
10
  end
data/test/models/book.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Book < ActiveRecord::Base
2
4
  belongs_to :topic, inverse_of: :books
3
5
  belongs_to :tag, foreign_key: [:tag_id, :parent_id]
data/test/models/car.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Car < ActiveRecord::Base
2
4
  self.primary_key = :Name
3
5
  end
data/test/models/card.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Card < ActiveRecord::Base
2
4
  belongs_to :deck, polymorphic: true
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Chapter < ActiveRecord::Base
2
4
  belongs_to :book, inverse_of: :chapters
3
5
  validates :title, presence: true
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Customer < ActiveRecord::Base
4
+ has_many :orders,
5
+ inverse_of: :customer,
6
+ primary_key: %i(account_id id),
7
+ foreign_key: %i(account_id customer_id)
8
+ end
data/test/models/deck.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Deck < ActiveRecord::Base
2
4
  has_many :cards
3
5
  def self.polymorphic_name
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'book'
2
4
 
3
5
  class Dictionary < Book
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Discount < ActiveRecord::Base
2
4
  belongs_to :discountable, polymorphic: true
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class EndNote < ActiveRecord::Base
2
4
  belongs_to :book, inverse_of: :end_notes
3
5
  validates :note, presence: true
data/test/models/group.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Group < ActiveRecord::Base
2
4
  self.table_name = 'group'
3
5
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Order < ActiveRecord::Base
4
+ belongs_to :customer,
5
+ inverse_of: :orders,
6
+ primary_key: %i(account_id id),
7
+ foreign_key: %i(account_id customer_id)
8
+ end
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class PlayingCard < ActiveRecord::Base
2
4
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Promotion < ActiveRecord::Base
2
4
  self.primary_key = :promotion_id
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Question < ActiveRecord::Base
2
4
  has_one :rule
3
5
  end