atlas_engine 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -17
  3. data/app/graphql/atlas_engine/schema.graphql +10 -1
  4. data/app/graphql/atlas_engine/types/address_validation/concern_type.rb +8 -1
  5. data/app/graphql/atlas_engine/types/address_validation/suggestion_type.rb +4 -0
  6. data/app/graphql/atlas_engine/types/message_format_type.rb +11 -0
  7. data/app/graphql/atlas_engine/types/query_type.rb +3 -1
  8. data/app/lib/atlas_engine/validation_transcriber/address_parsings.rb +14 -9
  9. data/app/models/atlas_engine/address_validation/es/validators/full_address.rb +18 -5
  10. data/app/models/atlas_engine/address_validation/es/validators/full_address_street.rb +2 -2
  11. data/app/models/atlas_engine/address_validation/full_address_validator_base.rb +6 -2
  12. data/app/models/atlas_engine/address_validation/message_format.rb +13 -0
  13. data/app/models/atlas_engine/address_validation/predicate_pipeline_builder.rb +90 -0
  14. data/app/models/atlas_engine/address_validation/request.rb +1 -0
  15. data/app/models/atlas_engine/address_validation/suggestion.rb +26 -1
  16. data/app/models/atlas_engine/address_validation/validator.rb +31 -14
  17. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result.rb +9 -5
  18. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result_base.rb +4 -3
  19. data/app/models/atlas_engine/address_validation/validators/full_address/concern_builder.rb +19 -4
  20. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_concern_builder.rb +4 -3
  21. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_country_concern_builder.rb +6 -4
  22. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_province_concern_builder.rb +4 -2
  23. data/app/models/atlas_engine/address_validation/validators/full_address/no_candidate_result.rb +1 -1
  24. data/app/models/atlas_engine/address_validation/validators/full_address/suggestion_builder.rb +5 -2
  25. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_address_concern_builder.rb +16 -4
  26. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern_builder.rb +8 -3
  27. data/app/models/atlas_engine/address_validation/validators/full_address/unmatched_field_concern_builder.rb +13 -3
  28. data/app/models/atlas_engine/address_validation/validators/full_address/unsupported_script_result.rb +1 -1
  29. data/app/models/atlas_engine/address_validation/validators/predicates/city/present.rb +1 -1
  30. data/app/models/atlas_engine/address_validation/validators/predicates/country/exists.rb +5 -1
  31. data/app/models/atlas_engine/address_validation/validators/predicates/country/valid_for_zip.rb +1 -1
  32. data/app/models/atlas_engine/address_validation/validators/predicates/neighborhood/present.rb +35 -0
  33. data/app/models/atlas_engine/address_validation/validators/predicates/not_exceed_max_length.rb +18 -3
  34. data/app/models/atlas_engine/address_validation/validators/predicates/phone/valid.rb +3 -1
  35. data/app/models/atlas_engine/address_validation/validators/predicates/predicate.rb +6 -2
  36. data/app/models/atlas_engine/address_validation/validators/predicates/province/exists.rb +3 -1
  37. data/app/models/atlas_engine/address_validation/validators/predicates/province/valid_for_country.rb +3 -1
  38. data/app/models/atlas_engine/address_validation/validators/predicates/street/present.rb +3 -1
  39. data/app/models/atlas_engine/address_validation/validators/predicates/street_name/present.rb +35 -0
  40. data/app/models/atlas_engine/address_validation/validators/predicates/street_number/present.rb +35 -0
  41. data/app/models/atlas_engine/address_validation/validators/predicates/zip/present.rb +2 -2
  42. data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_country.rb +1 -1
  43. data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_province.rb +1 -1
  44. data/app/models/atlas_engine/services/validation.rb +4 -0
  45. data/db/data/validation_pipelines/es.yml +46 -0
  46. data/db/data/validation_pipelines/es_street.yml +46 -0
  47. data/db/data/validation_pipelines/local.yml +46 -0
  48. data/lib/atlas_engine/version.rb +1 -1
  49. metadata +39 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dde673ac6063402f30381011574f018aee19ac9d6e9b961c04252cf76cfd49e5
4
- data.tar.gz: b5c0adce91a39d744004b902e2b3a4a13544a50af756bb1ace003e391b0d3643
3
+ metadata.gz: 2ac0ad464ab86fe1db96b5ca3f5a69254d6ad52571d8c83350645c9e031ea58b
4
+ data.tar.gz: f683950cfa6d89c1cdf4935d8a49d76e416c57220ac29e5aa62adcdaf2a628d5
5
5
  SHA512:
6
- metadata.gz: dfe8b1e2a4ebe506f55b62a541b57ab22c0cca456ed4ef071007d43e106d0ed0b904389fd22a0424661ca76cd2f7bdc4ed5887866663eaee361f9afd5e7d3ac0
7
- data.tar.gz: a632f397142d60a6da29ae440ed686ff920cb15e62349c3abb0ef9a3ccaddd975936870d55aee45867851337f10d46982f6740bbcf3379f9d74aeeed15369577
6
+ metadata.gz: 79ae2f83d4b4ee2d65a7d6e566bee41ac3b0c5e44f879090b4659151ca9f7987e128badf6f31569530c142ea683b8df6dce10275423469924c44f1477f6480d6
7
+ data.tar.gz: e1a0e889113742443408d479dba7f1bb294230d4bcfd0af8f128e6c200a19d6c595c1bdf420798ebd2a9cb9caa8fa2cd69ef21ab4361ae066aa6a48861e9f91d
data/README.md CHANGED
@@ -25,7 +25,6 @@ query validation {
25
25
  zip: "K2P 2L8"
26
26
  }
27
27
  locale: "en"
28
- matchingStrategy: LOCAL
29
28
  ) {
30
29
  validationScope
31
30
  concerns {
@@ -70,21 +69,6 @@ presence or absence differs per country.
70
69
 
71
70
  **Locale:** The language in which to render any messages in the validation API response.
72
71
 
73
- **MatchingStrategy:** The strategy used to evaluate the validity of the address input. Out of the box, Atlas Engine
74
- supports three different matching strategies: `local`, `es`, and `es_street`.
75
- - `local` matching uses the [worldwide](https://github.com/Shopify/worldwide) gem to provide the most basic level of
76
- address validation. This may include simple errors (required fields not populated) or more advanced errors (province
77
- not belonging to the country, zip code not belonging to the province). This level of matching does not require
78
- [ingestion](#ingestion) of country data to work, but the level of support and suggestions it can provide in its
79
- responses is minimal.
80
- - `es` matching uses data indexed in elasticsearch via our [ingestion](#ingestion) process to validate the city,
81
- province, country, and zip code fields of the input address, in addition to all of the basic functionality provided
82
- in the `local` strategy. A more detailed explanation for how this strategy works can be found [here](#elasticsearch-matching-strategy).
83
- - `es_street` is our most advanced matching strategy and requires the highest quality data indexed in elasticsearch
84
- via our [ingestion](#ingestion) process. This matching strategy provides everything that `es` and `local` does along
85
- with validation of the address1 and address2 components of the address input. A more detailed explanation of how
86
- this strategy works can be found [here](#elasticsearch-matching-strategy).
87
-
88
72
  **Validation Scope:** This response object is populated with the field names from the input that have been successfully
89
73
  validated.
90
74
 
@@ -109,7 +93,6 @@ query validation {
109
93
  zip: "90210"
110
94
  }
111
95
  locale: "en"
112
- matchingStrategy: LOCAL
113
96
  ) {
114
97
  validationScope
115
98
  concerns {
@@ -410,6 +393,20 @@ and the US data is in mysql the rest of the process for creating the elasticsear
410
393
 
411
394
  ## Elasticsearch Matching Strategy
412
395
 
396
+ An optional GraphQL parameter, and the strategy used to evaluate the validity of the address input. Out of the box, Atlas Engine
397
+ supports three different matching strategies: `local`, `es`, and `es_street`.
398
+ - `local` matching uses the [worldwide](https://github.com/Shopify/worldwide) gem to provide the most basic level of
399
+ address validation. This may include simple errors (required fields not populated) or more advanced errors (province
400
+ not belonging to the country, zip code not belonging to the province). This level of matching does not require
401
+ [ingestion](#ingestion) of country data to work, but the level of support and suggestions it can provide in its
402
+ responses is minimal.
403
+ - `es` matching uses data indexed in elasticsearch via our [ingestion](#ingestion) process to validate the city,
404
+ province, country, and zip code fields of the input address, in addition to all of the basic functionality provided
405
+ in the `local` strategy.
406
+ - `es_street` is our most advanced matching strategy and requires the highest quality data indexed in elasticsearch
407
+ via our [ingestion](#ingestion) process. This matching strategy provides everything that `es` and `local` does along
408
+ with validation of the address1 and address2 components of the address input.
409
+
413
410
  Once we have successfully created and activated an elasticsearch index using open address data, we may now use
414
411
  the more advanced elasticsearch matching strategies `es` and `es_street`.
415
412
 
@@ -47,8 +47,13 @@ enum MatchingStrategy {
47
47
  LOCAL
48
48
  }
49
49
 
50
+ enum MessageFormat {
51
+ INFORMATIVE
52
+ INSTRUCTIONAL
53
+ }
54
+
50
55
  type Query {
51
- validation(address: AddressInput!, locale: String!, matchingStrategy: MatchingStrategy): Validation!
56
+ validation(address: AddressInput!, locale: String!, matchingStrategy: MatchingStrategy, messageFormat: MessageFormat): Validation!
52
57
  }
53
58
 
54
59
  """
@@ -60,8 +65,12 @@ type Suggestion {
60
65
  city: String
61
66
  countryCode: ValidationSupportedCountry
62
67
  id: String!
68
+ line2: String
69
+ neighborhood: String
63
70
  province: String
64
71
  provinceCode: String
72
+ streetName: String
73
+ streetNumber: String
65
74
  zip: String
66
75
  }
67
76
 
@@ -1,10 +1,12 @@
1
- # typed: false
1
+ # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module AtlasEngine
5
5
  module Types
6
6
  module AddressValidation
7
7
  class ConcernType < BaseObject
8
+ extend T::Sig
9
+
8
10
  description "A piece of relevant information regarding the address validation result." \
9
11
  "They can be categorized as either a Warning or Error."
10
12
 
@@ -14,6 +16,11 @@ module AtlasEngine
14
16
  field :type, Enums::ConcernEnum, null: false
15
17
  field :type_level, Int, null: false
16
18
  field :suggestion_ids, [String], null: false
19
+
20
+ sig { returns(T::Array[String]) }
21
+ def field_names
22
+ object.field_names.map { |field_name| field_name.to_s.camelize(:lower) }
23
+ end
17
24
  end
18
25
  end
19
26
  end
@@ -9,7 +9,11 @@ module AtlasEngine
9
9
 
10
10
  field :id, String, null: false
11
11
  field :address1, String, null: true
12
+ field :street_name, String, null: true
13
+ field :street_number, String, null: true
12
14
  field :address2, String, null: true
15
+ field :line2, String, null: true
16
+ field :neighborhood, String, null: true
13
17
  field :city, String, null: true
14
18
  field :zip, String, null: true
15
19
  field :province_code, String, null: true
@@ -0,0 +1,11 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Types
6
+ class MessageFormatType < BaseEnum
7
+ value :INSTRUCTIONAL, value: "instructional"
8
+ value :INFORMATIVE, value: "informative"
9
+ end
10
+ end
11
+ end
@@ -10,9 +10,10 @@ module AtlasEngine
10
10
  argument :address, AddressValidation::AddressInput, required: true
11
11
  argument :locale, String, required: true
12
12
  argument :matching_strategy, MatchingStrategyType, required: false
13
+ argument :message_format, MessageFormatType, required: false
13
14
  end
14
15
 
15
- def validation(address:, locale: "en", matching_strategy: nil)
16
+ def validation(address:, locale: "en", matching_strategy: nil, message_format: nil)
16
17
  raise build_graphql_error(AtlasEngine::AddressValidation::Errors::MISSING_PARAMETER) if address.blank?
17
18
 
18
19
  locale = LocaleFormatHelper.format_locale(locale)
@@ -26,6 +27,7 @@ module AtlasEngine
26
27
  address: address,
27
28
  locale: locale,
28
29
  matching_strategy: matching_strategy,
30
+ message_format: message_format,
29
31
  ),
30
32
  )
31
33
  end
@@ -9,22 +9,27 @@ module AtlasEngine
9
9
 
10
10
  ParsedComponents = T.type_alias { T::Hash[Symbol, String] }
11
11
 
12
- sig { returns(T::Array[ParsedComponents]) }
13
- attr_reader :parsings
14
-
15
12
  sig { params(address_input: AddressValidation::AbstractAddress, locale: T.nilable(String)).void }
16
13
  def initialize(address_input:, locale: nil)
17
- @parsings = T.let(
14
+ @address_input = address_input
15
+ @locale = locale
16
+ end
17
+
18
+ sig { returns(T::Array[ParsedComponents]) }
19
+ def parsings
20
+ @parsings ||= T.let(
18
21
  begin
19
- if address_input.country_code.blank?
22
+ if @address_input.country_code.blank?
20
23
  []
21
- else
22
- parsing_result = AddressParserFactory.create(address: address_input, locale: locale).parse
23
- log_unparsable_address(address_input) if parsing_result.empty?
24
+ elsif @address_input.street_name.nil? && @address_input.street_number.nil?
25
+ parsing_result = AddressParserFactory.create(address: @address_input, locale: @locale).parse
26
+ log_unparsable_address(@address_input) if parsing_result.empty?
24
27
  parsing_result
28
+ else
29
+ [{ street: @address_input.street_name, building_num: @address_input.street_number }]
25
30
  end
26
31
  end,
27
- T::Array[ParsedComponents],
32
+ T.nilable(T::Array[ParsedComponents]),
28
33
  )
29
34
  end
30
35
 
@@ -8,12 +8,13 @@ module AtlasEngine
8
8
  class FullAddress < FullAddressValidatorBase
9
9
  include LogHelper
10
10
 
11
- attr_reader :address, :result
11
+ attr_reader :address, :result, :message_format
12
12
 
13
- sig { params(address: TAddress, result: Result).void }
14
- def initialize(address:, result: Result.new)
13
+ sig { params(address: TAddress, result: Result, message_format: MessageFormat).void }
14
+ def initialize(address:, result: Result.new, message_format: MessageFormat::Instructional)
15
15
  super
16
16
  @matching_strategy = MatchingStrategies::Es
17
+ @message_format = message_format
17
18
  end
18
19
 
19
20
  sig { override.returns(Result) }
@@ -29,16 +30,23 @@ module AtlasEngine
29
30
  sig { returns(AddressValidation::Validators::FullAddress::CandidateResultBase) }
30
31
  def build_candidate_result
31
32
  unless supported_address?(address)
32
- return AddressValidation::Validators::FullAddress::UnsupportedScriptResult.new(address:, result:)
33
+ return AddressValidation::Validators::FullAddress::UnsupportedScriptResult.new(
34
+ address:,
35
+ result:,
36
+ message_format:,
37
+ )
33
38
  end
34
39
 
35
40
  if best_candidate.nil?
36
- AddressValidation::Validators::FullAddress::NoCandidateResult.new(address:, result:)
41
+ AddressValidation::Validators::FullAddress::NoCandidateResult.new(
42
+ address:, result:, message_format:,
43
+ )
37
44
  else
38
45
  AddressValidation::Validators::FullAddress::CandidateResult.new(
39
46
  address_comparison: T.must(best_candidate),
40
47
  matching_strategy: @matching_strategy,
41
48
  result: result,
49
+ message_format:,
42
50
  )
43
51
  end
44
52
  end
@@ -100,6 +108,10 @@ module AtlasEngine
100
108
  :zip,
101
109
  :address1,
102
110
  :address2,
111
+ :street_name,
112
+ :street_number,
113
+ :neighborhood,
114
+ :line2,
103
115
  ])
104
116
  end
105
117
 
@@ -108,6 +120,7 @@ module AtlasEngine
108
120
  result.concerns.flat_map(&:code).intersect?([
109
121
  :address1_contains_too_many_words,
110
122
  :address2_contains_too_many_words,
123
+ :street_name_contains_too_many_words,
111
124
  ])
112
125
  end
113
126
 
@@ -6,8 +6,8 @@ module AtlasEngine
6
6
  module Es
7
7
  module Validators
8
8
  class FullAddressStreet < FullAddress
9
- sig { params(address: TAddress, result: Result).void }
10
- def initialize(address:, result: Result.new)
9
+ sig { params(address: TAddress, message_format: MessageFormat, result: Result).void }
10
+ def initialize(address:, message_format:, result: Result.new)
11
11
  super
12
12
  @matching_strategy = MatchingStrategies::EsStreet
13
13
  end
@@ -14,10 +14,14 @@ module AtlasEngine
14
14
  sig { returns(AbstractAddress) }
15
15
  attr_reader :address
16
16
 
17
- sig { params(address: AbstractAddress, result: Result).void }
18
- def initialize(address:, result:)
17
+ sig { returns(MessageFormat) }
18
+ attr_reader :message_format
19
+
20
+ sig { params(address: AbstractAddress, result: Result, message_format: MessageFormat).void }
21
+ def initialize(address:, result:, message_format: MessageFormat::Instructional)
19
22
  @address = address
20
23
  @result = result
24
+ @message_format = message_format
21
25
  end
22
26
 
23
27
  sig { abstract.returns(Result) }
@@ -0,0 +1,13 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module AddressValidation
6
+ class MessageFormat < T::Enum
7
+ enums do
8
+ Instructional = new("instructional")
9
+ Informative = new("informative")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,90 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module AddressValidation
6
+ class PredicatePipelineBuilder
7
+ extend T::Sig
8
+
9
+ sig { returns(PredicatePipeline) }
10
+ attr_reader :predicate_pipeline
11
+
12
+ sig { returns(AbstractAddress) }
13
+ attr_reader :address
14
+
15
+ sig { returns(Result) }
16
+ attr_reader :result
17
+
18
+ sig { returns(MessageFormat) }
19
+ attr_reader :message_format
20
+
21
+ sig do
22
+ params(
23
+ matching_strategy_name: String,
24
+ address: AbstractAddress,
25
+ result: Result,
26
+ message_format: MessageFormat,
27
+ ).void
28
+ end
29
+ def initialize(matching_strategy_name:, address:, result:, message_format:)
30
+ @address = address
31
+ @predicate_pipeline = T.let(PredicatePipeline.find(matching_strategy_name), PredicatePipeline)
32
+ @result = result
33
+ @message_format = message_format
34
+ end
35
+
36
+ sig { returns(T::Array[PredicatePipeline::PredicateConfig]) }
37
+ def pipeline
38
+ predicate_pipeline.pipeline.reject do |predicate_config|
39
+ unsupported_fields.include?(predicate_config.field)
40
+ end
41
+ end
42
+
43
+ sig { returns(T.nilable(FullAddressValidatorBase)) }
44
+ def full_address_validator
45
+ predicate_pipeline.full_address_validator&.new(
46
+ address: address,
47
+ result: result,
48
+ message_format: message_format,
49
+ )
50
+ end
51
+
52
+ sig do
53
+ returns(T::Array[Symbol])
54
+ end
55
+ def unsupported_fields
56
+ @unsupported_fields ||= T.let(
57
+ begin
58
+ unsupported_fields = []
59
+ unsupported_fields += address1_format == :extended ? [:address1] : [:street_name, :street_number]
60
+ unsupported_fields += address2_format == :extended ? [:address2] : [:line2, :neighborhood]
61
+ unsupported_fields
62
+ end,
63
+ T.nilable(T::Array[T.untyped]),
64
+ )
65
+ end
66
+
67
+ private
68
+
69
+ sig { returns(Symbol) }
70
+ def address1_format
71
+ T.let(
72
+ [:street_name, :street_number].all? do |field|
73
+ address.send(field).nil?
74
+ end ? :standard : :extended,
75
+ Symbol,
76
+ )
77
+ end
78
+
79
+ sig { returns(Symbol) }
80
+ def address2_format
81
+ T.let(
82
+ [:neighborhood, :line2].all? do |field|
83
+ address.send(field).nil?
84
+ end ? :standard : :extended,
85
+ Symbol,
86
+ )
87
+ end
88
+ end
89
+ end
90
+ end
@@ -7,6 +7,7 @@ module AtlasEngine
7
7
  const :address, AbstractAddress
8
8
  const :locale, String, default: "en"
9
9
  const :matching_strategy, T.nilable(T.any(String, Symbol)), default: nil
10
+ const :message_format, T.nilable(T.any(String, Symbol)), default: nil
10
11
  end
11
12
  end
12
13
  end
@@ -12,9 +12,21 @@ module AtlasEngine
12
12
  sig { returns(T.nilable(String)) }
13
13
  attr_accessor :address1
14
14
 
15
+ sig { returns(T.nilable(String)) }
16
+ attr_accessor :street_name
17
+
18
+ sig { returns(T.nilable(String)) }
19
+ attr_accessor :street_number
20
+
15
21
  sig { returns(T.nilable(String)) }
16
22
  attr_accessor :address2
17
23
 
24
+ sig { returns(T.nilable(String)) }
25
+ attr_accessor :line2
26
+
27
+ sig { returns(T.nilable(String)) }
28
+ attr_accessor :neighborhood
29
+
18
30
  sig { returns(T.nilable(String)) }
19
31
  attr_accessor :city
20
32
 
@@ -30,16 +42,25 @@ module AtlasEngine
30
42
  sig do
31
43
  params(
32
44
  address1: T.nilable(String),
45
+ street_name: T.nilable(String),
46
+ street_number: T.nilable(String),
33
47
  address2: T.nilable(String),
48
+ line2: T.nilable(String),
49
+ neighborhood: T.nilable(String),
34
50
  city: T.nilable(String),
35
51
  zip: T.nilable(String),
36
52
  province_code: T.nilable(String),
37
53
  country_code: T.nilable(String),
38
54
  ).void
39
55
  end
40
- def initialize(address1: nil, address2: nil, city: nil, zip: nil, province_code: nil, country_code: nil)
56
+ def initialize(address1: nil, street_name: nil, street_number: nil, address2: nil, line2: nil, neighborhood: nil,
57
+ city: nil, zip: nil, province_code: nil, country_code: nil)
41
58
  @address1 = address1
59
+ @street_name = street_name
60
+ @street_number = street_number
42
61
  @address2 = address2
62
+ @line2 = line2
63
+ @neighborhood = neighborhood
43
64
  @city = city
44
65
  @zip = zip
45
66
  @province_code = province_code
@@ -55,7 +76,11 @@ module AtlasEngine
55
76
  {
56
77
  id: id,
57
78
  address1: address1,
79
+ street_name: street_name,
80
+ street_number: street_number,
58
81
  address2: address2,
82
+ line2: line2,
83
+ neighborhood: neighborhood,
59
84
  city: city,
60
85
  zip: zip,
61
86
  province_code: province_code,
@@ -28,6 +28,12 @@ module AtlasEngine
28
28
  sig { returns(T.nilable(FullAddressValidatorBase)) }
29
29
  attr_reader :full_address_validator
30
30
 
31
+ sig { returns(T::Array[Symbol]) }
32
+ attr_reader :unsupported_fields
33
+
34
+ sig { returns(MessageFormat) }
35
+ attr_reader :message_format
36
+
31
37
  FIELD_MAP = T.let(
32
38
  {
33
39
  country: "country_code",
@@ -36,6 +42,10 @@ module AtlasEngine
36
42
  city: "city",
37
43
  address1: "address1",
38
44
  address2: "address2",
45
+ street_name: "street_name",
46
+ street_number: "street_number",
47
+ neighborhood: "neighborhood",
48
+ line2: "line2",
39
49
  phone: "phone",
40
50
  },
41
51
  T::Hash[Symbol, String],
@@ -47,13 +57,15 @@ module AtlasEngine
47
57
  matching_strategy: Strategies,
48
58
  locale: String,
49
59
  context: T::Hash[T.untyped, T.untyped],
60
+ message_format: MessageFormat,
50
61
  ).void
51
62
  end
52
63
  def initialize(
53
64
  address:,
54
65
  matching_strategy:,
55
66
  locale: "en",
56
- context: {}
67
+ context: {},
68
+ message_format: MessageFormat::Instructional
57
69
  )
58
70
  @address = T.let(address, AbstractAddress)
59
71
  @address1 = T.let(address.address1, T.nilable(String))
@@ -65,9 +77,9 @@ module AtlasEngine
65
77
  @country_code = T.let(address.country_code, T.nilable(String))
66
78
  @context = T.let(context, T::Hash[T.untyped, T.untyped])
67
79
  @matching_strategy = T.let(matching_strategy, Strategies)
80
+ @message_format = T.let(message_format, MessageFormat)
68
81
 
69
82
  matching_strategy_name = matching_strategy.serialize
70
- @predicate_pipeline = T.let(PredicatePipeline.find(matching_strategy_name), PredicatePipeline)
71
83
 
72
84
  @result = T.let(
73
85
  Result.new(
@@ -78,14 +90,14 @@ module AtlasEngine
78
90
  ),
79
91
  Result,
80
92
  )
93
+ pipeline_builder = PredicatePipelineBuilder.new(matching_strategy_name:, address:, result:, message_format:)
81
94
 
82
- @full_address_validator = T.let(
83
- @predicate_pipeline.full_address_validator&.new(
84
- address: @address,
85
- result: @result,
86
- ),
87
- T.nilable(FullAddressValidatorBase),
95
+ @pipeline = T.let(
96
+ pipeline_builder.pipeline,
97
+ T::Array[AtlasEngine::AddressValidation::PredicatePipeline::PredicateConfig],
88
98
  )
99
+ @unsupported_fields = T.let(pipeline_builder.unsupported_fields, T::Array[Symbol])
100
+ @full_address_validator = T.let(pipeline_builder.full_address_validator, T.nilable(FullAddressValidatorBase))
89
101
  end
90
102
 
91
103
  sig { override.returns(Result) }
@@ -113,15 +125,20 @@ module AtlasEngine
113
125
  pipeline_address = Address.from_address(address: address)
114
126
  local_concerns = {}
115
127
  cache = Validators::Predicates::Cache.new(pipeline_address)
116
- @predicate_pipeline.pipeline.each do |config|
128
+ @pipeline.each do |predicate_config|
117
129
  break if local_concerns[:country].present?
118
130
 
119
- local_concerns[config.field] = [] if local_concerns[config.field].nil?
120
- next if local_concerns[config.field].present?
131
+ local_concerns[predicate_config.field] = [] if local_concerns[predicate_config.field].nil?
132
+ next if local_concerns[predicate_config.field].present?
121
133
 
122
- concern = config.class_name.new(field: config.field, address: pipeline_address, cache: cache).evaluate
134
+ concern = predicate_config.class_name.new(
135
+ field: predicate_config.field,
136
+ address: pipeline_address,
137
+ cache: cache,
138
+ message_format: message_format,
139
+ ).evaluate
123
140
 
124
- local_concerns[config.field] << concern if concern.present?
141
+ local_concerns[predicate_config.field] << concern if concern.present?
125
142
  end
126
143
  local_concerns
127
144
  end
@@ -129,7 +146,7 @@ module AtlasEngine
129
146
  sig { params(local_concerns: T::Hash[Symbol, T::Array[Concern]]).void }
130
147
  def populate_result(local_concerns)
131
148
  local_concerns.keys.each do |field|
132
- if local_concerns[field]&.empty? && [:address2, :phone].exclude?(field)
149
+ if local_concerns[field]&.empty? && [:address2, :phone].concat(unsupported_fields).exclude?(field)
133
150
  result.validation_scope << T.must(FIELD_MAP[field])
134
151
  end
135
152
 
@@ -14,10 +14,11 @@ module AtlasEngine
14
14
  address_comparison: AddressComparison,
15
15
  matching_strategy: AddressValidation::MatchingStrategies,
16
16
  result: Result,
17
+ message_format: MessageFormat,
17
18
  ).void
18
19
  end
19
- def initialize(address_comparison:, matching_strategy:, result:)
20
- super(address: address_comparison.address, result: result)
20
+ def initialize(address_comparison:, matching_strategy:, result:, message_format:)
21
+ super(address: address_comparison.address, result: result, message_format: message_format)
21
22
  @address_comparison = address_comparison
22
23
  @candidate = address_comparison.candidate
23
24
  @matching_strategy = matching_strategy
@@ -56,11 +57,11 @@ module AtlasEngine
56
57
 
57
58
  sig { void }
58
59
  def add_concerns_without_suggestions
59
- concern = InvalidZipConcernBuilder.for(address, [])
60
+ concern = InvalidZipConcernBuilder.for(address, [], message_format)
60
61
  result.concerns << concern if concern
61
62
 
62
63
  if ConcernBuilder.too_many_unmatched_components?(address, unmatched_components.keys)
63
- result.concerns << UnknownAddressConcernBuilder.new(address).build
64
+ result.concerns << UnknownAddressConcernBuilder.new(address, message_format).build
64
65
  end
65
66
  end
66
67
 
@@ -79,6 +80,7 @@ module AtlasEngine
79
80
  matched_components: matched_components_to_validate.keys,
80
81
  address: address,
81
82
  suggestion_ids: [suggestion.id].compact,
83
+ message_format: message_format,
82
84
  ).build
83
85
  result.concerns << concern
84
86
  end
@@ -167,7 +169,9 @@ module AtlasEngine
167
169
 
168
170
  original_street = T.must(unmatched_components_to_validate[:street]).left_sequence.raw_value
169
171
 
170
- if address.address1.to_s.include?(original_street)
172
+ if address.street_name.present?
173
+ :street_name
174
+ elsif address.address1.to_s.include?(original_street)
171
175
  :address1
172
176
  elsif address.address2.to_s.include?(original_street)
173
177
  :address2
@@ -11,10 +11,11 @@ module AtlasEngine
11
11
 
12
12
  abstract!
13
13
 
14
- sig { params(address: AbstractAddress, result: Result).void }
15
- def initialize(address:, result:)
14
+ sig { params(address: AbstractAddress, result: Result, message_format: MessageFormat).void }
15
+ def initialize(address:, result:, message_format: MessageFormat::Instructional)
16
16
  @address = address
17
17
  @result = result
18
+ @message_format = message_format
18
19
  end
19
20
 
20
21
  sig { void }
@@ -22,7 +23,7 @@ module AtlasEngine
22
23
 
23
24
  private
24
25
 
25
- attr_reader :result, :address
26
+ attr_reader :result, :address, :message_format
26
27
 
27
28
  sig { void }
28
29
  def update_result_scope