atlas_engine 0.5.0 → 0.6.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 (24) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/atlas_engine/address_validation/candidate.rb +3 -2
  3. data/app/models/atlas_engine/address_validation/es/candidate_selector.rb +12 -12
  4. data/app/models/atlas_engine/address_validation/es/validators/full_address.rb +9 -10
  5. data/app/models/atlas_engine/address_validation/es/validators/full_address_street.rb +1 -1
  6. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result.rb +20 -20
  7. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result_base.rb +4 -6
  8. data/app/models/atlas_engine/address_validation/validators/full_address/concern_builder.rb +8 -3
  9. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_concern_builder.rb +6 -2
  10. data/app/models/atlas_engine/address_validation/validators/full_address/{invalid_zip_for_country_concern.rb → invalid_zip_for_country_concern_builder.rb} +14 -13
  11. data/app/models/atlas_engine/address_validation/validators/full_address/{invalid_zip_for_province_concern.rb → invalid_zip_for_province_concern_builder.rb} +15 -15
  12. data/app/models/atlas_engine/address_validation/validators/full_address/no_candidate_result.rb +2 -4
  13. data/app/models/atlas_engine/address_validation/validators/full_address/relevant_components.rb +9 -13
  14. data/app/models/atlas_engine/address_validation/validators/full_address/{unknown_address_concern.rb → unknown_address_concern_builder.rb} +11 -4
  15. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern_builder.rb +38 -0
  16. data/app/models/atlas_engine/address_validation/validators/full_address/{unknown_zip_for_address_concern.rb → unknown_zip_for_address_concern_builder.rb} +12 -10
  17. data/app/models/atlas_engine/address_validation/validators/full_address/{unmatched_field_concern.rb → unmatched_field_concern_builder.rb} +17 -9
  18. data/app/models/atlas_engine/address_validation/validators/full_address/unsupported_script_result.rb +1 -1
  19. data/lib/atlas_engine/version.rb +1 -1
  20. metadata +8 -11
  21. data/app/models/atlas_engine/address_validation/candidate_tuple.rb +0 -15
  22. data/app/models/atlas_engine/address_validation/session.rb +0 -47
  23. data/app/models/atlas_engine/address_validation/validators/full_address/result_updater.rb +0 -42
  24. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3285871f59bee7bdf0084bfb5f985a6e582a173a78baa496c07ba9e8bd526eda
4
- data.tar.gz: b25b6b4d8637c34d43a78e60f457342ccd9f7117f02d039f961476a7a4ef310e
3
+ metadata.gz: 56b5b41a624c3481954aadfa0101c9883dfe3479a3cdec373f8ecccab8bae879
4
+ data.tar.gz: 73ee021ecf5d8357ae8f000df7e963e7504153fdc3b7bb98f188445aa8cd7989
5
5
  SHA512:
6
- metadata.gz: ea581fe90f17c1924f2d370fef820dc8bf18ed094e570666cdc60f13b0ec37b7e8876749176bbb14cd9f408931c525f6f7b29afdf4da47270bf24f147f8f0bce
7
- data.tar.gz: 6ef3dca52ae9bfc224d694c6cb326f743701280cb8d6be14f30421ea247c53822d8017acdeaad5641cfe34ac080ca33a1b010308575057fec2e040a1d7a3222e
6
+ metadata.gz: b93dee8561c73619222ca4a4e803fb2f911b3149955c5b1af7803990318a7ebd36e781c41643cf3076197f579833e9c2d361e8e4550a9d2d3de628d8e7819ef7
7
+ data.tar.gz: f2f593c6e2a7849dae6dce6a52d9402ce7d907a90511664d1218133b5d4a501b5ae98a26e54a06412c3fb37e3dc74c75ae17c575ae24fa4805c02ad888467d21
@@ -6,9 +6,10 @@ module AtlasEngine
6
6
  class Candidate
7
7
  extend T::Sig
8
8
  attr_reader :id, :index
9
+ attr_accessor :position
9
10
 
10
- sig { params(id: String, source: Hash, index: T.nilable(String)).void }
11
- def initialize(id:, source:, index: nil)
11
+ sig { params(id: String, source: Hash, position: Integer, index: T.nilable(String)).void }
12
+ def initialize(id:, source:, position: 0, index: nil)
12
13
  components_hash = Hash.new { |hash, key| hash[key] = Component.new(key, nil) }
13
14
 
14
15
  @components = source.each_with_object(components_hash) do |(key, value), hash|
@@ -21,7 +21,7 @@ module AtlasEngine
21
21
  end
22
22
  end
23
23
 
24
- sig { returns(T.nilable(CandidateTuple)) }
24
+ sig { returns(T.nilable(AddressValidation::Validators::FullAddress::AddressComparison)) }
25
25
  def best_candidate
26
26
  street_sequences_future = datastore.fetch_street_sequences_async
27
27
  city_sequences_future = datastore.fetch_city_sequence_async
@@ -36,28 +36,28 @@ module AtlasEngine
36
36
 
37
37
  attr_reader :datastore, :address
38
38
 
39
- sig { returns(T::Array[CandidateTuple]) }
39
+ sig { returns(T::Array[AddressValidation::Validators::FullAddress::AddressComparison]) }
40
40
  def sorted_candidates
41
- sorted_candidate_tuples = datastore.fetch_full_address_candidates
41
+ sorted_address_comparisons = datastore.fetch_full_address_candidates
42
42
  .filter_map.with_index(1) do |candidate, position|
43
- address_comparison = AtlasEngine::AddressValidation::Validators::FullAddress::AddressComparison.new(
43
+ candidate.position = position
44
+ address_comparison = AddressValidation::Validators::FullAddress::AddressComparison.new(
44
45
  address: address,
45
46
  candidate: candidate,
46
47
  datastore: datastore,
47
48
  )
48
- tuple = CandidateTuple.new(address_comparison, position, candidate)
49
- tuple if tuple.address_comparison.potential_match?
49
+ address_comparison if address_comparison.potential_match?
50
50
  end.sort
51
51
 
52
- emit_sorted_candidates(sorted_candidate_tuples)
53
- sorted_candidate_tuples
52
+ emit_sorted_candidates(sorted_address_comparisons.map(&:candidate))
53
+ sorted_address_comparisons
54
54
  end
55
55
 
56
- sig { params(sorted_candidate_tuples: T::Array[CandidateTuple]).void }
57
- def emit_sorted_candidates(sorted_candidate_tuples)
58
- log_info("Sorted candidates:\n #{sorted_candidate_tuples.map { |tuple| tuple.candidate.serialize }}")
56
+ sig { params(sorted_candidates: T::Array[Candidate]).void }
57
+ def emit_sorted_candidates(sorted_candidates)
58
+ log_info("Sorted candidates:\n #{sorted_candidates.map(&:serialize)}")
59
59
 
60
- initial_position_top_candidate = sorted_candidate_tuples.first&.position || 0
60
+ initial_position_top_candidate = sorted_candidates.first&.position || 0
61
61
  StatsD.distribution(
62
62
  "AddressValidation.query.initial_position_top_candidate",
63
63
  initial_position_top_candidate,
@@ -9,12 +9,11 @@ module AtlasEngine
9
9
  include LogHelper
10
10
 
11
11
  attr_reader :address, :result
12
- attr_accessor :session
13
12
 
14
13
  sig { params(address: TAddress, result: Result).void }
15
14
  def initialize(address:, result: Result.new)
16
15
  super
17
- @session = T.let(Session.new(address: address, matching_strategy: MatchingStrategies::Es), Session)
16
+ @matching_strategy = MatchingStrategies::Es
18
17
  end
19
18
 
20
19
  sig { override.returns(Result) }
@@ -30,23 +29,23 @@ module AtlasEngine
30
29
  sig { returns(AddressValidation::Validators::FullAddress::CandidateResultBase) }
31
30
  def build_candidate_result
32
31
  unless supported_address?(address)
33
- return AddressValidation::Validators::FullAddress::UnsupportedScriptResult.new(session:, result:)
32
+ return AddressValidation::Validators::FullAddress::UnsupportedScriptResult.new(address:, result:)
34
33
  end
35
34
 
36
35
  if best_candidate.nil?
37
- AddressValidation::Validators::FullAddress::NoCandidateResult.new(session:, result:)
36
+ AddressValidation::Validators::FullAddress::NoCandidateResult.new(address:, result:)
38
37
  else
39
38
  AddressValidation::Validators::FullAddress::CandidateResult.new(
40
- candidate: T.must(best_candidate),
39
+ address_comparison: T.must(best_candidate),
40
+ matching_strategy: @matching_strategy,
41
41
  result: result,
42
- session: session,
43
42
  )
44
43
  end
45
44
  end
46
45
 
47
46
  private
48
47
 
49
- sig { returns(T.nilable(CandidateTuple)) }
48
+ sig { returns(T.nilable(AddressValidation::Validators::FullAddress::AddressComparison)) }
50
49
  def best_candidate
51
50
  @best_candidate ||= T.let(
52
51
  begin
@@ -63,15 +62,15 @@ module AtlasEngine
63
62
  # We want our futures to complete even when we do not consume their value.
64
63
  candidate_futures&.map(&:wait!)
65
64
  end,
66
- T.nilable(CandidateTuple),
65
+ T.nilable(AddressValidation::Validators::FullAddress::AddressComparison),
67
66
  )
68
67
  end
69
68
 
70
69
  sig { params(locale: T.nilable(String)).returns(Concurrent::Promises::Future) }
71
70
  def best_candidate_future(locale = nil)
72
71
  AddressValidation::Es::CandidateSelector.new(
73
- datastore: session.datastore(locale: locale),
74
- address: session.address,
72
+ datastore: Es::Datastore.new(address: address, locale: locale),
73
+ address: address,
75
74
  ).best_candidate_async
76
75
  end
77
76
 
@@ -9,7 +9,7 @@ module AtlasEngine
9
9
  sig { params(address: TAddress, result: Result).void }
10
10
  def initialize(address:, result: Result.new)
11
11
  super
12
- @session = T.let(Session.new(address: address, matching_strategy: MatchingStrategies::EsStreet), Session)
12
+ @matching_strategy = MatchingStrategies::EsStreet
13
13
  end
14
14
  end
15
15
  end
@@ -11,16 +11,16 @@ module AtlasEngine
11
11
 
12
12
  sig do
13
13
  params(
14
- candidate: AddressValidation::CandidateTuple,
15
- session: Session,
14
+ address_comparison: AddressComparison,
15
+ matching_strategy: AddressValidation::MatchingStrategies,
16
16
  result: Result,
17
- )
18
- .void
17
+ ).void
19
18
  end
20
- def initialize(candidate:, session:, result:)
21
- super(session: session, result: result)
22
- @candidate = candidate.candidate
23
- @address_comparison = candidate.address_comparison
19
+ def initialize(address_comparison:, matching_strategy:, result:)
20
+ super(address: address_comparison.address, result: result)
21
+ @address_comparison = address_comparison
22
+ @candidate = address_comparison.candidate
23
+ @matching_strategy = matching_strategy
24
24
  end
25
25
 
26
26
  sig { override.void }
@@ -34,7 +34,7 @@ module AtlasEngine
34
34
 
35
35
  sig { returns(T::Boolean) }
36
36
  def suggestable?
37
- ConcernBuilder.should_suggest?(session.address, unmatched_components.keys)
37
+ ConcernBuilder.should_suggest?(address, unmatched_components.keys)
38
38
  end
39
39
 
40
40
  private
@@ -56,11 +56,11 @@ module AtlasEngine
56
56
 
57
57
  sig { void }
58
58
  def add_concerns_without_suggestions
59
- concern = InvalidZipConcernBuilder.for(session.address, [])
59
+ concern = InvalidZipConcernBuilder.for(address, [])
60
60
  result.concerns << concern if concern
61
61
 
62
- if ConcernBuilder.too_many_unmatched_components?(session.address, unmatched_components.keys)
63
- result.concerns << UnknownAddressConcern.new(session.address)
62
+ if ConcernBuilder.too_many_unmatched_components?(address, unmatched_components.keys)
63
+ result.concerns << UnknownAddressConcernBuilder.new(address).build
64
64
  end
65
65
  end
66
66
 
@@ -77,7 +77,7 @@ module AtlasEngine
77
77
  unmatched_component: unmatched_component,
78
78
  unmatched_field: field_name,
79
79
  matched_components: matched_components_to_validate.keys,
80
- address: session.address,
80
+ address: address,
81
81
  suggestion_ids: [suggestion.id].compact,
82
82
  ).build
83
83
  result.concerns << concern
@@ -90,7 +90,7 @@ module AtlasEngine
90
90
  unmatched_fields = { street: unmatched_field_name(:street) }.compact
91
91
 
92
92
  @suggestion ||= SuggestionBuilder.from_comparisons(
93
- session.address.to_h,
93
+ address.to_h,
94
94
  unmatched_components_to_validate,
95
95
  candidate,
96
96
  unmatched_fields,
@@ -126,7 +126,7 @@ module AtlasEngine
126
126
  components = {}
127
127
  @matched_and_unmatched_components ||= begin
128
128
  components_to_compare.each do |component|
129
- components[component] = @address_comparison.for(component).sequence_comparison
129
+ components[component] = address_comparison.for(component).sequence_comparison
130
130
  end
131
131
  components
132
132
  end
@@ -144,7 +144,7 @@ module AtlasEngine
144
144
 
145
145
  sig { returns(RelevantComponents) }
146
146
  def relevant_components
147
- @relevant_components ||= RelevantComponents.new(session, candidate, address_comparison)
147
+ @relevant_components ||= RelevantComponents.new(address_comparison, @matching_strategy)
148
148
  end
149
149
 
150
150
  sig do
@@ -167,17 +167,17 @@ module AtlasEngine
167
167
 
168
168
  original_street = T.must(unmatched_components_to_validate[:street]).left_sequence.raw_value
169
169
 
170
- if session.address.address1.to_s.include?(original_street)
170
+ if address.address1.to_s.include?(original_street)
171
171
  :address1
172
- elsif session.address.address2.to_s.include?(original_street)
172
+ elsif address.address2.to_s.include?(original_street)
173
173
  :address2
174
174
  end
175
175
  end
176
176
 
177
177
  sig { void }
178
178
  def log_unknown_field_name
179
- potential_streets = { potential_streets: session.parsings.potential_streets }
180
- input_address = session.address.to_h.compact_blank.except(:phone)
179
+ potential_streets = { potential_streets: address_comparison.parsings.potential_streets }
180
+ input_address = address.to_h.compact_blank.except(:phone)
181
181
  log_details = input_address.merge(potential_streets)
182
182
  log_info("[AddressValidation] Unable to identify unmatched field name", log_details)
183
183
  end
@@ -11,9 +11,9 @@ module AtlasEngine
11
11
 
12
12
  abstract!
13
13
 
14
- sig { params(session: Session, result: Result).void }
15
- def initialize(session:, result:)
16
- @session = session
14
+ sig { params(address: AbstractAddress, result: Result).void }
15
+ def initialize(address:, result:)
16
+ @address = address
17
17
  @result = result
18
18
  end
19
19
 
@@ -22,9 +22,7 @@ module AtlasEngine
22
22
 
23
23
  private
24
24
 
25
- attr_reader :session, :result
26
-
27
- delegate :address, to: :session
25
+ attr_reader :result, :address
28
26
 
29
27
  sig { void }
30
28
  def update_result_scope
@@ -110,7 +110,7 @@ module AtlasEngine
110
110
  return concern if concern
111
111
 
112
112
  if :province_code.in?(matched_components) && :city.in?(matched_components)
113
- return UnknownZipForAddressConcern.new(address, suggestion_ids)
113
+ return UnknownZipForAddressConcernBuilder.new(address).build(suggestion_ids)
114
114
  end
115
115
 
116
116
  build_default_concern
@@ -119,7 +119,7 @@ module AtlasEngine
119
119
  sig { returns(AddressValidation::Concern) }
120
120
  def build_province_concern
121
121
  if ([:zip, :city] - matched_components).empty?
122
- UnknownProvinceConcern.new(address, suggestion_ids)
122
+ UnknownProvinceConcernBuilder.new(address).build(suggestion_ids)
123
123
  else
124
124
  build_default_concern
125
125
  end
@@ -127,7 +127,12 @@ module AtlasEngine
127
127
 
128
128
  sig { returns(AddressValidation::Concern) }
129
129
  def build_default_concern
130
- UnmatchedFieldConcern.new(unmatched_component, matched_components, address, suggestion_ids, unmatched_field)
130
+ UnmatchedFieldConcernBuilder.new(
131
+ unmatched_component,
132
+ matched_components,
133
+ address,
134
+ unmatched_field,
135
+ ).build(suggestion_ids)
131
136
  end
132
137
  end
133
138
  end
@@ -22,9 +22,13 @@ module AtlasEngine
22
22
  return unless country.has_zip?
23
23
 
24
24
  if country_expects_zone_in_address?(country) && province.province?
25
- InvalidZipForProvinceConcern.new(address, suggestion_ids) unless province.valid_zip?(address.zip)
25
+ return if province.valid_zip?(address.zip)
26
+
27
+ InvalidZipForProvinceConcernBuilder.new(address).build
26
28
  else
27
- InvalidZipForCountryConcern.new(address, suggestion_ids) unless country.valid_zip?(address.zip)
29
+ return if country.valid_zip?(address.zip)
30
+
31
+ InvalidZipForCountryConcernBuilder.new(address).build(suggestion_ids)
28
32
  end
29
33
  end
30
34
 
@@ -5,31 +5,32 @@ module AtlasEngine
5
5
  module AddressValidation
6
6
  module Validators
7
7
  module FullAddress
8
- class InvalidZipForCountryConcern < AddressValidation::Concern
8
+ class InvalidZipForCountryConcernBuilder
9
+ extend T::Sig
9
10
  include ConcernFormatter
10
11
  attr_reader :address
11
12
 
12
- sig { params(address: AbstractAddress, suggestion_ids: T::Array[String]).void }
13
- def initialize(address, suggestion_ids)
13
+ sig { params(address: AbstractAddress).void }
14
+ def initialize(address)
14
15
  @address = address
16
+ end
17
+
18
+ sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
19
+ def build(suggestion_ids = [])
20
+ message = country.field(key: :zip).error(
21
+ code: :invalid_for_country,
22
+ options: { country: country.full_name },
23
+ ).to_s
15
24
 
16
- super(
25
+ Concern.new(
17
26
  code: :zip_invalid_for_country,
18
27
  field_names: [:zip],
19
28
  message: message,
20
29
  type: T.must(Concern::TYPES[:error]),
21
30
  type_level: 1,
22
- suggestion_ids: suggestion_ids
31
+ suggestion_ids: suggestion_ids,
23
32
  )
24
33
  end
25
-
26
- sig { returns(String) }
27
- def message
28
- country.field(key: :zip).error(
29
- code: :invalid_for_country,
30
- options: { country: country.full_name },
31
- ).to_s
32
- end
33
34
  end
34
35
  end
35
36
  end
@@ -5,30 +5,30 @@ module AtlasEngine
5
5
  module AddressValidation
6
6
  module Validators
7
7
  module FullAddress
8
- class InvalidZipForProvinceConcern < AddressValidation::Concern
8
+ class InvalidZipForProvinceConcernBuilder
9
+ extend T::Sig
9
10
  include ConcernFormatter
10
11
  attr_reader :address
11
12
 
12
- sig { params(address: AbstractAddress, suggestion_ids: T::Array[String]).void }
13
- def initialize(address, suggestion_ids)
13
+ def initialize(address)
14
14
  @address = address
15
-
16
- super(
17
- code: :zip_invalid_for_province,
18
- field_names: [:zip],
19
- message: message,
20
- type: T.must(Concern::TYPES[:error]),
21
- type_level: 1,
22
- suggestion_ids: suggestion_ids
23
- )
24
15
  end
25
16
 
26
- sig { returns(String) }
27
- def message
28
- country.field(key: :zip).error(
17
+ sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
18
+ def build(suggestion_ids = [])
19
+ message = country.field(key: :zip).error(
29
20
  code: :invalid_for_province,
30
21
  options: { province: province_name },
31
22
  ).to_s
23
+
24
+ Concern.new(
25
+ field_names: [:zip],
26
+ code: :zip_invalid_for_province,
27
+ type: T.must(Concern::TYPES[:error]),
28
+ type_level: 1,
29
+ suggestion_ids: suggestion_ids,
30
+ message: message,
31
+ )
32
32
  end
33
33
  end
34
34
  end
@@ -10,11 +10,9 @@ module AtlasEngine
10
10
 
11
11
  sig { void }
12
12
  def update_result
13
- result.concerns << UnknownAddressConcern.new(
14
- address,
15
- )
13
+ result.concerns << UnknownAddressConcernBuilder.new(address).build
16
14
 
17
- concern = InvalidZipConcernBuilder.for(session.address, [])
15
+ concern = InvalidZipConcernBuilder.for(address, [])
18
16
  result.concerns << concern if concern
19
17
 
20
18
  update_result_scope
@@ -8,9 +8,6 @@ module AtlasEngine
8
8
  class RelevantComponents
9
9
  extend T::Sig
10
10
 
11
- sig { returns(Session) }
12
- attr_reader :session
13
-
14
11
  sig { returns(Candidate) }
15
12
  attr_reader :candidate
16
13
 
@@ -19,15 +16,15 @@ module AtlasEngine
19
16
 
20
17
  sig do
21
18
  params(
22
- session: Session,
23
- candidate: Candidate,
24
19
  address_comparison: AddressComparison,
20
+ matching_strategy: AtlasEngine::AddressValidation::MatchingStrategies,
25
21
  ).void
26
22
  end
27
- def initialize(session, candidate, address_comparison)
28
- @session = session
29
- @candidate = candidate
23
+ def initialize(address_comparison, matching_strategy)
30
24
  @address_comparison = address_comparison
25
+ @matching_strategy = matching_strategy
26
+ @address = address_comparison.address
27
+ @candidate = address_comparison.candidate
31
28
  @all_supported_components = address_comparison.relevant_components.dup
32
29
  end
33
30
 
@@ -62,8 +59,7 @@ module AtlasEngine
62
59
  def exclude_street_validation?
63
60
  return @exclude_street_validation if defined?(@exclude_street_validation)
64
61
 
65
- @exclude_street_validation = if session.matching_strategy !=
66
- AddressValidation::MatchingStrategies::EsStreet
62
+ @exclude_street_validation = if @matching_strategy != AddressValidation::MatchingStrategies::EsStreet
67
63
  true
68
64
  elsif address_comparison.street_comparison.sequence_comparison.blank?
69
65
  emit_excluded_validation(:street, "not_found")
@@ -80,7 +76,7 @@ module AtlasEngine
80
76
 
81
77
  sig { returns(CountryProfile) }
82
78
  def country_profile
83
- @country_profile ||= CountryProfile.for(session.country_code)
79
+ @country_profile ||= CountryProfile.for(@address.country_code)
84
80
  end
85
81
 
86
82
  sig { params(component: Symbol, reason: String).void }
@@ -88,7 +84,7 @@ module AtlasEngine
88
84
  tags = [
89
85
  "reason:#{reason}",
90
86
  "component:#{component}",
91
- "country:#{session.country_code}",
87
+ "country:#{@address.country_code}",
92
88
  ]
93
89
  StatsD.increment("AddressValidation.skip", sample_rate: 1.0, tags: tags)
94
90
  end
@@ -97,7 +93,7 @@ module AtlasEngine
97
93
  def unsupported_components_for_country
98
94
  @unsupported_components_for_country ||= begin
99
95
  unsupported_components = []
100
- country = Worldwide.region(code: session.address.country_code)
96
+ country = Worldwide.region(code: @address.country_code)
101
97
  unsupported_components << :province_code if country.province_optional?
102
98
  unsupported_components << :province_code if country.hide_provinces_from_addresses
103
99
  unsupported_components << :city unless country.city_required?
@@ -5,7 +5,8 @@ module AtlasEngine
5
5
  module AddressValidation
6
6
  module Validators
7
7
  module FullAddress
8
- class UnknownAddressConcern < AddressValidation::Concern
8
+ class UnknownAddressConcernBuilder
9
+ extend T::Sig
9
10
  include ConcernFormatter
10
11
 
11
12
  sig { returns(TAddress) }
@@ -14,12 +15,18 @@ module AtlasEngine
14
15
  sig { params(address: TAddress).void }
15
16
  def initialize(address)
16
17
  @address = address
17
- super(
18
+ end
19
+
20
+ sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
21
+ def build(suggestion_ids = [])
22
+ message = country.field(key: :address).error(code: :may_not_exist)
23
+
24
+ Concern.new(
18
25
  code: :address_unknown,
19
- message: Worldwide.region(code: address.country_code).field(key: :address).error(code: :may_not_exist),
26
+ message: message,
20
27
  type: T.must(Concern::TYPES[:warning]),
21
28
  type_level: 1,
22
- suggestion_ids: [],
29
+ suggestion_ids: suggestion_ids,
23
30
  field_names: [:address1],
24
31
  )
25
32
  end
@@ -0,0 +1,38 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module AddressValidation
6
+ module Validators
7
+ module FullAddress
8
+ class UnknownProvinceConcernBuilder
9
+ extend T::Sig
10
+ include ConcernFormatter
11
+ attr_reader :address
12
+
13
+ sig { params(address: AbstractAddress).void }
14
+ def initialize(address)
15
+ @address = address
16
+ end
17
+
18
+ sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
19
+ def build(suggestion_ids = [])
20
+ message = country.field(key: :province).error(
21
+ code: :unknown_for_city_and_zip,
22
+ options: { city: address.city, zip: address.zip },
23
+ ).to_s
24
+
25
+ Concern.new(
26
+ code: :province_inconsistent,
27
+ field_names: [:province],
28
+ message: message,
29
+ type: T.must(Concern::TYPES[:error]),
30
+ type_level: 1,
31
+ suggestion_ids: suggestion_ids,
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -5,26 +5,28 @@ module AtlasEngine
5
5
  module AddressValidation
6
6
  module Validators
7
7
  module FullAddress
8
- class UnknownZipForAddressConcern < AddressValidation::Concern
8
+ class UnknownZipForAddressConcernBuilder
9
+ extend T::Sig
9
10
  attr_reader :address
10
11
 
11
- sig { params(address: AbstractAddress, suggestion_ids: T::Array[String]).void }
12
- def initialize(address, suggestion_ids)
12
+ sig { params(address: AbstractAddress).void }
13
+ def initialize(address)
13
14
  @address = address
14
- super(
15
+ end
16
+
17
+ sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
18
+ def build(suggestion_ids = [])
19
+ message = "Enter a valid ZIP for #{address.address1}, #{address.city}"
20
+
21
+ Concern.new(
15
22
  code: :zip_inconsistent,
16
23
  field_names: [:zip],
17
24
  message: message,
18
25
  type: T.must(Concern::TYPES[:warning]),
19
26
  type_level: 3,
20
- suggestion_ids: suggestion_ids
27
+ suggestion_ids: suggestion_ids,
21
28
  )
22
29
  end
23
-
24
- sig { returns(String) }
25
- def message
26
- "Enter a valid ZIP for #{address.address1}, #{address.city}"
27
- end
28
30
  end
29
31
  end
30
32
  end
@@ -5,9 +5,10 @@ module AtlasEngine
5
5
  module AddressValidation
6
6
  module Validators
7
7
  module FullAddress
8
- class UnmatchedFieldConcern < AddressValidation::Concern
8
+ class UnmatchedFieldConcernBuilder
9
+ extend T::Sig
9
10
  include ConcernFormatter
10
- attr_reader :component, :matched_components, :address, :unmatched_field
11
+ attr_reader :address, :component, :matched_components, :unmatched_field
11
12
 
12
13
  COMPONENTS_TO_LABELS = {
13
14
  zip: "ZIP",
@@ -25,26 +26,34 @@ module AtlasEngine
25
26
  unmatched_component: Symbol,
26
27
  matched_components: T::Array[Symbol],
27
28
  address: AbstractAddress,
28
- suggestion_ids: T::Array[String],
29
29
  unmatched_field: T.nilable(Symbol),
30
30
  ).void
31
31
  end
32
- def initialize(unmatched_component, matched_components, address, suggestion_ids, unmatched_field = nil)
32
+ def initialize(unmatched_component, matched_components, address, unmatched_field = nil)
33
+ @address = address
33
34
  @component = unmatched_component
34
35
  @matched_components = matched_components
35
- @address = address
36
36
  @unmatched_field = unmatched_field
37
+ end
37
38
 
38
- super(
39
+ sig do
40
+ params(
41
+ suggestion_ids: T::Array[String],
42
+ ).returns(Concern)
43
+ end
44
+ def build(suggestion_ids = [])
45
+ Concern.new(
39
46
  code: code,
40
47
  field_names: field_names,
41
48
  message: message,
42
49
  type: T.must(Concern::TYPES[:warning]),
43
50
  type_level: 3,
44
- suggestion_ids: suggestion_ids
51
+ suggestion_ids: suggestion_ids,
45
52
  )
46
53
  end
47
54
 
55
+ private
56
+
48
57
  sig { returns(String) }
49
58
  def message
50
59
  "Enter a valid #{COMPONENTS_TO_LABELS[component]} for #{valid_address_component_values.join(", ")}"
@@ -60,8 +69,6 @@ module AtlasEngine
60
69
  [field_name]
61
70
  end
62
71
 
63
- private
64
-
65
72
  sig { returns(T::Array[String]) }
66
73
  def valid_address_component_values
67
74
  matched_components.last(2).map do |component|
@@ -74,6 +81,7 @@ module AtlasEngine
74
81
  SHORTENED_COMPONENT_NAMES[component] || component
75
82
  end
76
83
 
84
+ sig { returns(Symbol) }
77
85
  def field_name
78
86
  unmatched_field || shortened_component_name
79
87
  end
@@ -10,7 +10,7 @@ module AtlasEngine
10
10
 
11
11
  sig { void }
12
12
  def update_result
13
- concern = InvalidZipConcernBuilder.for(session.address, [])
13
+ concern = InvalidZipConcernBuilder.for(address, [])
14
14
  result.concerns << concern if concern
15
15
 
16
16
  update_result_scope
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module AtlasEngine
5
- VERSION = "0.5.0"
5
+ VERSION = "0.6.0"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atlas_engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-20 00:00:00.000000000 Z
11
+ date: 2024-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: annex_29
@@ -437,7 +437,6 @@ files:
437
437
  - app/models/atlas_engine/address_validation/abstract_address.rb
438
438
  - app/models/atlas_engine/address_validation/address.rb
439
439
  - app/models/atlas_engine/address_validation/candidate.rb
440
- - app/models/atlas_engine/address_validation/candidate_tuple.rb
441
440
  - app/models/atlas_engine/address_validation/concern.rb
442
441
  - app/models/atlas_engine/address_validation/concern_producer.rb
443
442
  - app/models/atlas_engine/address_validation/concern_queue.rb
@@ -463,7 +462,6 @@ files:
463
462
  - app/models/atlas_engine/address_validation/request.rb
464
463
  - app/models/atlas_engine/address_validation/result.rb
465
464
  - app/models/atlas_engine/address_validation/runs_validation.rb
466
- - app/models/atlas_engine/address_validation/session.rb
467
465
  - app/models/atlas_engine/address_validation/statsd_emitter.rb
468
466
  - app/models/atlas_engine/address_validation/strategies.rb
469
467
  - app/models/atlas_engine/address_validation/suggestion.rb
@@ -485,20 +483,19 @@ files:
485
483
  - app/models/atlas_engine/address_validation/validators/full_address/exclusions/exclusion_base.rb
486
484
  - app/models/atlas_engine/address_validation/validators/full_address/field_comparison_base.rb
487
485
  - app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_concern_builder.rb
488
- - app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_country_concern.rb
489
- - app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_province_concern.rb
486
+ - app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_country_concern_builder.rb
487
+ - app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_province_concern_builder.rb
490
488
  - app/models/atlas_engine/address_validation/validators/full_address/no_candidate_result.rb
491
489
  - app/models/atlas_engine/address_validation/validators/full_address/number_comparison.rb
492
490
  - app/models/atlas_engine/address_validation/validators/full_address/postal_code_matcher.rb
493
491
  - app/models/atlas_engine/address_validation/validators/full_address/province_code_comparison.rb
494
492
  - app/models/atlas_engine/address_validation/validators/full_address/relevant_components.rb
495
- - app/models/atlas_engine/address_validation/validators/full_address/result_updater.rb
496
493
  - app/models/atlas_engine/address_validation/validators/full_address/street_comparison.rb
497
494
  - app/models/atlas_engine/address_validation/validators/full_address/suggestion_builder.rb
498
- - app/models/atlas_engine/address_validation/validators/full_address/unknown_address_concern.rb
499
- - app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern.rb
500
- - app/models/atlas_engine/address_validation/validators/full_address/unknown_zip_for_address_concern.rb
501
- - app/models/atlas_engine/address_validation/validators/full_address/unmatched_field_concern.rb
495
+ - app/models/atlas_engine/address_validation/validators/full_address/unknown_address_concern_builder.rb
496
+ - app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern_builder.rb
497
+ - app/models/atlas_engine/address_validation/validators/full_address/unknown_zip_for_address_concern_builder.rb
498
+ - app/models/atlas_engine/address_validation/validators/full_address/unmatched_field_concern_builder.rb
502
499
  - app/models/atlas_engine/address_validation/validators/full_address/unsupported_script_result.rb
503
500
  - app/models/atlas_engine/address_validation/validators/full_address/zip_comparison.rb
504
501
  - app/models/atlas_engine/address_validation/validators/predicates/cache.rb
@@ -1,15 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module AtlasEngine
5
- module AddressValidation
6
- CandidateTuple = Struct.new(:address_comparison, :position, :candidate) do
7
- extend T::Sig
8
-
9
- sig { params(other: CandidateTuple).returns(Integer) }
10
- def <=>(other)
11
- to_a[0..1] <=> other.to_a[0..1] # only consider address_comparison and position
12
- end
13
- end
14
- end
15
- end
@@ -1,47 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "forwardable"
5
-
6
- module AtlasEngine
7
- module AddressValidation
8
- class Session
9
- extend Forwardable
10
- extend T::Sig
11
-
12
- sig { returns(AbstractAddress) }
13
- attr_reader :address
14
-
15
- sig { returns(MatchingStrategies) }
16
- attr_accessor :matching_strategy
17
-
18
- sig { returns(T::Hash[String, AtlasEngine::AddressValidation::DatastoreBase]) }
19
- attr_reader :datastore_hash
20
-
21
- def_delegators :@address, :address1, :address2, :city, :province_code, :country_code, :zip, :phone
22
-
23
- sig do
24
- params(
25
- address: AbstractAddress,
26
- matching_strategy: MatchingStrategies,
27
- ).void
28
- end
29
- def initialize(address:, matching_strategy: MatchingStrategies::Es)
30
- @address = address
31
- @matching_strategy = matching_strategy
32
- @datastore_hash = T.let({}, T::Hash[String, AtlasEngine::AddressValidation::DatastoreBase])
33
- end
34
-
35
- sig { params(locale: T.nilable(String)).returns(ValidationTranscriber::AddressParsings) }
36
- def parsings(locale: nil)
37
- datastore(locale: locale).parsings
38
- end
39
-
40
- sig { params(locale: T.nilable(String)).returns(AtlasEngine::AddressValidation::DatastoreBase) }
41
- def datastore(locale: nil)
42
- key = locale || "default"
43
- @datastore_hash[key] ||= AtlasEngine::AddressValidation::Es::Datastore.new(address: address, locale: locale)
44
- end
45
- end
46
- end
47
- end
@@ -1,42 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module AtlasEngine
5
- module AddressValidation
6
- module Validators
7
- module FullAddress
8
- class ResultUpdater
9
- extend T::Sig
10
- extend T::Helpers
11
- abstract!
12
-
13
- sig { params(session: Session, result: Result).void }
14
- def initialize(session:, result:)
15
- @session = session
16
- @result = result
17
- end
18
-
19
- private
20
-
21
- attr_reader :session, :result
22
-
23
- delegate :address, to: :session
24
-
25
- sig { void }
26
- def update_result_scope
27
- concern_fields = result.concerns.flat_map(&:field_names).uniq
28
- scopes_to_remove = concern_fields.flat_map { |field| contained_scopes_for(field) }
29
- result.validation_scope.reject! { |scope| scope.in?(scopes_to_remove) }
30
- end
31
-
32
- sig { params(scope: Symbol).returns(T.nilable(T::Array[Symbol])) }
33
- def contained_scopes_for(scope)
34
- return [] unless (scope_index = Result::SORTED_VALIDATION_SCOPES.index(scope))
35
-
36
- Result::SORTED_VALIDATION_SCOPES.slice(scope_index..)
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,38 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module AtlasEngine
5
- module AddressValidation
6
- module Validators
7
- module FullAddress
8
- class UnknownProvinceConcern < AddressValidation::Concern
9
- include ConcernFormatter
10
- attr_reader :address
11
-
12
- sig { params(address: AbstractAddress, suggestion_ids: T::Array[String]).void }
13
- def initialize(address, suggestion_ids)
14
- @address = address
15
- super(
16
- code: :province_inconsistent,
17
- field_names: [:province],
18
- message: message,
19
- type: T.must(Concern::TYPES[:error]),
20
- type_level: 1,
21
- suggestion_ids: suggestion_ids
22
- )
23
- end
24
-
25
- sig { returns(String) }
26
- def message
27
- country
28
- .field(key: :province)
29
- .error(
30
- code: :unknown_for_city_and_zip,
31
- options: { city: address.city, zip: address.zip },
32
- ).to_s
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end