From cf617dcbc8637f5758949841fa481c67c75cca43 Mon Sep 17 00:00:00 2001 From: Landon Fackrell Date: Wed, 11 Jun 2025 16:08:33 -0600 Subject: [PATCH 1/2] Support Component Analysis --- .../src/us_street_api/candidate.rs | 25 ++ smarty-rust-sdk/src/us_street_api/mod.rs | 237 ++++++++++++++++++ 2 files changed, 262 insertions(+) diff --git a/smarty-rust-sdk/src/us_street_api/candidate.rs b/smarty-rust-sdk/src/us_street_api/candidate.rs index 08dfb03..5f16ac0 100644 --- a/smarty-rust-sdk/src/us_street_api/candidate.rs +++ b/smarty-rust-sdk/src/us_street_api/candidate.rs @@ -83,4 +83,29 @@ pub struct Analysis { pub suitelink_match: bool, pub ews_match: bool, pub enhanced_match: String, + pub components: ComponentAnalysis, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct MatchInfo { + pub status: String, + pub change: Vec, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ComponentAnalysis { + pub primary_number: MatchInfo, + pub street_predirection: MatchInfo, + pub street_name: MatchInfo, + pub street_postdirection: MatchInfo, + pub street_suffix: MatchInfo, + pub secondary_number: MatchInfo, + pub secondary_designator: MatchInfo, + pub extra_secondary_number: MatchInfo, + pub extra_secondary_designator: MatchInfo, + pub city_name: MatchInfo, + pub state_abbreviation: MatchInfo, + pub zipcode: MatchInfo, + pub plus4_code: MatchInfo, + pub urbanization: MatchInfo, } diff --git a/smarty-rust-sdk/src/us_street_api/mod.rs b/smarty-rust-sdk/src/us_street_api/mod.rs index 5c1f3c4..320c1c4 100644 --- a/smarty-rust-sdk/src/us_street_api/mod.rs +++ b/smarty-rust-sdk/src/us_street_api/mod.rs @@ -9,6 +9,8 @@ mod tests { use crate::sdk::options::OptionsBuilder; use crate::us_street_api::client::USStreetAddressClient; use crate::us_street_api::lookup::{Lookup, MatchStrategy}; + use serde_json::json; + use crate::us_street_api::candidate::Candidate; #[test] fn client_test() { @@ -71,4 +73,239 @@ mod tests { ); assert_eq!(batch.records().len(), 4); } + + #[test] + fn full_candidate_test_with_top_level_fields() { + let data = json!({ + "input_id": "1234", + "candidate_index": 0, + "delivery_line_1": "1600 Amphitheatre Pkwy", + "delivery_line_2": "Ste 100", + "last_line": "Mountain View CA 94043-1351", + "delivery_point_barcode": "940431351000", + "components": { + "urbanization": "URB", + "primary_number": "1600", + "street_name": "Amphitheatre", + "street_predirection": "N", + "street_postdirection": "W", + "street_suffix": "Pkwy", + "secondary_number": "100", + "secondary_designator": "Ste", + "extra_secondary_number": "200", + "extra_secondary_designator": "Apt", + "pmb_designator": "PMB", + "pmb_number": "300", + "city_name": "Mountain View", + "default_city_name": "Mountain View", + "state_abbreviation": "CA", + "zipcode": "94043", + "plus4_code": "1351", + "delivery_point": "00", + "delivery_point_check_digit": "1" + }, + "metadata": { + "record_type": "S", + "zip_type": "Standard", + "county_fips": "06085", + "county_name": "Santa Clara", + "carrier_route": "C001", + "congressional_district": "18", + "building_default_indicator": "Y", + "rdi": "Residential", + "elot_sequence": "0056", + "elot_sort": "A", + "latitude": 37.422, + "longitude": -122.084, + "precision": "Zip9", + "time_zone": "Pacific", + "utc_offset": -8.0, + "dst": true, + "ews_match": false + }, + "analysis": { + "dpv_match_code": "Y", + "dpv_footnotes": "AABB", + "dpv_cmra": "N", + "dpv_vacant": "N", + "dpv_no_stat": "N", + "active": "Y", + "ews_match": false, + "footnotes": "N#", + "lacslink_code": "L", + "lacslink_indicator": "Y", + "suitelink_match": true, + "enhanced_match": "Y", + "components": { + "primary_number": { + "status": "confirmed", + "change": ["added"] + }, + "street_predirection": { + "status": "unconfirmed", + "change": ["spelling"] + }, + "street_name": { + "status": "confirmed", + "change": ["replaced"] + }, + "street_postdirection": { + "status": "confirmed", + "change": [] + }, + "street_suffix": { + "status": "confirmed", + "change": ["spelling"] + }, + "secondary_number": { + "status": "unconfirmed", + "change": ["added"] + }, + "secondary_designator": { + "status": "confirmed", + "change": ["replaced"] + }, + "extra_secondary_number": { + "status": "confirmed", + "change": ["spelling"] + }, + "extra_secondary_designator": { + "status": "confirmed", + "change": ["added"] + }, + "city_name": { + "status": "unconfirmed", + "change": ["replaced"] + }, + "state_abbreviation": { + "status": "confirmed", + "change": [] + }, + "zipcode": { + "status": "confirmed", + "change": ["spelling"] + }, + "plus4_code": { + "status": "confirmed", + "change": ["added"] + }, + "urbanization": { + "status": "unconfirmed", + "change": [] + } + } + } + }); + + let candidate: Candidate = serde_json::from_value(data).unwrap(); + + // Top-level + assert_eq!(candidate.input_id, "1234"); + assert_eq!(candidate.candidate_index, 0); + assert_eq!(candidate.delivery_line_1, "1600 Amphitheatre Pkwy"); + assert_eq!(candidate.delivery_line_2, "Ste 100"); + assert_eq!(candidate.last_line, "Mountain View CA 94043-1351"); + assert_eq!(candidate.delivery_point_barcode, "940431351000"); + + // Components + let c = &candidate.components; + assert_eq!(c.urbanization, "URB"); + assert_eq!(c.primary_number, "1600"); + assert_eq!(c.street_name, "Amphitheatre"); + assert_eq!(c.street_predirection, "N"); + assert_eq!(c.street_postdirection, "W"); + assert_eq!(c.street_suffix, "Pkwy"); + assert_eq!(c.secondary_number, "100"); + assert_eq!(c.secondary_designator, "Ste"); + assert_eq!(c.extra_secondary_number, "200"); + assert_eq!(c.extra_secondary_designator, "Apt"); + assert_eq!(c.pmb_designator, "PMB"); + assert_eq!(c.pmb_number, "300"); + assert_eq!(c.city_name, "Mountain View"); + assert_eq!(c.default_city_name, "Mountain View"); + assert_eq!(c.state_abbreviation, "CA"); + assert_eq!(c.zipcode, "94043"); + assert_eq!(c.plus4_code, "1351"); + assert_eq!(c.delivery_point, "00"); + assert_eq!(c.delivery_point_check_digit, "1"); + + // Metadata + let m = &candidate.metadata; + assert_eq!(m.record_type, "S"); + assert_eq!(m.zip_type, "Standard"); + assert_eq!(m.county_fips, "06085"); + assert_eq!(m.county_name, "Santa Clara"); + assert_eq!(m.carrier_route, "C001"); + assert_eq!(m.congressional_district, "18"); + assert_eq!(m.building_default_indicator, "Y"); + assert_eq!(m.rdi, "Residential"); + assert_eq!(m.elot_sequence, "0056"); + assert_eq!(m.elot_sort, "A"); + assert_eq!(m.latitude, 37.422); + assert_eq!(m.longitude, -122.084); + assert_eq!(m.precision, "Zip9"); + assert_eq!(m.time_zone, "Pacific"); + assert_eq!(m.utc_offset, -8.0); + assert!(m.dst); + assert!(!m.ews_match); + + // Analysis + let a = &candidate.analysis; + assert_eq!(a.dpv_match_code, "Y"); + assert_eq!(a.dpv_footnotes, "AABB"); + assert_eq!(a.dpv_cmra, "N"); + assert_eq!(a.dpv_vacant, "N"); + assert_eq!(a.active, "Y"); + assert!(!a.ews_match); + assert_eq!(a.footnotes, "N#"); + assert_eq!(a.lacslink_code, "L"); + assert_eq!(a.lacslink_indicator, "Y"); + assert!(a.suitelink_match); + assert_eq!(a.dpv_no_stat, "N"); + assert_eq!(a.enhanced_match, "Y"); + + // Component Analysis (nested) + let ca = &a.components; + assert_eq!(ca.primary_number.status, "confirmed"); + assert_eq!(ca.primary_number.change, vec!["added"]); + + assert_eq!(ca.street_predirection.status, "unconfirmed"); + assert_eq!(ca.street_predirection.change, vec!["spelling"]); + + assert_eq!(ca.street_name.status, "confirmed"); + assert_eq!(ca.street_name.change, vec!["replaced"]); + + assert_eq!(ca.street_postdirection.status, "confirmed"); + assert!(ca.street_postdirection.change.is_empty()); + + assert_eq!(ca.street_suffix.status, "confirmed"); + assert_eq!(ca.street_suffix.change, vec!["spelling"]); + + assert_eq!(ca.secondary_number.status, "unconfirmed"); + assert_eq!(ca.secondary_number.change, vec!["added"]); + + assert_eq!(ca.secondary_designator.status, "confirmed"); + assert_eq!(ca.secondary_designator.change, vec!["replaced"]); + + assert_eq!(ca.extra_secondary_number.status, "confirmed"); + assert_eq!(ca.extra_secondary_number.change, vec!["spelling"]); + + assert_eq!(ca.extra_secondary_designator.status, "confirmed"); + assert_eq!(ca.extra_secondary_designator.change, vec!["added"]); + + assert_eq!(ca.city_name.status, "unconfirmed"); + assert_eq!(ca.city_name.change, vec!["replaced"]); + + assert_eq!(ca.state_abbreviation.status, "confirmed"); + assert!(ca.state_abbreviation.change.is_empty()); + + assert_eq!(ca.zipcode.status, "confirmed"); + assert_eq!(ca.zipcode.change, vec!["spelling"]); + + assert_eq!(ca.plus4_code.status, "confirmed"); + assert_eq!(ca.plus4_code.change, vec!["added"]); + + assert_eq!(ca.urbanization.status, "unconfirmed"); + assert!(ca.urbanization.change.is_empty()); + } } From 04346027a1db79f90297a7858d85af713af1e820 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 23 Oct 2025 15:30:38 -0600 Subject: [PATCH 2/2] Updating component analysis and adding example. --- Makefile | 2 +- .../examples/us_street_component_analysis.rs | 47 +++++++++++++++++++ .../src/us_street_api/candidate.rs | 2 + 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 smarty-rust-sdk/examples/us_street_component_analysis.rs diff --git a/Makefile b/Makefile index c6b64cf..c60a7c3 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ us_reverse_geo_api: RUST_LOG=trace cargo run --example us_reverse_geo_api us_street_api: - RUST_LOG=trace cargo run --example us_street_api + RUST_LOG=trace cargo run --example us_street_api && RUST_LOG=trace cargo run --example us_street_component_analysis us_zipcode_api: RUST_LOG=trace cargo run --example us_zipcode_api diff --git a/smarty-rust-sdk/examples/us_street_component_analysis.rs b/smarty-rust-sdk/examples/us_street_component_analysis.rs new file mode 100644 index 0000000..d129f8d --- /dev/null +++ b/smarty-rust-sdk/examples/us_street_component_analysis.rs @@ -0,0 +1,47 @@ +extern crate serde_json; +extern crate smarty_rust_sdk; +extern crate tokio; + +use smarty_rust_sdk::us_street_api::lookup::{Lookup, MatchStrategy}; + +use smarty_rust_sdk::sdk::authentication::SecretKeyCredential; +use smarty_rust_sdk::sdk::batch::Batch; +use smarty_rust_sdk::sdk::options::OptionsBuilder; +use smarty_rust_sdk::us_street_api::client::USStreetAddressClient; +use std::error::Error; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let lookup = Lookup { + street: "1600 Amphitheatre Pkwy".to_string(), + last_line: "Mountain View, CA".to_string(), + max_candidates: 10, + match_strategy: MatchStrategy::Enhanced, // Enhanced matching is required to return component analysis results. + ..Default::default() + }; + + let mut batch = Batch::default(); + batch.push(lookup)?; + + let authentication = SecretKeyCredential::new( + std::env::var("SMARTY_AUTH_ID").expect("Missing SMARTY_AUTH_ID env variable"), + std::env::var("SMARTY_AUTH_TOKEN").expect("Missing SMARTY_AUTH_TOKEN env variable"), + ); + + let options = OptionsBuilder::new(Some(authentication)) + .with_component_analysis() // To add component analysis feature you need to specify when you create the options for the client. + .build(); + + let client = USStreetAddressClient::new(options)?; + + client.send(&mut batch).await?; + + // Here is an example of how to access component analysis + for record in batch.records() { + if !record.results.is_empty() { + println!("Component Analysis Results:\n {}",serde_json::to_string_pretty(&record.results[0].analysis.components)?); + } + } + + Ok(()) +} diff --git a/smarty-rust-sdk/src/us_street_api/candidate.rs b/smarty-rust-sdk/src/us_street_api/candidate.rs index 5f16ac0..6227daa 100644 --- a/smarty-rust-sdk/src/us_street_api/candidate.rs +++ b/smarty-rust-sdk/src/us_street_api/candidate.rs @@ -87,12 +87,14 @@ pub struct Analysis { } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(default)] pub struct MatchInfo { pub status: String, pub change: Vec, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(default)] pub struct ComponentAnalysis { pub primary_number: MatchInfo, pub street_predirection: MatchInfo,