autofill/db/models/
address.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2* License, v. 2.0. If a copy of the MPL was not distributed with this
3* file, You can obtain one at http://mozilla.org/MPL/2.0/.
4*/
5
6use super::Metadata;
7use rusqlite::Row;
8use sync_guid::Guid;
9use types::Timestamp;
10
11// UpdatableAddressFields contains the fields we support for creating a new
12// address or updating an existing one. It's missing the guid, our "internal"
13// meta fields (such as the change counter) and "external" meta fields
14// (such as timeCreated) because it doesn't make sense for these things to be
15// specified as an item is created - any meta fields which can be updated
16// have special methods for doing so.
17#[derive(Debug, Clone, Default)]
18pub struct UpdatableAddressFields {
19    pub name: String,
20    pub organization: String,
21    pub street_address: String,
22    pub address_level3: String,
23    pub address_level2: String,
24    pub address_level1: String,
25    pub postal_code: String,
26    pub country: String,
27    pub tel: String,
28    pub email: String,
29}
30
31/// Metadata fields managed internally by the library: the guid, timestamps and
32/// local sync state. These are automatically set on `add_address` and updated on
33/// operations like `touch` and `update_address`. Not included in
34/// `UpdatableAddressFields`; use `add_address_with_meta` when importing records
35/// that already have metadata.
36#[derive(Debug, Clone, Default)]
37pub struct AddressMeta {
38    pub guid: String,
39    pub time_created: i64,
40    pub time_last_used: Option<i64>,
41    pub time_last_modified: i64,
42    pub times_used: i64,
43    /// Local changes not yet uploaded; 0 means it matches what was last synced.
44    pub sync_change_counter: i64,
45}
46
47/// A tombstone for a record deleted locally but not yet uploaded, supplied to
48/// `add_many_address_tombstones` when migrating from another store.
49#[derive(Debug, Clone, Default)]
50pub struct AddressTombstone {
51    pub guid: String,
52    pub time_deleted: i64,
53}
54
55/// Per-record result of `add_many_address_tombstones`.
56#[derive(Debug)]
57pub enum AddressBulkTombstoneResultEntry {
58    Success { guid: String },
59    Error { message: String },
60}
61
62/// An address together with its metadata, passed to `add_address_with_meta` and
63/// `update_address_with_meta` when importing a record from another store.
64#[derive(Debug, Clone, Default)]
65pub struct UpdatableAddressFieldsWithMeta {
66    pub fields: UpdatableAddressFields,
67    pub meta: AddressMeta,
68}
69
70/// A bulk insert result entry, returned per input record by
71/// `add_many_addresses_with_meta` so that one record failing does not abort the
72/// batch. Note that although the success case is much larger than the error
73/// case, this is negligible in real life, as we expect a very small
74/// success/error ratio.
75#[allow(clippy::large_enum_variant)]
76#[derive(Debug)]
77pub enum AddressBulkResultEntry {
78    Success { address: Address },
79    Error { message: String },
80}
81
82// "Address" is what we return to consumers and has most of the metadata.
83#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)]
84pub struct Address {
85    pub guid: String,
86    pub name: String,
87    pub organization: String,
88    pub street_address: String,
89    pub address_level3: String,
90    pub address_level2: String,
91    pub address_level1: String,
92    pub postal_code: String,
93    pub country: String,
94    pub tel: String,
95    pub email: String,
96    // We expose some of the metadata
97    pub time_created: i64,
98    pub time_last_used: Option<i64>,
99    pub time_last_modified: i64,
100    pub times_used: i64,
101}
102
103// This is used to "externalize" an address, suitable for handing back to
104// consumers.
105impl From<InternalAddress> for Address {
106    fn from(ia: InternalAddress) -> Self {
107        Address {
108            guid: ia.guid.to_string(),
109            name: ia.name,
110            organization: ia.organization,
111            street_address: ia.street_address,
112            address_level3: ia.address_level3,
113            address_level2: ia.address_level2,
114            address_level1: ia.address_level1,
115            postal_code: ia.postal_code,
116            country: ia.country,
117            tel: ia.tel,
118            email: ia.email,
119            // note we can't use u64 in uniffi
120            time_created: u64::from(ia.metadata.time_created) as i64,
121            time_last_used: if ia.metadata.time_last_used.0 == 0 {
122                None
123            } else {
124                Some(ia.metadata.time_last_used.0 as i64)
125            },
126            time_last_modified: u64::from(ia.metadata.time_last_modified) as i64,
127            times_used: ia.metadata.times_used,
128        }
129    }
130}
131
132// An "internal" address is used by the public APIs and by sync. No `PartialEq`
133// because it's impossible to do it meaningfully for credit-cards and we'd like
134// to keep the API symmetric
135#[derive(Default, Debug, Clone)]
136pub struct InternalAddress {
137    pub guid: Guid,
138    pub name: String,
139    pub organization: String,
140    pub street_address: String,
141    pub address_level3: String,
142    pub address_level2: String,
143    pub address_level1: String,
144    pub postal_code: String,
145    pub country: String,
146    pub tel: String,
147    pub email: String,
148    pub metadata: Metadata,
149}
150
151impl InternalAddress {
152    pub fn from_row(row: &Row<'_>) -> Result<InternalAddress, rusqlite::Error> {
153        Ok(Self {
154            guid: row.get("guid")?,
155            name: row.get("name")?,
156            organization: row.get("organization")?,
157            street_address: row.get("street_address")?,
158            address_level3: row.get("address_level3")?,
159            address_level2: row.get("address_level2")?,
160            address_level1: row.get("address_level1")?,
161            postal_code: row.get("postal_code")?,
162            country: row.get("country")?,
163            tel: row.get("tel")?,
164            email: row.get("email")?,
165            metadata: Metadata {
166                time_created: row.get::<_, Timestamp>("time_created")?.sanitized(),
167                time_last_used: row.get::<_, Timestamp>("time_last_used")?.sanitized(),
168                time_last_modified: row.get::<_, Timestamp>("time_last_modified")?.sanitized(),
169                times_used: row.get("times_used")?,
170                sync_change_counter: row.get("sync_change_counter")?,
171            },
172        })
173    }
174}