diff options
author | Galen Guyer <galen@galenguyer.com> | 2022-11-09 16:40:20 -0500 |
---|---|---|
committer | Galen Guyer <galen@galenguyer.com> | 2022-11-09 16:41:15 -0500 |
commit | 6d4f09d9f70565aae233414595bd735eb76ed226 (patch) | |
tree | 94578a9541c6f93df6d4135856d755c2b0723cd1 | |
parent | 2d369519777ea969262dd5b22a8042415ecfe0a8 (diff) |
Seperate out types and FCC date
-rw-r--r-- | src/fcc_date.rs | 43 | ||||
-rw-r--r-- | src/main.rs | 247 | ||||
-rw-r--r-- | src/types.rs | 198 |
3 files changed, 245 insertions, 243 deletions
diff --git a/src/fcc_date.rs b/src/fcc_date.rs new file mode 100644 index 0000000..df738d5 --- /dev/null +++ b/src/fcc_date.rs @@ -0,0 +1,43 @@ +use chrono::NaiveDate; +use serde::{self, Deserialize, Deserializer, Serializer}; + +const FCC_FORMAT: &str = "%m/%d/%Y"; +const SQL_FORMAT: &str = "%Y-%m-%d"; + +// The signature of a serialize_with function must follow the pattern: +// +// fn serialize<S>(&T, S) -> Result<S::Ok, S::Error> +// where +// S: Serializer +// +// although it may also be generic over the input types T. +pub fn serialize<S>(date: &Option<NaiveDate>, serializer: S) -> Result<S::Ok, S::Error> +where + S: Serializer, +{ + let s = match date { + Some(date) => date.format(SQL_FORMAT).to_string(), + None => "".to_string(), + }; + serializer.serialize_str(&s) +} + +// The signature of a deserialize_with function must follow the pattern: +// +// fn deserialize<'de, D>(D) -> Result<T, D::Error> +// where +// D: Deserializer<'de> +// +// although it may also be generic over the output types T. +pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<NaiveDate>, D::Error> +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + if s == "" { + return Ok(None); + } + NaiveDate::parse_from_str(&s, FCC_FORMAT) + .map(|date| Some(date)) + .map_err(serde::de::Error::custom) +} diff --git a/src/main.rs b/src/main.rs index 637333a..4d12aa0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,15 @@ -use chrono::{DateTime, NaiveDate}; +use chrono::DateTime; use filetime::{self, FileTime}; use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; use regex::Regex; -use serde::Deserialize; use sqlx::sqlite::SqlitePool; use sqlx::{Pool, Sqlite}; use std::fs::{self, File}; use std::io::BufRead; use std::io::{Read, Write}; +mod fcc_date; +mod types; +use crate::types::*; const WEEKLY_DUMP_URL: &str = "https://data.fcc.gov/download/pub/uls/complete/l_amat.zip"; const INSERT_AMATEUR_SQL: &str = r"INSERT INTO amateurs (record_type, unique_system_identifier, uls_file_number, ebf_number, call_sign, operator_class, group_code, region_code, trustee_call_sign, trustee_indicator, physician_certification, ve_signature, systematic_call_sign_change, vanity_call_sign_change, vainty_relationship, previous_call_sign, previous_operator_class, trustee_name) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; @@ -19,247 +21,6 @@ const INSERT_LICENSE_ATTACHMENT_SQL: &str = r"INSERT INTO license_attachments (r const INSERT_SPECIAL_CONDITION_SQL: &str = r"INSERT INTO special_conditions (record_type, unique_system_identifier, uls_file_number, ebf_number, call_sign, special_conditions_type, special_conditions_code, status_code, status_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; const INSERT_SPECIAL_CONDITION_FREE_FORM_SQL: &str = r"INSERT INTO special_conditions_free_form (record_type, unique_system_identifier, uls_file_number, ebf_number, call_sign, license_free_form_type, unique_license_free_form_identifier, sequence_number, license_free_form_condition, status_code, status_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; -#[allow(dead_code)] -mod fcc_date { - use chrono::NaiveDate; - use serde::{self, Deserialize, Deserializer, Serializer}; - - const FCC_FORMAT: &str = "%m/%d/%Y"; - const SQL_FORMAT: &str = "%Y-%m-%d"; - - // The signature of a serialize_with function must follow the pattern: - // - // fn serialize<S>(&T, S) -> Result<S::Ok, S::Error> - // where - // S: Serializer - // - // although it may also be generic over the input types T. - pub fn serialize<S>(date: &Option<NaiveDate>, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - let s = match date { - Some(date) => date.format(SQL_FORMAT).to_string(), - None => "".to_string(), - }; - serializer.serialize_str(&s) - } - - // The signature of a deserialize_with function must follow the pattern: - // - // fn deserialize<'de, D>(D) -> Result<T, D::Error> - // where - // D: Deserializer<'de> - // - // although it may also be generic over the output types T. - pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<NaiveDate>, D::Error> - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - if s == "" { - return Ok(None); - } - NaiveDate::parse_from_str(&s, FCC_FORMAT) - .map(|date| Some(date)) - .map_err(serde::de::Error::custom) - } -} - -#[allow(dead_code, non_snake_case)] -#[derive(Debug, Deserialize)] -struct Amateur<'a> { - pub RecordType: &'a str, - pub UniqueSystemIdentifier: u32, - pub UlsFileNumber: &'a str, - pub EBFNumber: &'a str, - pub CallSign: &'a str, - pub OperatorClass: &'a str, - pub GroupCode: &'a str, - pub RegionCode: &'a str, - pub TrusteeCallSign: &'a str, - pub TrusteeIndicator: &'a str, - pub PhysicianCertification: &'a str, - pub VESignature: &'a str, - pub SystematicCallSignChange: &'a str, - pub VanityCallSignChange: &'a str, - pub VanityRelationship: &'a str, - pub PreviousCallSign: &'a str, - pub PreviousOperatorClass: &'a str, - pub TrusteeName: &'a str, -} -#[allow(dead_code, non_snake_case)] -#[derive(Debug, Deserialize)] -struct Comment<'a> { - pub RecordType: &'a str, - pub UniqueSystemIdentifier: &'a str, - pub UlsFileNumber: &'a str, - pub CallSign: &'a str, - #[serde(with = "fcc_date")] - pub CommentDate: Option<NaiveDate>, - pub Description: &'a str, - pub StatusCode: &'a str, - #[serde(with = "fcc_date")] - pub StatusDate: Option<NaiveDate>, -} -#[allow(dead_code, non_snake_case)] -#[derive(Deserialize, Debug)] -struct Entity<'a> { - pub RecordType: &'a str, - pub UniqueSystemIdentifier: u32, - pub UlsFileNumber: &'a str, - pub EBFNumber: &'a str, - pub CallSign: &'a str, - pub EntityType: &'a str, - pub LicenseeId: &'a str, - pub EntityName: &'a str, - pub FirstName: &'a str, - pub MiddleInitial: &'a str, - pub LastName: &'a str, - pub Suffix: &'a str, - pub Phone: &'a str, - pub Fax: &'a str, - pub Email: &'a str, - pub StreetAddress: &'a str, - pub City: &'a str, - pub State: &'a str, - pub ZipCode: &'a str, - pub POBox: &'a str, - pub AttentionLine: &'a str, - pub SGIN: &'a str, - pub FRN: &'a str, - pub ApplicantTypeCode: &'a str, - pub ApplicantTypeCodeOther: &'a str, - pub StatusCode: &'a str, - #[serde(with = "fcc_date")] - pub StatusDate: Option<NaiveDate>, - pub ThreePointSevenGhzLicenseType: &'a str, - pub LinkedUniqueSystemIdentifier: &'a str, - pub LinkedCallsign: &'a str, -} - -#[allow(dead_code, non_snake_case)] -#[derive(Deserialize, Debug)] -struct Header<'a> { - pub RecordType: &'a str, - pub UniqueSystemIdentifier: u32, - pub UlsFileNumber: &'a str, - pub EBFNumber: &'a str, - pub CallSign: &'a str, - pub LicenseStatus: &'a str, - pub RadioServiceCode: &'a str, - #[serde(with = "fcc_date")] - pub GrantDate: Option<NaiveDate>, - #[serde(with = "fcc_date")] - pub ExpiredDate: Option<NaiveDate>, - #[serde(with = "fcc_date")] - pub CancellationDate: Option<NaiveDate>, - pub EligibilityRuleNumber: &'a str, - pub Reserved: &'a str, - pub Alien: &'a str, - pub AlienGovernment: &'a str, - pub AlienCorporation: &'a str, - pub AlienOfficers: &'a str, - pub AlienControl: &'a str, - pub Revoked: &'a str, - pub Convicted: &'a str, - pub Adjudged: &'a str, - pub Reserved2: &'a str, - pub CommonCarrier: &'a str, - pub NonCommonCarrier: &'a str, - pub PrivateComm: &'a str, - pub Fixed: &'a str, - pub Mobile: &'a str, - pub Radiolocation: &'a str, - pub Sattelite: &'a str, - pub DevelopmentalOrSta: &'a str, - pub InterconnectedService: &'a str, - pub CertifierFirstName: &'a str, - pub CertifierMiddleInitial: &'a str, - pub CertifierLastName: &'a str, - pub CertifierSuffix: &'a str, - pub CertifierTitle: &'a str, - pub Female: &'a str, - pub BlackOrAfricanAmerican: &'a str, - pub NativeAmerican: &'a str, - pub Hawaiian: &'a str, - pub Asian: &'a str, - pub White: &'a str, - pub Hispanic: &'a str, - #[serde(with = "fcc_date")] - pub EffectiveDate: Option<NaiveDate>, - #[serde(with = "fcc_date")] - pub LastActionDate: Option<NaiveDate>, - pub AuctionId: Option<i32>, - pub BroadcastServicesRegulatoryStatus: &'a str, - pub BandManagerRegulatoryStatus: &'a str, - pub BroadcastServicesTypeOfRadioService: &'a str, - pub AlienRuling: &'a str, - pub LicenseeNameChange: &'a str, - pub WhitespaceIndicator: &'a str, - pub OperationRequirementChoice: &'a str, - pub OperationRequirementAnswer: &'a str, - pub DiscontinuationOfService: &'a str, - pub RegulatoryCompliance: &'a str, - pub EligibilityCertification900Mhz: &'a str, - pub TransitionPlanCertification900Mhz: &'a str, - pub ReturnSpectrumCertification900Mhz: &'a str, - pub PaymentCertification900Mhz: &'a str, -} -#[allow(dead_code, non_snake_case)] -#[derive(Deserialize, Debug)] -struct History<'a> { - pub RecordType: &'a str, - pub UniqueSystemIdentifier: &'a str, - pub UlsFileNumber: &'a str, - pub CallSign: &'a str, - #[serde(with = "fcc_date")] - pub LogDate: Option<NaiveDate>, - pub Code: &'a str, -} -#[allow(dead_code, non_snake_case)] -#[derive(Deserialize, Debug)] -struct LicenseAttachment<'a> { - pub RecordType: &'a str, - pub UniqueSystemIdentifier: u32, - pub CallSign: &'a str, - pub AttachmentCode: &'a str, - pub AttachmentDescription: &'a str, - #[serde(with = "fcc_date")] - pub AttachmentDate: Option<NaiveDate>, - pub AttachmentFileName: &'a str, - pub ActionPerformed: &'a str, -} -#[allow(dead_code, non_snake_case)] -#[derive(Deserialize, Debug)] -struct SpecialCondition<'a> { - pub RecordType: &'a str, - pub UniqueSystemIdentifier: u32, - pub UlsFileNumber: &'a str, - pub EBFNumber: &'a str, - pub CallSign: &'a str, - pub SpecialConditionType: &'a str, - pub SpecialConditionCode: Option<i32>, - pub StatusCode: &'a str, - #[serde(with = "fcc_date")] - pub StatusDate: Option<NaiveDate>, -} -#[allow(dead_code, non_snake_case)] -#[derive(Deserialize, Debug)] -struct SpecialConditionFreeForm<'a> { - pub RecordType: &'a str, - pub UniqueSystemIdentifier: u32, - pub UlsFileNumber: &'a str, - pub EBFNumber: &'a str, - pub CallSign: &'a str, - pub LicenseFreeFormType: &'a str, - pub UniqueLicenseFreeFormIdentifier: &'a str, - pub SequenceNumber: Option<i32>, - pub LicenseFreeFormCondition: &'a str, - pub StatusCode: &'a str, - #[serde(with = "fcc_date")] - pub StatusDate: Option<NaiveDate>, -} fn download_file() -> Result<File, ()> { let resp = ureq::get(WEEKLY_DUMP_URL) .call() diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..9d8fcf3 --- /dev/null +++ b/src/types.rs @@ -0,0 +1,198 @@ +#![allow(dead_code, non_snake_case)] + +use crate::fcc_date; +use chrono::NaiveDate; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Amateur<'a> { + pub RecordType: &'a str, + pub UniqueSystemIdentifier: u32, + pub UlsFileNumber: &'a str, + pub EBFNumber: &'a str, + pub CallSign: &'a str, + pub OperatorClass: &'a str, + pub GroupCode: &'a str, + pub RegionCode: &'a str, + pub TrusteeCallSign: &'a str, + pub TrusteeIndicator: &'a str, + pub PhysicianCertification: &'a str, + pub VESignature: &'a str, + pub SystematicCallSignChange: &'a str, + pub VanityCallSignChange: &'a str, + pub VanityRelationship: &'a str, + pub PreviousCallSign: &'a str, + pub PreviousOperatorClass: &'a str, + pub TrusteeName: &'a str, +} + +#[derive(Debug, Deserialize)] +pub struct Comment<'a> { + pub RecordType: &'a str, + pub UniqueSystemIdentifier: &'a str, + pub UlsFileNumber: &'a str, + pub CallSign: &'a str, + #[serde(with = "fcc_date")] + pub CommentDate: Option<NaiveDate>, + pub Description: &'a str, + pub StatusCode: &'a str, + #[serde(with = "fcc_date")] + pub StatusDate: Option<NaiveDate>, +} + +#[derive(Deserialize, Debug)] +pub struct Entity<'a> { + pub RecordType: &'a str, + pub UniqueSystemIdentifier: u32, + pub UlsFileNumber: &'a str, + pub EBFNumber: &'a str, + pub CallSign: &'a str, + pub EntityType: &'a str, + pub LicenseeId: &'a str, + pub EntityName: &'a str, + pub FirstName: &'a str, + pub MiddleInitial: &'a str, + pub LastName: &'a str, + pub Suffix: &'a str, + pub Phone: &'a str, + pub Fax: &'a str, + pub Email: &'a str, + pub StreetAddress: &'a str, + pub City: &'a str, + pub State: &'a str, + pub ZipCode: &'a str, + pub POBox: &'a str, + pub AttentionLine: &'a str, + pub SGIN: &'a str, + pub FRN: &'a str, + pub ApplicantTypeCode: &'a str, + pub ApplicantTypeCodeOther: &'a str, + pub StatusCode: &'a str, + #[serde(with = "fcc_date")] + pub StatusDate: Option<NaiveDate>, + pub ThreePointSevenGhzLicenseType: &'a str, + pub LinkedUniqueSystemIdentifier: &'a str, + pub LinkedCallsign: &'a str, +} + +#[derive(Deserialize, Debug)] +pub struct Header<'a> { + pub RecordType: &'a str, + pub UniqueSystemIdentifier: u32, + pub UlsFileNumber: &'a str, + pub EBFNumber: &'a str, + pub CallSign: &'a str, + pub LicenseStatus: &'a str, + pub RadioServiceCode: &'a str, + #[serde(with = "fcc_date")] + pub GrantDate: Option<NaiveDate>, + #[serde(with = "fcc_date")] + pub ExpiredDate: Option<NaiveDate>, + #[serde(with = "fcc_date")] + pub CancellationDate: Option<NaiveDate>, + pub EligibilityRuleNumber: &'a str, + pub Reserved: &'a str, + pub Alien: &'a str, + pub AlienGovernment: &'a str, + pub AlienCorporation: &'a str, + pub AlienOfficers: &'a str, + pub AlienControl: &'a str, + pub Revoked: &'a str, + pub Convicted: &'a str, + pub Adjudged: &'a str, + pub Reserved2: &'a str, + pub CommonCarrier: &'a str, + pub NonCommonCarrier: &'a str, + pub PrivateComm: &'a str, + pub Fixed: &'a str, + pub Mobile: &'a str, + pub Radiolocation: &'a str, + pub Sattelite: &'a str, + pub DevelopmentalOrSta: &'a str, + pub InterconnectedService: &'a str, + pub CertifierFirstName: &'a str, + pub CertifierMiddleInitial: &'a str, + pub CertifierLastName: &'a str, + pub CertifierSuffix: &'a str, + pub CertifierTitle: &'a str, + pub Female: &'a str, + pub BlackOrAfricanAmerican: &'a str, + pub NativeAmerican: &'a str, + pub Hawaiian: &'a str, + pub Asian: &'a str, + pub White: &'a str, + pub Hispanic: &'a str, + #[serde(with = "fcc_date")] + pub EffectiveDate: Option<NaiveDate>, + #[serde(with = "fcc_date")] + pub LastActionDate: Option<NaiveDate>, + pub AuctionId: Option<i32>, + pub BroadcastServicesRegulatoryStatus: &'a str, + pub BandManagerRegulatoryStatus: &'a str, + pub BroadcastServicesTypeOfRadioService: &'a str, + pub AlienRuling: &'a str, + pub LicenseeNameChange: &'a str, + pub WhitespaceIndicator: &'a str, + pub OperationRequirementChoice: &'a str, + pub OperationRequirementAnswer: &'a str, + pub DiscontinuationOfService: &'a str, + pub RegulatoryCompliance: &'a str, + pub EligibilityCertification900Mhz: &'a str, + pub TransitionPlanCertification900Mhz: &'a str, + pub ReturnSpectrumCertification900Mhz: &'a str, + pub PaymentCertification900Mhz: &'a str, +} + +#[derive(Deserialize, Debug)] +pub struct History<'a> { + pub RecordType: &'a str, + pub UniqueSystemIdentifier: &'a str, + pub UlsFileNumber: &'a str, + pub CallSign: &'a str, + #[serde(with = "fcc_date")] + pub LogDate: Option<NaiveDate>, + pub Code: &'a str, +} + +#[derive(Deserialize, Debug)] +pub struct LicenseAttachment<'a> { + pub RecordType: &'a str, + pub UniqueSystemIdentifier: u32, + pub CallSign: &'a str, + pub AttachmentCode: &'a str, + pub AttachmentDescription: &'a str, + #[serde(with = "fcc_date")] + pub AttachmentDate: Option<NaiveDate>, + pub AttachmentFileName: &'a str, + pub ActionPerformed: &'a str, +} +#[allow(dead_code, non_snake_case)] +#[derive(Deserialize, Debug)] +pub struct SpecialCondition<'a> { + pub RecordType: &'a str, + pub UniqueSystemIdentifier: u32, + pub UlsFileNumber: &'a str, + pub EBFNumber: &'a str, + pub CallSign: &'a str, + pub SpecialConditionType: &'a str, + pub SpecialConditionCode: Option<i32>, + pub StatusCode: &'a str, + #[serde(with = "fcc_date")] + pub StatusDate: Option<NaiveDate>, +} + +#[derive(Deserialize, Debug)] +pub struct SpecialConditionFreeForm<'a> { + pub RecordType: &'a str, + pub UniqueSystemIdentifier: u32, + pub UlsFileNumber: &'a str, + pub EBFNumber: &'a str, + pub CallSign: &'a str, + pub LicenseFreeFormType: &'a str, + pub UniqueLicenseFreeFormIdentifier: &'a str, + pub SequenceNumber: Option<i32>, + pub LicenseFreeFormCondition: &'a str, + pub StatusCode: &'a str, + #[serde(with = "fcc_date")] + pub StatusDate: Option<NaiveDate>, +} |