atlas_engine 1.1.0 → 1.2.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.
- checksums.yaml +4 -4
- data/README.md +14 -17
- data/app/graphql/atlas_engine/schema.graphql +10 -1
- data/app/graphql/atlas_engine/types/address_validation/concern_type.rb +8 -1
- data/app/graphql/atlas_engine/types/address_validation/suggestion_type.rb +4 -0
- data/app/graphql/atlas_engine/types/message_format_type.rb +11 -0
- data/app/graphql/atlas_engine/types/query_type.rb +3 -1
- data/app/lib/atlas_engine/validation_transcriber/address_parsings.rb +14 -9
- data/app/models/atlas_engine/address_validation/es/validators/full_address.rb +18 -5
- data/app/models/atlas_engine/address_validation/es/validators/full_address_street.rb +2 -2
- data/app/models/atlas_engine/address_validation/full_address_validator_base.rb +6 -2
- data/app/models/atlas_engine/address_validation/message_format.rb +13 -0
- data/app/models/atlas_engine/address_validation/predicate_pipeline_builder.rb +90 -0
- data/app/models/atlas_engine/address_validation/request.rb +1 -0
- data/app/models/atlas_engine/address_validation/suggestion.rb +26 -1
- data/app/models/atlas_engine/address_validation/validator.rb +31 -14
- data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result.rb +9 -5
- data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result_base.rb +4 -3
- data/app/models/atlas_engine/address_validation/validators/full_address/concern_builder.rb +19 -4
- data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_concern_builder.rb +4 -3
- data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_country_concern_builder.rb +6 -4
- data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_province_concern_builder.rb +4 -2
- data/app/models/atlas_engine/address_validation/validators/full_address/no_candidate_result.rb +1 -1
- data/app/models/atlas_engine/address_validation/validators/full_address/suggestion_builder.rb +5 -2
- data/app/models/atlas_engine/address_validation/validators/full_address/unknown_address_concern_builder.rb +16 -4
- data/app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern_builder.rb +8 -3
- data/app/models/atlas_engine/address_validation/validators/full_address/unmatched_field_concern_builder.rb +13 -3
- data/app/models/atlas_engine/address_validation/validators/full_address/unsupported_script_result.rb +1 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/city/present.rb +1 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/country/exists.rb +5 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/country/valid_for_zip.rb +1 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/neighborhood/present.rb +35 -0
- data/app/models/atlas_engine/address_validation/validators/predicates/not_exceed_max_length.rb +18 -3
- data/app/models/atlas_engine/address_validation/validators/predicates/phone/valid.rb +3 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/predicate.rb +6 -2
- data/app/models/atlas_engine/address_validation/validators/predicates/province/exists.rb +3 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/province/valid_for_country.rb +3 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/street/present.rb +3 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/street_name/present.rb +35 -0
- data/app/models/atlas_engine/address_validation/validators/predicates/street_number/present.rb +35 -0
- data/app/models/atlas_engine/address_validation/validators/predicates/zip/present.rb +2 -2
- data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_country.rb +1 -1
- data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_province.rb +1 -1
- data/app/models/atlas_engine/services/validation.rb +4 -0
- data/db/data/validation_pipelines/es.yml +46 -0
- data/db/data/validation_pipelines/es_street.yml +46 -0
- data/db/data/validation_pipelines/local.yml +46 -0
- data/lib/atlas_engine/version.rb +1 -1
- metadata +39 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ac0ad464ab86fe1db96b5ca3f5a69254d6ad52571d8c83350645c9e031ea58b
|
4
|
+
data.tar.gz: f683950cfa6d89c1cdf4935d8a49d76e416c57220ac29e5aa62adcdaf2a628d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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:
|
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
|
@@ -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
|
-
@
|
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
|
-
|
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(
|
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(
|
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 {
|
18
|
-
|
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,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
|
@@ -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,
|
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
|
-
@
|
83
|
-
|
84
|
-
|
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
|
-
@
|
128
|
+
@pipeline.each do |predicate_config|
|
117
129
|
break if local_concerns[:country].present?
|
118
130
|
|
119
|
-
local_concerns[
|
120
|
-
next if local_concerns[
|
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 =
|
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[
|
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.
|
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
|
data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result_base.rb
CHANGED
@@ -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
|