topographer 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/lib/topographer/exceptions.rb +5 -3
  3. data/lib/topographer/importer.rb +25 -9
  4. data/lib/topographer/importer/helpers.rb +19 -13
  5. data/lib/topographer/importer/helpers/write_log_to_csv.rb +75 -67
  6. data/lib/topographer/importer/importable.rb +7 -3
  7. data/lib/topographer/importer/input.rb +11 -4
  8. data/lib/topographer/importer/input/base.rb +21 -15
  9. data/lib/topographer/importer/input/delimited_spreadsheet.rb +55 -0
  10. data/lib/topographer/importer/input/roo.rb +31 -24
  11. data/lib/topographer/importer/input/source_data.rb +14 -8
  12. data/lib/topographer/importer/logger.rb +10 -6
  13. data/lib/topographer/importer/logger/base.rb +75 -66
  14. data/lib/topographer/importer/logger/fatal_error_entry.rb +22 -16
  15. data/lib/topographer/importer/logger/log_entry.rb +31 -25
  16. data/lib/topographer/importer/logger/simple.rb +25 -19
  17. data/lib/topographer/importer/mapper.rb +58 -53
  18. data/lib/topographer/importer/mapper/default_field_mapping.rb +23 -17
  19. data/lib/topographer/importer/mapper/field_mapping.rb +56 -49
  20. data/lib/topographer/importer/mapper/ignored_field_mapping.rb +14 -7
  21. data/lib/topographer/importer/mapper/mapper_builder.rb +57 -44
  22. data/lib/topographer/importer/mapper/mapping_columns.rb +51 -44
  23. data/lib/topographer/importer/mapper/mapping_validator.rb +39 -32
  24. data/lib/topographer/importer/mapper/result.rb +21 -15
  25. data/lib/topographer/importer/mapper/validation_field_mapping.rb +35 -28
  26. data/lib/topographer/importer/strategy.rb +12 -6
  27. data/lib/topographer/importer/strategy/base.rb +43 -38
  28. data/lib/topographer/importer/strategy/create_or_update_record.rb +39 -34
  29. data/lib/topographer/importer/strategy/import_new_record.rb +16 -10
  30. data/lib/topographer/importer/strategy/import_status.rb +27 -20
  31. data/lib/topographer/importer/strategy/update_record.rb +28 -24
  32. data/lib/topographer/version.rb +1 -1
  33. data/spec/assets/test_files/a_csv.csv +3 -0
  34. data/spec/topographer/importer/helpers/write_log_to_csv_spec.rb +4 -4
  35. data/spec/topographer/importer/importer_spec.rb +21 -5
  36. data/spec/topographer/importer/input/delimited_spreadsheet_spec.rb +90 -0
  37. data/spec/topographer/importer/input/source_data_spec.rb +2 -2
  38. data/spec/topographer/importer/logger/base_spec.rb +19 -0
  39. data/spec/topographer/importer/logger/fatal_error_entry_spec.rb +2 -2
  40. data/spec/topographer/importer/logger/simple_spec.rb +3 -3
  41. data/spec/topographer/importer/mapper/default_field_mapping_spec.rb +2 -2
  42. data/spec/topographer/importer/mapper/field_mapping_spec.rb +21 -21
  43. data/spec/topographer/importer/mapper/mapper_builder_spec.rb +9 -9
  44. data/spec/topographer/importer/mapper/mapping_validator_spec.rb +10 -10
  45. data/spec/topographer/importer/mapper/validation_field_mapping_spec.rb +3 -3
  46. data/spec/topographer/importer/mapper_spec.rb +25 -25
  47. data/spec/topographer/importer/strategy/base_spec.rb +16 -5
  48. data/spec/topographer/importer/strategy/create_or_update_record_spec.rb +3 -3
  49. data/spec/topographer/importer/strategy/import_new_records_spec.rb +5 -5
  50. data/spec/topographer/importer/strategy/mapped_model.rb +9 -0
  51. data/spec/topographer/importer/strategy/update_record_spec.rb +3 -3
  52. data/topographer.gemspec +3 -2
  53. metadata +101 -102
@@ -1,12 +1,18 @@
1
- class Topographer::Importer::Input::SourceData
2
- attr_reader :source_identifier, :data
1
+ module Topographer
2
+ class Importer
3
+ module Input
4
+ class SourceData
5
+ attr_reader :source_identifier, :data
3
6
 
4
- def initialize(source_identifier, data)
5
- @source_identifier = source_identifier
6
- @data = data
7
- end
7
+ def initialize(source_identifier, data)
8
+ @source_identifier = source_identifier
9
+ @data = data
10
+ end
8
11
 
9
- def empty?
10
- @data.empty?
12
+ def empty?
13
+ @data.empty?
14
+ end
15
+ end
16
+ end
11
17
  end
12
18
  end
@@ -1,8 +1,12 @@
1
- class Topographer::Importer::Logger
2
- require_relative 'logger/base'
3
- require_relative 'logger/simple'
4
- require_relative 'logger/file'
5
- require_relative 'logger/log_entry'
6
- require_relative 'logger/fatal_error_entry'
1
+ require_relative 'logger/base'
2
+ require_relative 'logger/simple'
3
+ require_relative 'logger/file'
4
+ require_relative 'logger/log_entry'
5
+ require_relative 'logger/fatal_error_entry'
7
6
 
7
+ module Topographer
8
+ class Importer
9
+ module Logger
10
+ end
11
+ end
8
12
  end
@@ -1,69 +1,78 @@
1
- class Topographer::Importer::Logger::Base
2
-
3
- attr_reader :fatal_errors
4
-
5
- def initialize
6
- @fatal_errors = []
7
- end
8
-
9
- def successes
10
- raise NotImplementedError
11
- end
12
-
13
- def failures
14
- raise NotImplementedError
15
- end
16
-
17
- def log_import(log_entry)
18
- if log_entry.success?
19
- log_success(log_entry)
20
- else
21
- log_failure(log_entry)
1
+ module Topographer
2
+ class Importer
3
+ module Logger
4
+ class Base
5
+
6
+ attr_reader :fatal_errors
7
+
8
+ def initialize
9
+ @fatal_errors = []
10
+ end
11
+
12
+ def successes
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def failures
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def log_import(log_entry)
21
+ if log_entry.success?
22
+ log_success(log_entry)
23
+ else
24
+ log_failure(log_entry)
25
+ end
26
+ end
27
+
28
+ def log_success(log_entry)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def log_failure(log_entry)
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def log_fatal(source, message)
37
+ @fatal_errors << Topographer::Importer::Logger::FatalErrorEntry.new(source, message)
38
+ end
39
+
40
+ def successful_imports
41
+ raise NotImplementedError
42
+ end
43
+
44
+ def failed_imports
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def entries?
49
+ total_imports > 0
50
+ end
51
+
52
+ def total_imports
53
+ (successful_imports + failed_imports)
54
+ end
55
+
56
+ def all_entries
57
+ (successes + failures + fatal_errors).sort { |a, b| a.timestamp <=> b.timestamp }
58
+ end
59
+
60
+ def errors?
61
+ fatal_error? || failed_imports > 0
62
+ end
63
+
64
+ def success?
65
+ !errors?
66
+ end
67
+
68
+ def fatal_error?
69
+ @fatal_errors.any?
70
+ end
71
+
72
+ def save
73
+ raise NotImplementedError
74
+ end
75
+ end
22
76
  end
23
77
  end
24
-
25
- def log_success(log_entry)
26
- raise NotImplementedError
27
- end
28
-
29
- def log_failure(log_entry)
30
- raise NotImplementedError
31
- end
32
-
33
- def log_fatal(source, message)
34
- @fatal_errors << Topographer::Importer::Logger::FatalErrorEntry.new(source, message)
35
- end
36
-
37
- def successful_imports
38
- raise NotImplementedError
39
- end
40
-
41
- def failed_imports
42
- raise NotImplementedError
43
- end
44
-
45
- def entries?
46
- total_imports > 0
47
- end
48
-
49
- def total_imports
50
- (successful_imports + failed_imports)
51
- end
52
-
53
- def all_entries
54
- (successes + failures + fatal_errors).sort {|a, b| a.timestamp <=> b.timestamp}
55
- end
56
-
57
- def errors?
58
- fatal_error? || failed_imports > 0
59
- end
60
-
61
- def fatal_error?
62
- @fatal_errors.any?
63
- end
64
-
65
- def save
66
- raise NotImplementedError
67
- end
68
-
69
78
  end
@@ -1,19 +1,25 @@
1
- class Topographer::Importer::Logger::FatalErrorEntry < Topographer::Importer::Logger::LogEntry
2
- attr_reader :message, :timestamp, :model_name
1
+ module Topographer
2
+ class Importer
3
+ module Logger
4
+ class FatalErrorEntry < Topographer::Importer::Logger::LogEntry
5
+ attr_reader :message, :timestamp, :model_name
3
6
 
4
- def initialize(input_identifier, message)
5
- @timestamp = DateTime.now
6
- @input_identifier = input_identifier
7
- @model_name = 'N/A'
8
- @message = message
9
- end
10
- def source_identifier
11
- 'import failure'
12
- end
13
- def details
14
- {}
15
- end
16
- def failure?
17
- true
7
+ def initialize(input_identifier, message)
8
+ @timestamp = DateTime.now
9
+ @input_identifier = input_identifier
10
+ @model_name = 'N/A'
11
+ @message = message
12
+ end
13
+ def source_identifier
14
+ 'import failure'
15
+ end
16
+ def details
17
+ {}
18
+ end
19
+ def failure?
20
+ true
21
+ end
22
+ end
23
+ end
18
24
  end
19
25
  end
@@ -1,34 +1,40 @@
1
- class Topographer::Importer::Logger::LogEntry
2
- attr_reader :input_identifier,
3
- :model_name
1
+ module Topographer
2
+ class Importer
3
+ module Logger
4
+ class LogEntry
5
+ attr_reader :input_identifier,
6
+ :model_name
4
7
 
5
- def initialize(input_identifier, model_name, import_status)
6
- @input_identifier = input_identifier
7
- @model_name = model_name
8
- @import_status = import_status
9
- end
8
+ def initialize(input_identifier, model_name, import_status)
9
+ @input_identifier = input_identifier
10
+ @model_name = model_name
11
+ @import_status = import_status
12
+ end
10
13
 
11
- def source_identifier
12
- @import_status.input_identifier
13
- end
14
+ def source_identifier
15
+ @import_status.input_identifier
16
+ end
14
17
 
15
- def message
16
- @import_status.message
17
- end
18
+ def message
19
+ @import_status.message
20
+ end
18
21
 
19
- def timestamp
20
- @import_status.timestamp
21
- end
22
+ def timestamp
23
+ @import_status.timestamp
24
+ end
22
25
 
23
- def details
24
- @import_status.errors
25
- end
26
+ def details
27
+ @import_status.errors
28
+ end
26
29
 
27
- def success?
28
- !failure?
29
- end
30
+ def success?
31
+ !failure?
32
+ end
30
33
 
31
- def failure?
32
- @import_status.errors?
34
+ def failure?
35
+ @import_status.errors?
36
+ end
37
+ end
38
+ end
33
39
  end
34
40
  end
@@ -1,27 +1,33 @@
1
- class Topographer::Importer::Logger::Simple < Topographer::Importer::Logger::Base
1
+ module Topographer
2
+ class Importer
3
+ module Logger
4
+ class Simple < Topographer::Importer::Logger::Base
2
5
 
3
- attr_reader :successes, :failures
6
+ attr_reader :successes, :failures
4
7
 
5
- def initialize
6
- @successes = []
7
- @failures = []
8
- super
9
- end
8
+ def initialize
9
+ @successes = []
10
+ @failures = []
11
+ super
12
+ end
10
13
 
11
- def log_success(message)
12
- @successes << message
13
- end
14
+ def log_success(message)
15
+ @successes << message
16
+ end
14
17
 
15
- def log_failure(message)
16
- @failures << message
17
- end
18
+ def log_failure(message)
19
+ @failures << message
20
+ end
18
21
 
19
- def successful_imports
20
- @successes.size
21
- end
22
+ def successful_imports
23
+ @successes.size
24
+ end
22
25
 
23
- def failed_imports
24
- @failures.size
25
- end
26
+ def failed_imports
27
+ @failures.size
28
+ end
26
29
 
30
+ end
31
+ end
32
+ end
27
33
  end
@@ -1,68 +1,73 @@
1
- class Topographer::Importer::Mapper
2
- require_relative 'mapper/mapping_validator'
3
- require_relative 'mapper/mapping_columns'
4
- require_relative 'mapper/mapper_builder'
5
- require_relative 'mapper/field_mapping'
6
- require_relative 'mapper/ignored_field_mapping'
7
- require_relative 'mapper/validation_field_mapping'
8
- require_relative 'mapper/default_field_mapping'
9
- require_relative 'mapper/result'
1
+ require_relative 'mapper/mapping_validator'
2
+ require_relative 'mapper/mapping_columns'
3
+ require_relative 'mapper/mapper_builder'
4
+ require_relative 'mapper/field_mapping'
5
+ require_relative 'mapper/ignored_field_mapping'
6
+ require_relative 'mapper/validation_field_mapping'
7
+ require_relative 'mapper/default_field_mapping'
8
+ require_relative 'mapper/result'
10
9
 
11
- include Topographer::Importer::Mapper::MappingColumns
10
+ module Topographer
11
+ class Importer
12
+ class Mapper
12
13
 
13
- attr_reader :required_mappings, :optional_mappings, :ignored_mappings, :validation_mappings,
14
- :default_values, :key_fields, :bad_columns, :missing_columns, :model_class, :key_fields
14
+ include Topographer::Importer::Mapper::MappingColumns
15
15
 
16
- def self.build_mapper(model_class)
17
- mapper_builder = MapperBuilder.new()
18
- yield mapper_builder
16
+ attr_reader :required_mappings, :optional_mappings, :ignored_mappings, :validation_mappings,
17
+ :default_values, :key_fields, :bad_columns, :missing_columns, :model_class, :key_fields
19
18
 
20
- new(mapper_builder, model_class)
21
- end
19
+ def self.build_mapper(model_class)
20
+ mapper_builder = MapperBuilder.new()
21
+ yield mapper_builder
22
22
 
23
- def initialize(mapper_builder, model_class)
24
- @required_mappings = mapper_builder.required_mappings
25
- @optional_mappings = mapper_builder.optional_mappings
26
- @ignored_mappings = mapper_builder.ignored_mappings
27
- @validation_mappings = mapper_builder.validation_mappings
28
- @default_values = mapper_builder.default_values
29
- @key_fields = mapper_builder.key_fields
30
- @model_class = model_class
31
- end
23
+ new(mapper_builder, model_class)
24
+ end
32
25
 
33
- def input_structure_valid?(input_columns, options={})
34
- ignore_unmapped_columns = options.fetch(:ignore_unmapped_columns, false)
35
- @bad_columns ||= input_columns - mapped_input_columns
36
- @missing_columns ||= required_input_columns - input_columns
26
+ def initialize(mapper_builder, model_class)
27
+ @required_mappings = mapper_builder.required_mappings
28
+ @optional_mappings = mapper_builder.optional_mappings
29
+ @ignored_mappings = mapper_builder.ignored_mappings
30
+ @validation_mappings = mapper_builder.validation_mappings
31
+ @default_values = mapper_builder.default_values
32
+ @key_fields = mapper_builder.key_fields
33
+ @field_mappings = mapper_builder.field_mappings
34
+ @model_class = model_class
35
+ end
37
36
 
38
- if ignore_unmapped_columns
39
- @missing_columns.empty?
40
- else
41
- @bad_columns.empty? && @missing_columns.empty?
42
- end
43
- end
37
+ def input_structure_valid?(input_columns, options={})
38
+ ignore_unmapped_columns = options.fetch(:ignore_unmapped_columns, false)
39
+ @bad_columns ||= input_columns - mapped_input_columns
40
+ @missing_columns ||= required_input_columns - input_columns
44
41
 
45
- def map_input(source_data)
46
- mapping_result = Result.new(source_data.source_identifier)
42
+ if ignore_unmapped_columns
43
+ @missing_columns.empty?
44
+ else
45
+ @bad_columns.empty? && @missing_columns.empty?
46
+ end
47
+ end
47
48
 
48
- if source_data.empty?
49
- handle_no_data(mapping_result)
50
- else
51
- @validation_mappings.values.each do |validation_field_mapping|
52
- validation_field_mapping.process_input(source_data.data, mapping_result)
49
+ def map_input(source_data)
50
+ mapping_result = Result.new(source_data.source_identifier)
51
+
52
+ if source_data.empty?
53
+ handle_no_data(mapping_result)
54
+ else
55
+ @validation_mappings.values.each do |validation_field_mapping|
56
+ validation_field_mapping.process_input(source_data.data, mapping_result)
57
+ end
58
+
59
+ mappings.each do |_output_field, field_mapping|
60
+ field_mapping.process_input(source_data.data, mapping_result)
61
+ end
62
+ end
63
+
64
+ mapping_result
53
65
  end
54
66
 
55
- output_fields.each do |output_field|
56
- field_mapping = mappings[output_field]
57
- field_mapping.process_input(source_data.data, mapping_result)
67
+ private
68
+ def handle_no_data(mapping_result)
69
+ mapping_result.add_error('EmptyRow', 'Unable to import empty row.')
58
70
  end
59
71
  end
60
-
61
- mapping_result
62
72
  end
63
-
64
- private
65
- def handle_no_data(mapping_result)
66
- mapping_result.add_error('EmptyRow', 'Unable to import empty row.')
67
- end
68
73
  end