scaffolding_core/
lib.rs

1//! Object-oriented programming (OOP) has been around since the 1960s and was first introduced in the late 1950s
2//! in artificial intelligence by an MMIT group. It is no wonder then that over the years, the concept of objects
3//! being represented by classes and attributes with inheritanted behavior.
4//!
5//! Rust addresses this design by providing structures, traits, and implementations. However, the native ability to
6//! `extend` a class (like in other languages) makes OOP a bit of a challenge. To address this gap, `Scaffolding` utilizes
7//! Rust's [procedural macros](https://doc.rust-lang.org/reference/procedural-macros.html) to mimic the ability to  
8//! `extend` a class - both data structure and behavior.
9//!
10//! ## Scaffolding Concept
11//! 1. A class that `extends` the "Scaffolding class" should inherate all the "parent" data structure and behavior,
12//!    as well as append the "child" specific data structure and behavior from the generic type being extended.
13//! 2. The developer should have the flexibility to adopt the default "parent" characteristics or overwrite them as desired.
14//! 3. There are common class attributes that are required in order to manage it using CRUD
15//!  + `id` - The unique identifier of the object.
16//!  + `created_dtm` - The unix epoch (UTC) representation of when the object was created
17//!  + `modified_dtm` - The unix epoch (UTC) representation of when the object was last updated
18//!  + `inactive_dtm` - The unix epoch (UTC) representation of when the object was/will be considered obsolete
19//!  + `expired_dtm` - The unix epoch (UTC) representation of when the object was/will be ready for deletion
20//!  + `activity` - The list of actions performed on the object
21//! 4. There is common class behaviors that are required in order to manage it using CRUD
22//!  + The `id` is not optional. It must be either provided or automatically generated during instantiation.
23//!    This can be done by calling the `Scaffolding` trait's `id()` method
24//!  + The `created_dtm` is not optional. It must be either provided or automatically generated during instantiation.
25//!    This can be done by calling one of the `Scaffolding` trait's many datetime related methods, (e.g.: `now()`)  
26//!  + The `modified_dtm` is not optional. It must be either provided or automatically generated during instantiation or updates to the object.
27//!    This can be done by calling one of the `Scaffolding` trait's many datetime related methods, (e.g.: `now()`)
28//!  + The `inactive_dtm` is not optional. It must be either provided or automatically generated during instantiation or updates to the object.
29//!    This can be done by calling one of the `Scaffolding` trait's many datetime related methods, (e.g.: `add_months()` in conjuctions with `now()`)  
30//!  + The `expire_dtm` is not optional. It must be either provided or automatically generated during instantiation or updates to the object.
31//!    This can be done by calling one of the `Scaffolding` trait's many datetime related methods, (e.g.: `never()`)
32//!  + The `activity` is required and by default is an empty list of activity
33//!
34//! ### Example
35//! Add Scaffolding to a `struct` and `impl` `::new()` using macros and defaults
36//! ```rust
37//! extern crate scaffolding_core;
38//!
39//! use scaffolding_core::*;
40//!
41//! // (1) Define the structure - Required
42//! #[scaffolding_struct]
43//! #[derive(Debug, Clone, Deserialize, Serialize, Scaffolding)]
44//! struct MyEntity {
45//!     a: bool,
46//!     b: String,
47//! }
48//!
49//! impl MyEntity {
50//!     // (2) Define the constructor - Optional
51//!     //     Note: Any of the Scaffodling attributes that are set here
52//!     //           will not be overwritten when generated. For example
53//!     //           the `id` attribute, if uncommented, would be ignored.
54//!     #[scaffolding_fn]
55//!     fn new(arg: bool) -> Self {
56//!         let msg = format!("You said it is {}", arg);
57//!         Self {
58//!             // id: "my unique identitifer".to_string(),
59//!             a: arg,
60//!             b: msg
61//!         }
62//!     }
63//!
64//!     fn my_func(&self) -> String {
65//!         "my function".to_string()
66//!     }
67//! }
68//!
69//! let mut entity = MyEntity::new(true);
70//!
71//! /* scaffolding attributes */
72//! assert_eq!(entity.id.len(), "54324f57-9e6b-4142-b68d-1d4c86572d0a".len());
73//! assert_eq!(entity.created_dtm, defaults::now());
74//! assert_eq!(entity.modified_dtm, defaults::now());
75//! // becomes inactive in 90 days
76//! assert_eq!(entity.inactive_dtm, defaults::add_days(defaults::now(), 90));
77//! // expires in 3 years
78//! assert_eq!(entity.expired_dtm, defaults::add_years(defaults::now(), 3));
79//!
80//! /* serialization */
81//! let json_string = entity.serialize();
82//! println!("{}", json_string);
83//!
84//! /* use the activity log functionality  */
85//! // (1) Log an activity
86//! entity.log_activity("cancelled".to_string(), "The customer has cancelled their service".to_string());
87//! // (2) Get activities
88//! assert_eq!(entity.get_activity("cancelled".to_string()).len(), 1);
89//!
90//! // extended attributes
91//! assert_eq!(entity.a, true);
92//! assert_eq!(entity.b, "You said it is true");
93//!
94//! // extended behavior
95//! assert_eq!(entity.my_func(), "my function");
96//! ```
97#[macro_use]
98extern crate serde_derive;
99extern crate serde_json;
100
101use errors::*;
102use regex::Regex;
103pub use scaffolding_macros::*;
104use serde::de::DeserializeOwned;
105use serde::ser::Serialize;
106pub use serde_derive::{Deserialize, Serialize};
107pub use std::collections::BTreeMap;
108
109use serde_json::Value;
110
111/// Supporting Classes
112#[derive(Clone, Debug, Deserialize, Serialize)]
113pub struct ActivityItem {
114    // The timestamp when the action occurred
115    pub created_dtm: i64,
116    // The textual name of the action that occurred
117    pub action: String,
118    // The textual description of the action that occurred
119    pub description: String,
120}
121
122impl ActivityItem {
123    /// This is the constructor function.
124    ///
125    /// #Example
126    ///
127    /// ```rust
128    /// extern crate scaffolding_core;
129    ///     
130    /// use scaffolding_core::*;
131    ///
132    /// let mut activity_item = ActivityItem::new("updated".to_string(), "This was updated".to_string());
133    /// ```
134    pub fn new(name: String, descr: String) -> Self {
135        Self {
136            created_dtm: defaults::now(),
137            action: name,
138            description: descr,
139        }
140    }
141
142    /// This function instantiates an ActivityItem from a JSON string.
143    ///
144    /// #Example
145    ///
146    /// ```rust     
147    /// extern crate scaffolding_core;
148    ///     
149    /// use scaffolding_core::*;
150    ///
151    /// let serialized = r#"{
152    ///   "created_dtm":1711760135,
153    ///   "action":"updated",
154    ///   "description":"The object has been updated."
155    /// }"#;
156    /// let mut activity_item = ActivityItem::deserialized(&serialized.as_bytes()).unwrap();
157    ///
158    /// assert_eq!(activity_item.created_dtm, 1711760135);
159    /// assert_eq!(activity_item.action, "updated".to_string());
160    /// assert_eq!(activity_item.description, "The object has been updated.".to_string());
161    /// ```
162    pub fn deserialized(serialized: &[u8]) -> Result<ActivityItem, DeserializeError> {
163        match serde_json::from_slice(&serialized) {
164            Ok(item) => Ok(item),
165            Err(err) => {
166                println!("{}", err);
167                Err(DeserializeError)
168            }
169        }
170    }
171
172    /// This function converts the ActivityItem to a serialize JSON string.
173    ///
174    /// #Example
175    ///
176    /// ```rust
177    /// extern crate scaffolding_core;
178    ///     
179    /// use scaffolding_core::*;
180    ///
181    /// let mut activity_item = ActivityItem::new("updated".to_string(), "This was updated".to_string());
182    /// let json = activity_item.serialize();
183    ///
184    /// println!("{}", json);
185    /// ```
186    pub fn serialize(&mut self) -> String {
187        serde_json::to_string(&self).unwrap()
188    }
189}
190
191#[derive(Clone, Debug, Deserialize, Serialize)]
192pub struct Address {
193    // The unique identifier of the note
194    pub id: String,
195    // The timestamp when the note was created
196    pub created_dtm: i64,
197    // The timestamp when the note was last modified
198    pub modified_dtm: i64,
199    // The type of address, (e.g.: Billing, Shipping, Home, Work, etc.)
200    pub category: String,
201    // The first line of the address should contain the location's full name
202    pub line_1: String,
203    // The second line of the address should include the house number and street address/ PO box address
204    pub line_2: String,
205    // The third line of the address should include the city name followed by province, state, or county name and postal code
206    pub line_3: String,
207    // The fourth line of the address including the country
208    pub line_4: String,
209    // The country code of the location (Use Alpha 3 codes)
210    pub country_code: String,
211}
212
213impl Address {
214    /// This is the constructor function.
215    ///
216    /// #Example
217    ///
218    /// ```rust
219    /// extern crate scaffolding_core;
220    ///
221    /// use scaffolding_core::*;
222    ///
223    /// fn main() {
224    ///   let address = Address::new(
225    ///       "shipping".to_string(),
226    ///       "acmes company".to_string(),
227    ///       "14 Main Street".to_string(),
228    ///       "Big City, NY 038845".to_string(),
229    ///       "USA".to_string(),
230    ///       "USA".to_string(),
231    ///   
232    ///   );
233    ///   
234    ///   // scaffolding attributes
235    ///   println!("{}", address.id);
236    ///   println!("{}", address.created_dtm);
237    ///   println!("{}", address.modified_dtm,);
238    /// }
239    /// ```
240    pub fn new(
241        category: String,
242        line_1: String,
243        line_2: String,
244        line_3: String,
245        line_4: String,
246        country_code: String,
247    ) -> Self {
248        Self {
249            id: defaults::id(),
250            created_dtm: defaults::now(),
251            modified_dtm: defaults::now(),
252            category: category,
253            line_1: line_1,
254            line_2: line_2,
255            line_3: line_3,
256            line_4: line_4,
257            country_code: country_code,
258        }
259    }
260
261    /// This function instantiates an Address from a JSON string.
262    ///
263    /// #Example
264    ///
265    /// ```rust     
266    /// use scaffolding_core::*;
267    ///
268    /// let serialized = r#"{
269    ///   "id":"2d624160-16b1-49ce-9b90-09a82127d6ac",
270    ///   "created_dtm":1711833619,
271    ///   "modified_dtm":1711833619,
272    ///   "category":"shipping",
273    ///   "line_1":"acmes company",
274    ///   "line_2":"14 Main Street",
275    ///   "line_3":"Big City, NY 038845",
276    ///   "line_4":"United States",
277    ///   "country_code": "USA"
278    /// }"#;
279    /// let mut address = Address::deserialized(&serialized.as_bytes()).unwrap();
280    ///
281    /// assert_eq!(address.created_dtm, 1711833619);
282    /// assert_eq!(address.modified_dtm, 1711833619);
283    /// assert_eq!(address.category, "shipping".to_string());
284    /// ```
285    pub fn deserialized(serialized: &[u8]) -> Result<Address, DeserializeError> {
286        match serde_json::from_slice(&serialized) {
287            Ok(item) => Ok(item),
288            Err(err) => {
289                println!("{}", err);
290                Err(DeserializeError)
291            }
292        }
293    }
294
295    /// This function converts the Address to a serialize JSON string.
296    ///
297    /// #Example
298    ///
299    /// ```rust     
300    /// use scaffolding_core::*;
301    ///
302    /// let mut address = Address::new(
303    ///   "shipping".to_string(),
304    ///   "acmes company".to_string(),
305    ///   "14 Main Street".to_string(),
306    ///   "Big City, NY 038845".to_string(),
307    ///   "USA".to_string(),
308    ///   "USA".to_string()
309    /// );
310    /// println!("{}", address.serialize());
311    /// ```
312    pub fn serialize(&mut self) -> String {
313        serde_json::to_string(&self).unwrap()
314    }
315
316    /// This function updates the Address.
317    ///
318    /// #Example
319    ///
320    /// ```rust     
321    /// use scaffolding_core::*;
322    ///
323    /// let mut address = Address::new(
324    ///   "shipping".to_string(),
325    ///   "acmes company".to_string(),
326    ///   "14 Main Street".to_string(),
327    ///   "Big City, NY 038845".to_string(),
328    ///   "USA".to_string(),
329    ///   "USA".to_string()
330    /// );
331    ///
332    /// address.update(
333    ///   "billing".to_string(),
334    ///   "acmes company".to_string(),
335    ///   "14 Main Street".to_string(),
336    ///   "Big City, NY 038845".to_string(),
337    ///   "USA".to_string(),
338    ///   "USA".to_string());
339    ///
340    /// assert_eq!(address.category, "billing".to_string());
341    /// ```
342    pub fn update(
343        &mut self,
344        category: String,
345        line_1: String,
346        line_2: String,
347        line_3: String,
348        line_4: String,
349        country_code: String,
350    ) {
351        self.category = category;
352        self.line_1 = line_1;
353        self.line_2 = line_2;
354        self.line_3 = line_3;
355        self.line_4 = line_4;
356        self.country_code = country_code;
357        self.modified_dtm = defaults::now();
358    }
359}
360pub struct Countries {
361    // The list of countries
362    pub list: Vec<Country>,
363}
364
365impl Countries {
366    /// This is the constructor function.
367    ///
368    /// #Example
369    ///
370    /// ```rust
371    /// extern crate scaffolding_core;
372    ///
373    /// use scaffolding_core::*;
374    ///
375    /// fn main() {
376    ///   let countries = Countries::new();
377    /// }
378    /// ```
379    pub fn new() -> Self {
380        let data = include_str!("countries.json");
381        let array: Value = serde_json::from_str(data).unwrap();
382        let countries: Vec<Country> = array
383            .as_array()
384            .unwrap()
385            .iter()
386            .map(|c| {
387                Country::new(
388                    c["country_name"].as_str().unwrap().to_string(),
389                    c["phone_code"].as_str().unwrap().to_string(),
390                    c["iso_2_code"].as_str().unwrap().to_string(),
391                    c["iso_3_code"].as_str().unwrap().to_string(),
392                )
393            })
394            .collect();
395        Self { list: countries }
396    }
397
398    /// Verifies a Country
399    ///
400    /// ### Example
401    /// ```rust
402    /// extern crate scaffolding_core;
403    ///
404    /// use scaffolding_core::*;
405    ///
406    /// fn main() {
407    ///  let countries = Countries::new();
408    ///   let country = Country::new(
409    ///       "United States".to_string(),
410    ///       "1".to_string(),
411    ///       "US".to_string(),
412    ///       "USA".to_string()
413    ///   );
414    ///
415    ///   assert_eq!(countries.is_valid(country), true);
416    /// }
417    /// ```
418    pub fn is_valid(&self, country: Country) -> bool {
419        let found = self.list.iter().filter(|c| {
420            c.name == country.name
421                && c.phone_code == country.phone_code
422                && c.iso_2_code == country.iso_2_code
423                && c.iso_3_code == country.iso_3_code
424        });
425        match found.count() {
426            0 => return false,
427            _ => return true,
428        }
429    }
430
431    /// Retrieves a Country based on the ISO 2 Code
432    ///
433    /// ### Example
434    /// ```rust
435    /// extern crate scaffolding_core;
436    ///
437    /// use scaffolding_core::*;
438    ///
439    /// fn main() {
440    ///  let countries = Countries::new();
441    ///  let country = countries.get_country_by_iso_2_code("US".to_string()).unwrap();
442    ///
443    ///  assert_eq!(country.name, "United States");
444    ///  assert_eq!(country.phone_code, "1");
445    ///  assert_eq!(country.iso_2_code, "US");
446    ///  assert_eq!(country.iso_3_code, "USA");
447    /// }
448    /// ```
449    pub fn get_country_by_iso_2_code(&self, iso_2_code: String) -> Option<&Country> {
450        let found = self.list.iter().filter(|c| c.iso_2_code == iso_2_code);
451
452        return found.last();
453    }
454
455    /// Retrieves a Country based on the ISO 3 Code
456    ///
457    /// ### Example
458    /// ```rust
459    /// extern crate scaffolding_core;
460    ///
461    /// use scaffolding_core::*;
462    ///
463    /// fn main() {
464    ///  let countries = Countries::new();
465    ///  let country = countries.get_country_by_iso_3_code("USA".to_string()).unwrap();
466    ///
467    ///  assert_eq!(country.name, "United States");
468    ///  assert_eq!(country.phone_code, "1");
469    ///  assert_eq!(country.iso_2_code, "US");
470    ///  assert_eq!(country.iso_3_code, "USA");
471    /// }
472    /// ```
473    pub fn get_country_by_iso_3_code(&self, iso_3_code: String) -> Option<&Country> {
474        let found = self.list.iter().filter(|c| c.iso_3_code == iso_3_code);
475
476        return found.last();
477    }
478
479    /// Retrieves a Country based on the international phone code
480    ///
481    /// ### Example
482    /// ```rust
483    /// extern crate scaffolding_core;
484    ///
485    /// use scaffolding_core::*;
486    ///
487    /// fn main() {
488    ///  let countries = Countries::new();
489    ///  let country = countries.get_country_by_phone_code("1".to_string()).unwrap();
490    ///
491    ///  assert_eq!(country.name, "United States");
492    ///  assert_eq!(country.phone_code, "1");
493    ///  assert_eq!(country.iso_2_code, "US");
494    ///  assert_eq!(country.iso_3_code, "USA");
495    /// }
496    /// ```
497    pub fn get_country_by_phone_code(&self, phone_code: String) -> Option<&Country> {
498        let found = self.list.iter().filter(|c| c.phone_code == phone_code);
499
500        return found.last();
501    }
502}
503
504// A country definition
505#[derive(Clone, Debug, Deserialize, Serialize)]
506pub struct Country {
507    // Textual name of the coutnry
508    pub name: String,
509    // The code used for international phone calls
510    pub phone_code: String,
511    // The 2 char abbreviation
512    pub iso_2_code: String,
513    // The 3 char abbreviation
514    pub iso_3_code: String,
515}
516
517impl Country {
518    /// This is the constructor function.
519    ///
520    /// #Example
521    ///
522    /// ```rust
523    /// extern crate scaffolding_core;
524    ///
525    /// use scaffolding_core::Country;
526    ///
527    /// fn main() {
528    ///    let country = Country::new("United States".to_string(), "1".to_string(), "US".to_string(), "USA".to_string());
529    ///
530    ///    assert_eq!(country.name, "United States".to_string());
531    ///    assert_eq!(country.phone_code, "1".to_string());
532    ///    assert_eq!(country.iso_2_code, "US".to_string());
533    ///    assert_eq!(country.iso_3_code, "USA".to_string());
534    /// }
535    /// ```
536    pub fn new(name: String, phone_code: String, iso_2_code: String, iso_3_code: String) -> Self {
537        Self {
538            name: name,
539            phone_code: phone_code,
540            iso_2_code: iso_2_code,
541            iso_3_code: iso_3_code,
542        }
543    }
544}
545
546#[derive(Serialize, Deserialize, Debug, Clone)]
547pub struct EmailAddress {
548    // The unique identifier of the note
549    pub id: String,
550    // The timestamp when the note was created
551    pub created_dtm: i64,
552    // The timestamp when the note was last modified
553    pub modified_dtm: i64,
554    // The type of email address, (e.g.: Login, Personal, Work, Primary Contact, Assistant, etc.)
555    pub category: String,
556    // The email address
557    pub address: String,
558}
559
560impl EmailAddress {
561    /// This is the constructor function.
562    ///
563    /// #Example
564    ///
565    /// ```rust
566    /// extern crate scaffolding_core;
567    ///
568    /// use scaffolding_core::*;
569    ///
570    /// fn main() {
571    ///   let email = EmailAddress::new(
572    ///       "home".to_string(),
573    ///       "myemail@example.com".to_string(),
574    ///   );
575    ///   
576    ///   // scaffolding attributes
577    ///   println!("{}", email.id);
578    ///   println!("{}", email.created_dtm);
579    ///   println!("{}", email.modified_dtm,);
580    /// }
581    /// ```
582    pub fn new(category: String, address: String) -> Self {
583        Self {
584            id: defaults::id(),
585            created_dtm: defaults::now(),
586            modified_dtm: defaults::now(),
587            category: category,
588            address: address,
589        }
590    }
591
592    /// This function instantiates a EmailAddress from a JSON string.
593    ///
594    /// #Example
595    ///
596    /// ```rust     
597    /// extern crate scaffolding_core;
598    ///
599    /// use scaffolding_core::*;
600    ///
601    /// let serialized = r#"{
602    ///   "id":"2d624160-16b1-49ce-9b90-09a82127d6ac",
603    ///   "created_dtm":1711833619,
604    ///   "modified_dtm":1711833619,
605    ///   "category":"home",
606    ///   "address":"myemail@example.com"
607    /// }"#;
608    /// let mut email = EmailAddress::deserialized(&serialized.as_bytes()).unwrap();
609    ///
610    /// assert_eq!(email.created_dtm, 1711833619);
611    /// assert_eq!(email.modified_dtm, 1711833619);
612    /// assert_eq!(email.category, "home".to_string());
613    /// ```
614    pub fn deserialized(serialized: &[u8]) -> Result<EmailAddress, DeserializeError> {
615        match serde_json::from_slice(&serialized) {
616            Ok(item) => Ok(item),
617            Err(err) => {
618                println!("{}", err);
619                Err(DeserializeError)
620            }
621        }
622    }
623
624    /// This function performs a quick check to see if the email address is properly formatted.
625    /// NOTE: This is not a validation that the email address is real.
626    ///
627    /// #Example
628    ///
629    /// ```rust     
630    /// extern crate scaffolding_core;
631    ///
632    /// use scaffolding_core::*;
633    ///
634    /// let email = EmailAddress::new(
635    ///     "home".to_string(),
636    ///     "myemail@example.com".to_string(),
637    /// );
638    ///
639    /// assert_eq!(email.is_valid(), true);
640    /// ```
641
642    pub fn is_valid(&self) -> bool {
643        // use regex::Regex;
644        let exp = r#"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])"#;
645        let re = Regex::new(exp).unwrap();
646        re.is_match(&self.address)
647    }
648    /// This function converts the EmailAddress to a serialize JSON string.
649    ///
650    /// #Example
651    ///
652    /// ```rust     
653    /// extern crate scaffolding_core;
654    ///
655    /// use scaffolding_core::*;
656    ///
657    /// let mut email = EmailAddress::new(
658    ///       "home".to_string(),
659    ///       "myemail@example.com".to_string(),
660    /// );
661    /// println!("{}", email.serialize());
662    /// ```
663    pub fn serialize(&mut self) -> String {
664        serde_json::to_string(&self).unwrap()
665    }
666}
667
668#[derive(Serialize, Deserialize, Debug, Clone)]
669pub struct Note {
670    // The unique identifier of the note
671    pub id: String,
672    // The timestamp when the note was created
673    pub created_dtm: i64,
674    // The timestamp when the note was last modified
675    pub modified_dtm: i64,
676    // The identifier of the author of the note
677    pub author: String,
678    // The identifier of access rule of the note, (e.g.: public, internal, confidential)
679    pub access: String,
680    // The comment of the note
681    pub content: Vec<u8>,
682}
683
684impl Note {
685    /// This is the constructor function.
686    ///
687    /// #Example
688    ///
689    /// ```rust    
690    /// extern crate scaffolding_core;
691    ///
692    /// use scaffolding_core::*;
693    ///
694    /// let note = Note::new("fsmith".to_string(), "This was updated".as_bytes().to_vec(), None);
695    /// ```
696    pub fn new(auth: String, cont: Vec<u8>, acc: Option<String>) -> Self {
697        Self {
698            id: defaults::id(),
699            created_dtm: defaults::now(),
700            modified_dtm: defaults::now(),
701            author: auth,
702            access: match acc {
703                Some(a) => a,
704                None => defaults::access(),
705            },
706            content: cont,
707        }
708    }
709
710    /// This function returns the content of the note as a string.
711    ///
712    /// #Example
713    ///
714    /// ```rust     
715    /// extern crate scaffolding_core;
716    ///
717    /// use scaffolding_core::{defaults, Note};
718    ///
719    /// let note = Note::new("fsmith".to_string(), "This was updated".as_bytes().to_vec(), None);
720    /// assert_eq!(note.content_as_string().unwrap(), "This was updated".to_string());
721    /// ```
722    pub fn content_as_string(&self) -> Result<String, String> {
723        String::from_utf8(self.content.clone())
724            .map_err(|non_utf8| String::from_utf8_lossy(non_utf8.as_bytes()).into_owned())
725    }
726
727    /// This function instantiates an ActivityItem from a JSON string.
728    ///
729    /// #Example
730    ///
731    /// ```rust     
732    /// extern crate scaffolding_core;
733    ///
734    /// use scaffolding_core::*;
735    ///
736    /// let serialized = r#"{
737    ///   "id":"2d624160-16b1-49ce-9b90-09a82127d6ac",
738    ///   "created_dtm":1711833619,
739    ///   "modified_dtm":1711833619,
740    ///   "author":"fsmith",
741    ///   "access":"public",
742    ///   "content":[84,104,105,115,32,119,97,115,32,117,112,100,97,116,101,100]
743    /// }"#;
744    /// let mut note = Note::deserialized(&serialized.as_bytes()).unwrap();
745    ///
746    /// assert_eq!(note.created_dtm, 1711833619);
747    /// assert_eq!(note.modified_dtm, 1711833619);
748    /// assert_eq!(note.author, "fsmith".to_string());
749    /// assert_eq!(note.access, "public".to_string());
750    /// assert_eq!(note.content, "This was updated".as_bytes().to_vec());
751    /// ```
752    pub fn deserialized(serialized: &[u8]) -> Result<Note, DeserializeError> {
753        match serde_json::from_slice(&serialized) {
754            Ok(item) => Ok(item),
755            Err(err) => {
756                println!("{}", err);
757                Err(DeserializeError)
758            }
759        }
760    }
761
762    /// This function converts the ActivityItem to a serialize JSON string.
763    ///
764    /// #Example
765    ///
766    /// ```rust     
767    /// extern crate scaffolding_core;
768    ///
769    /// use scaffolding_core::*;
770    ///
771    /// let mut note = Note::new("fsmith".to_string(), "This was updated".as_bytes().to_vec(), None);
772    /// println!("{}", note.serialize());
773    /// ```
774    pub fn serialize(&mut self) -> String {
775        serde_json::to_string(&self).unwrap()
776    }
777
778    /// This function updates the note and sets the modified_dtm.
779    /// The modified_dtm will not be changed if the attributes are written to directly.
780    ///
781    /// #Example
782    ///
783    /// ```rust     
784    /// extern crate scaffolding_core;
785    ///
786    /// use scaffolding_core::*;
787    ///
788    /// let serialized = r#"{
789    ///   "id":"2d624160-16b1-49ce-9b90-09a82127d6ac",
790    ///   "created_dtm":1711833619,
791    ///   "modified_dtm":1711833619,
792    ///   "author":"fsmith",
793    ///   "access":"public",
794    ///   "content":[84,104,105,115,32,119,97,115,32,117,112,100,97,116,101,100]
795    /// }"#;
796    /// let mut note = Note::deserialized(&serialized.as_bytes()).unwrap();
797    /// let first_modified = note.modified_dtm.clone();
798    ///
799    /// note.update("fsmith".to_string(), "This was updated again".as_bytes().to_vec(), Some("private".to_string()));
800    ///
801    /// assert_eq!(note.author, "fsmith".to_string());
802    /// assert_eq!(note.access, "private".to_string());
803    /// assert_eq!(note.content, "This was updated again".as_bytes().to_vec());
804    /// assert!(note.modified_dtm > first_modified);
805    /// ```
806    pub fn update(&mut self, auth: String, cont: Vec<u8>, acc: Option<String>) {
807        self.author = auth;
808        self.content = cont;
809        self.access = match acc {
810            Some(a) => a,
811            None => self.access.clone(),
812        };
813        self.modified_dtm = defaults::now();
814    }
815}
816
817#[derive(Clone, Debug, Deserialize, Serialize)]
818pub struct PhoneNumber {
819    // The unique identifier of the note
820    pub id: String,
821    // The timestamp when the note was created
822    pub created_dtm: i64,
823    // The timestamp when the note was last modified
824    pub modified_dtm: i64,
825    // The type of address, (e.g.: Login, Personal, Work, Primary Contact, Assistant, etc.)
826    pub category: String,
827    // The phone number
828    pub number: String,
829    // The country code of the phone number (Use Alpha 3 codes)
830    pub country_code: String,
831}
832
833impl PhoneNumber {
834    /// This is the constructor function.
835    ///
836    /// #Example
837    ///
838    /// ```rust
839    /// extern crate scaffolding_core;
840    ///
841    /// use scaffolding_core::*;
842    ///
843    /// fn main() {
844    ///   let phone = PhoneNumber::new(
845    ///       "home".to_string(),
846    ///       "8482493561".to_string(),
847    ///       "USA".to_string(),
848    ///   );
849    ///   
850    ///   // scaffolding attributes
851    ///   println!("{}", phone.id);
852    ///   println!("{}", phone.created_dtm);
853    ///   println!("{}", phone.modified_dtm,);
854    /// }
855    /// ```
856    pub fn new(category: String, number: String, country_code: String) -> Self {
857        Self {
858            id: defaults::id(),
859            created_dtm: defaults::now(),
860            modified_dtm: defaults::now(),
861            category: category,
862            number: number,
863            country_code: country_code,
864        }
865    }
866
867    /// This function instantiates a PhoneNumber from a JSON string.
868    ///
869    /// #Example
870    ///
871    /// ```rust     
872    /// extern crate scaffolding_core;
873    ///
874    /// use scaffolding_core::*;
875    ///
876    /// let serialized = r#"{
877    ///   "id":"2d624160-16b1-49ce-9b90-09a82127d6ac",
878    ///   "created_dtm":1711833619,
879    ///   "modified_dtm":1711833619,
880    ///   "category":"home",
881    ///   "number":"8482493561",
882    ///   "country_code": "USA"
883    /// }"#;
884    /// let mut phone = PhoneNumber::deserialized(&serialized.as_bytes()).unwrap();
885    ///
886    /// assert_eq!(phone.created_dtm, 1711833619);
887    /// assert_eq!(phone.modified_dtm, 1711833619);
888    /// assert_eq!(phone.category, "home".to_string());
889    /// ```
890    pub fn deserialized(serialized: &[u8]) -> Result<PhoneNumber, DeserializeError> {
891        match serde_json::from_slice(&serialized) {
892            Ok(item) => Ok(item),
893            Err(err) => {
894                println!("{}", err);
895                Err(DeserializeError)
896            }
897        }
898    }
899
900    /// This function converts the PhoneNumber to a serialize JSON string.
901    ///
902    /// #Example
903    ///
904    /// ```rust    
905    /// extern crate scaffolding_core;
906    ///
907    /// use scaffolding_core::*;
908    ///
909    /// let mut phone = PhoneNumber::new(
910    ///       "home".to_string(),
911    ///       "8482493561".to_string(),
912    ///       "USA".to_string(),
913    /// );
914    /// println!("{}", phone.serialize());
915    /// ```
916    pub fn serialize(&mut self) -> String {
917        serde_json::to_string(&self).unwrap()
918    }
919}
920
921/// The core behavior of a Scaffolding object
922pub trait Scaffolding {
923    /// This function adds a ActivityItem to the activity log
924    ///
925    /// #Example
926    ///
927    /// ```rust
928    /// extern crate scaffolding_core;
929    ///  
930    /// use scaffolding_core::*;
931    ///
932    /// #[scaffolding_struct]
933    /// #[derive(Clone, Debug, Scaffolding)]
934    /// struct MyEntity {}
935    ///
936    /// impl MyEntity {
937    ///     #[scaffolding_fn]
938    ///     fn new() -> Self {
939    ///         Self {}
940    ///     }
941    /// }
942    ///
943    /// let mut entity = MyEntity::new();
944    ///
945    /// entity.log_activity("cancelled".to_string(), "The customer has cancelled their service".to_string());
946    /// assert_eq!(entity.activity.len(), 1);
947    /// ```
948    fn log_activity(&mut self, name: String, descr: String);
949
950    /// This function retrieves all the ActivityItems that have the specified action (name)
951    ///
952    /// #Example
953    ///
954    /// ```rust
955    /// extern crate scaffolding_core;
956    ///  
957    /// use scaffolding_core::*;
958    ///
959    /// #[scaffolding_struct]
960    /// #[derive(Clone, Debug, Scaffolding)]
961    /// struct MyEntity {}
962    ///
963    /// impl MyEntity {
964    ///     #[scaffolding_fn]
965    ///     fn new() -> Self {
966    ///         Self {}
967    ///     }
968    /// }
969    ///
970    /// let mut entity = MyEntity::new();
971    ///
972    /// entity.log_activity("ordered".to_string(), "The customer has place the order".to_string());
973    /// entity.log_activity("cancelled".to_string(), "The customer has cancelled their service".to_string());
974    /// assert_eq!(entity.get_activity("cancelled".to_string()).len(), 1);
975    /// ```
976    fn get_activity(&self, name: String) -> Vec<ActivityItem>;
977
978    /// This function instantiates an entity from a JSON string.
979    ///
980    /// #Example
981    ///
982    /// ```rust
983    /// extern crate scaffolding_core;
984    ///  
985    /// use scaffolding_core::*;
986    ///
987    /// #[scaffolding_struct]
988    /// #[derive(Clone, Debug, Deserialize, Scaffolding)]
989    /// struct MyEntity {}
990    ///
991    /// impl MyEntity {
992    ///     #[scaffolding_fn]
993    ///     fn new() -> Self {
994    ///         Self {}
995    ///     }
996    /// }
997    ///
998    /// let json = r#"{
999    ///     "id":"b4d6c6db-7468-400a-8536-a5e83b1f2bdc",
1000    ///     "created_dtm":1711802687,
1001    ///     "modified_dtm":1711802687,
1002    ///     "inactive_dtm":1719578687,
1003    ///     "expired_dtm":1806410687,
1004    ///     "activity":[
1005    ///         {
1006    ///             "created_dtm":1711802687,
1007    ///             "action":"updated",
1008    ///             "description":"The object has been updated"
1009    ///         },
1010    ///         {
1011    ///             "created_dtm":1711802687,
1012    ///             "action":"updated",
1013    ///             "description":"The object has been updated"
1014    ///         },
1015    ///         {
1016    ///             "created_dtm":1711802687,
1017    ///             "action":"cancelled",
1018    ///             "description":"The object has been cancelled"
1019    ///         }
1020    ///         ]
1021    ///     }"#;
1022    /// let deserialized = MyEntity::deserialized(json.as_bytes()).unwrap();
1023    ///
1024    /// assert_eq!(deserialized.id, "b4d6c6db-7468-400a-8536-a5e83b1f2bdc");
1025    /// assert_eq!(deserialized.activity.len(), 3);  
1026    ///
1027    /// ```
1028    fn deserialized(serialized: &[u8]) -> Result<Self, DeserializeError>
1029    where
1030        Self: DeserializeOwned,
1031    {
1032        match serde_json::from_slice::<Self>(&serialized) {
1033            Ok(item) => Ok(item),
1034            Err(err) => {
1035                println!("{}", err);
1036                Err(DeserializeError)
1037            }
1038        }
1039    }
1040
1041    /// This function converts the entity to a serialize JSON string.
1042    ///
1043    /// #Example
1044    ///
1045    /// ```rust
1046    /// extern crate scaffolding_core;
1047    ///  
1048    /// use scaffolding_core::*;
1049    ///
1050    /// #[scaffolding_struct]
1051    /// #[derive(Clone, Debug, Serialize, Scaffolding)]
1052    /// struct MyEntity {}
1053    ///
1054    /// impl MyEntity {
1055    ///     #[scaffolding_fn]
1056    ///     fn new() -> Self {
1057    ///         Self {}
1058    ///     }
1059    /// }
1060    ///
1061    /// let mut entity = MyEntity::new();
1062    /// let json_string = entity.serialize();
1063    ///
1064    /// println!("{}", json_string);
1065    /// ```
1066    fn serialize(&mut self) -> String
1067    where
1068        Self: Serialize,
1069    {
1070        serde_json::to_string(&self).unwrap()
1071    }
1072}
1073
1074/// The addresses behavior of a Scaffolding object
1075pub trait ScaffoldingAddresses {
1076    /// Retrieves a related Address to the Entity based on the specified id.
1077    ///
1078    /// #Example
1079    ///
1080    /// ```rust
1081    /// extern crate scaffolding_core;
1082    ///  
1083    /// use scaffolding_core::*;
1084    ///
1085    /// #[scaffolding_struct("addresses")]
1086    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingAddresses)]
1087    /// struct MyEntity {}
1088    ///
1089    /// impl MyEntity {
1090    ///     #[scaffolding_fn("addresses")]
1091    ///     fn new() -> Self {
1092    ///         Self {}
1093    ///     }
1094    /// }
1095    ///
1096    /// let mut entity = MyEntity::new();
1097    /// let id = entity.insert_address(
1098    ///     "shipping".to_string(),
1099    ///     "acmes company".to_string(),
1100    ///     "14 Main Street".to_string(),
1101    ///     "Big City, NY 038845".to_string(),
1102    ///     "USA".to_string(),
1103    ///     "USA".to_string(),
1104    /// );
1105    ///
1106    /// assert_eq!(entity.get_address(id).unwrap().category, "shipping".to_string());
1107    /// ```    
1108    fn get_address(&self, id: String) -> Option<&Address>;
1109
1110    /// Insert or updates a related Address to the Entity and returns the id of the Address.
1111    ///
1112    /// #Example
1113    ///
1114    /// ```rust
1115    /// extern crate scaffolding_core;
1116    ///  
1117    /// use scaffolding_core::*;
1118    ///
1119    /// #[scaffolding_struct("addresses")]
1120    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingAddresses)]
1121    /// struct MyEntity {}
1122    ///
1123    /// impl MyEntity {
1124    ///     #[scaffolding_fn("addresses")]
1125    ///     fn new() -> Self {
1126    ///         Self {}
1127    ///     }
1128    /// }
1129    ///
1130    /// let mut entity = MyEntity::new();
1131    /// let _ = entity.insert_address(
1132    ///     "shipping".to_string(),
1133    ///     "acmes company".to_string(),
1134    ///     "14 Main Street".to_string(),
1135    ///     "Big City, NY 038845".to_string(),
1136    ///     "USA".to_string(),
1137    ///     "USA".to_string(),
1138    /// );
1139    ///
1140    /// assert_eq!(entity.addresses.len(), 1);
1141    /// ```
1142    fn insert_address(
1143        &mut self,
1144        category: String,
1145        line_1: String,
1146        line_2: String,
1147        line_3: String,
1148        line_4: String,
1149        country_code: String,
1150    ) -> String;
1151
1152    /// Insert or updates a related Address to the Entity and returns the id of the Address for reference.
1153    ///
1154    /// #Example
1155    ///
1156    /// ```rust
1157    /// extern crate scaffolding_core;
1158    ///  
1159    /// use scaffolding_core::*;
1160    ///
1161    /// #[scaffolding_struct("addresses")]
1162    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingAddresses)]
1163    /// struct MyEntity {}
1164    ///
1165    /// impl MyEntity {
1166    ///     #[scaffolding_fn("addresses")]
1167    ///     fn new() -> Self {
1168    ///         Self {}
1169    ///     }
1170    /// }
1171    ///
1172    /// let mut entity = MyEntity::new();
1173    /// let id = entity.insert_address(
1174    ///     "shipping".to_string(),
1175    ///     "acmes company".to_string(),
1176    ///     "14 Main Street".to_string(),
1177    ///     "Big City, NY 038845".to_string(),
1178    ///     "USA".to_string(),
1179    ///     "USA".to_string(),
1180    /// );
1181    ///
1182    /// entity.modify_address(
1183    ///     id.clone(),
1184    ///     "billing".to_string(),
1185    ///     "acmes company".to_string(),
1186    ///     "14 Main Street".to_string(),
1187    ///     "Big City, NY 038845".to_string(),
1188    ///     "USA".to_string(),
1189    ///     "USA".to_string(),);
1190    ///
1191    /// assert_eq!(entity.get_address(id).unwrap().category, "billing".to_string());
1192    /// ```
1193    fn modify_address(
1194        &mut self,
1195        id: String,
1196        category: String,
1197        line_1: String,
1198        line_2: String,
1199        line_3: String,
1200        line_4: String,
1201        country_code: String,
1202    );
1203
1204    /// Retrieves all the Addresses with the specified category.
1205    ///
1206    /// #Example
1207    ///
1208    /// ```rust
1209    /// extern crate scaffolding_core;
1210    ///  
1211    /// use scaffolding_core::*;
1212    ///
1213    /// #[scaffolding_struct("addresses")]
1214    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingAddresses)]
1215    /// struct MyEntity {}
1216    ///
1217    /// impl MyEntity {
1218    ///     #[scaffolding_fn("addresses")]
1219    ///     fn new() -> Self {
1220    ///         Self {}
1221    ///     }
1222    /// }
1223    ///
1224    /// let mut entity = MyEntity::new();
1225    /// let address = entity.insert_address(
1226    ///     "shipping".to_string(),
1227    ///     "acmes company".to_string(),
1228    ///     "14 Main Street".to_string(),
1229    ///     "Big City, NY 038845".to_string(),
1230    ///     "USA".to_string(),
1231    ///     "USA".to_string(),
1232    /// );
1233    ///
1234    /// assert_eq!(entity.search_addresses_by_category("shipping".to_string()).len(), 1);
1235    /// ```
1236    fn search_addresses_by_category(&self, category: String) -> Vec<Address>;
1237
1238    /// Removes a related Address to the Entity.
1239    ///
1240    /// #Example
1241    ///
1242    /// ```rust
1243    /// extern crate scaffolding_core;
1244    ///  
1245    /// use scaffolding_core::*;
1246    ///
1247    /// #[scaffolding_struct("addresses")]
1248    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingAddresses)]
1249    /// struct MyEntity {}
1250    ///
1251    /// impl MyEntity {
1252    ///     #[scaffolding_fn("addresses")]
1253    ///     fn new() -> Self {
1254    ///         Self {}
1255    ///     }
1256    /// }
1257    ///
1258    /// let mut entity = MyEntity::new();
1259    /// let id = entity.insert_address(
1260    ///     "shipping".to_string(),
1261    ///     "acmes company".to_string(),
1262    ///     "14 Main Street".to_string(),
1263    ///     "Big City, NY 038845".to_string(),
1264    ///     "USA".to_string(),
1265    ///     "USA".to_string(),
1266    /// );
1267    /// assert_eq!(entity.addresses.len(), 1);
1268    ///
1269    /// entity.remove_address(id);
1270    /// assert_eq!(entity.addresses.len(), 0);
1271    /// ```
1272    fn remove_address(&mut self, id: String);
1273}
1274
1275/// The email address behavior of a Scaffolding object
1276pub trait ScaffoldingEmailAddresses {
1277    /// Retrieves a related EmailAddress based on the specific id.
1278    ///
1279    /// #Example
1280    ///
1281    /// ```rust
1282    /// extern crate scaffolding_core;
1283    ///  
1284    /// use scaffolding_core::*;
1285    ///
1286    /// #[scaffolding_struct("email_addresses")]
1287    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingEmailAddresses)]
1288    /// struct MyEntity {}
1289    ///
1290    /// impl MyEntity {
1291    ///     #[scaffolding_fn("email_addresses")]
1292    ///     fn new() -> Self {
1293    ///         Self {}
1294    ///     }
1295    /// }
1296    ///
1297    /// let mut entity = MyEntity::new();
1298    /// let id = entity.insert_email_address(
1299    ///     "home".to_string(),
1300    ///     "myemail@example.com".to_string(),
1301    /// );
1302    ///
1303    /// assert_eq!(entity.get_email_address(id).unwrap().address, "myemail@example.com".to_string());
1304    /// ```
1305    fn get_email_address(&self, id: String) -> Option<&EmailAddress>;
1306
1307    /// Adds a related PhoneNumber to the Entity and returns the id for reference.
1308    ///
1309    /// #Example
1310    ///
1311    /// ```rust
1312    /// extern crate scaffolding_core;
1313    ///  
1314    /// use scaffolding_core::*;
1315    ///
1316    /// #[scaffolding_struct("email_addresses")]
1317    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingEmailAddresses)]
1318    /// struct MyEntity {}
1319    ///
1320    /// impl MyEntity {
1321    ///     #[scaffolding_fn("email_addresses")]
1322    ///     fn new() -> Self {
1323    ///         Self {}
1324    ///     }
1325    /// }
1326    ///
1327    /// let mut entity = MyEntity::new();
1328    /// let _ = entity.insert_email_address(
1329    ///     "home".to_string(),
1330    ///     "myemail@example.com".to_string(),
1331    /// );
1332    ///
1333    /// assert_eq!(entity.email_addresses.len(), 1);
1334    /// ```
1335    fn insert_email_address(&mut self, category: String, address: String) -> String;
1336
1337    /// Retrieves all the EmailAddress with the specified category.
1338    ///
1339    /// #Example
1340    ///
1341    /// ```rust
1342    /// extern crate scaffolding_core;
1343    ///  
1344    /// use scaffolding_core::*;
1345    ///
1346    /// #[scaffolding_struct("email_addresses")]
1347    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingEmailAddresses)]
1348    /// struct MyEntity {}
1349    ///
1350    /// impl MyEntity {
1351    ///     #[scaffolding_fn("email_addresses")]
1352    ///     fn new() -> Self {
1353    ///         Self {}
1354    ///     }
1355    /// }
1356    ///
1357    /// let mut entity = MyEntity::new();
1358    /// let _ = entity.insert_email_address(
1359    ///     "home".to_string(),
1360    ///     "myemail@example.com".to_string(),
1361    /// );
1362    ///
1363    /// assert_eq!(entity.search_email_addresses_by_category("home".to_string()).len(), 1);
1364    /// ```
1365    fn search_email_addresses_by_category(&self, category: String) -> Vec<EmailAddress>;
1366
1367    /// Removes a related EmailAddress to the Entity.
1368    ///
1369    /// #Example
1370    ///
1371    /// ```rust
1372    /// extern crate scaffolding_core;
1373    ///  
1374    /// use scaffolding_core::*;
1375    ///
1376    /// #[scaffolding_struct("email_addresses")]
1377    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingEmailAddresses)]
1378    /// struct MyEntity {}
1379    ///
1380    /// impl MyEntity {
1381    ///     #[scaffolding_fn("email_addresses")]
1382    ///     fn new() -> Self {
1383    ///         Self {}
1384    ///     }
1385    /// }
1386    ///
1387    /// let mut entity = MyEntity::new();
1388    /// let id = entity.insert_email_address(
1389    ///     "home".to_string(),
1390    ///     "myemail@example.com".to_string(),
1391    /// );
1392    /// assert_eq!(entity.email_addresses.len(), 1);
1393    ///
1394    /// entity.remove_email_address(id);
1395    /// assert_eq!(entity.email_addresses.len(), 0);
1396    /// ```
1397    fn remove_email_address(&mut self, id: String);
1398}
1399
1400/// The notes behavior of a Scaffolding object
1401pub trait ScaffoldingNotes {
1402    /// Retrieves a related Note based on the specific id.
1403    ///
1404    /// #Example
1405    ///
1406    /// ```rust
1407    /// extern crate scaffolding_core;
1408    ///  
1409    /// use scaffolding_core::*;
1410    ///
1411    /// #[scaffolding_struct("notes")]
1412    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingNotes)]
1413    /// struct MyEntity {}
1414    ///
1415    /// impl MyEntity {
1416    ///     #[scaffolding_fn("notes")]
1417    ///     fn new() -> Self {
1418    ///         Self {}
1419    ///     }
1420    /// }
1421    ///
1422    /// let mut entity = MyEntity::new();
1423    /// let id = entity.insert_note(
1424    ///     "fsmith".to_string(),
1425    ///     "This was updated".as_bytes().to_vec(),
1426    ///     None,
1427    /// );
1428    ///
1429    /// assert_eq!(entity.get_note(id).unwrap().content_as_string().unwrap(), "This was updated".to_string());
1430    /// ```
1431    fn get_note(&self, id: String) -> Option<&Note>;
1432
1433    /// Inserts a related Note.
1434    ///
1435    /// #Example
1436    ///
1437    /// ```rust
1438    /// extern crate scaffolding_core;
1439    ///  
1440    /// use scaffolding_core::*;
1441    ///
1442    /// #[scaffolding_struct("notes")]
1443    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingNotes)]
1444    /// struct MyEntity {}
1445    ///
1446    /// impl MyEntity {
1447    ///     #[scaffolding_fn("notes")]
1448    ///     fn new() -> Self {
1449    ///         Self {}
1450    ///     }
1451    /// }
1452    ///
1453    /// let mut entity = MyEntity::new();
1454    /// let id = entity.insert_note(
1455    ///     "fsmith".to_string(),
1456    ///     "This was updated".as_bytes().to_vec(),
1457    ///     None,
1458    /// );
1459    ///
1460    /// assert_eq!(entity.notes.len(), 1);
1461    /// ```
1462    fn insert_note(&mut self, auth: String, cont: Vec<u8>, acc: Option<String>) -> String;
1463
1464    /// Updates a related Note based on the specified id.
1465    ///
1466    /// #Example
1467    ///
1468    /// ```rust
1469    /// extern crate scaffolding_core;
1470    ///  
1471    /// use scaffolding_core::*;
1472    ///
1473    /// #[scaffolding_struct("notes")]
1474    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingNotes)]
1475    /// struct MyEntity {}
1476    ///
1477    /// impl MyEntity {
1478    ///     #[scaffolding_fn("notes")]
1479    ///     fn new() -> Self {
1480    ///         Self {}
1481    ///     }
1482    /// }
1483    ///
1484    /// let mut entity = MyEntity::new();
1485    /// let id = entity.insert_note(
1486    ///     "fsmith".to_string(),
1487    ///     "This was updated".as_bytes().to_vec(),
1488    ///     None,
1489    /// );
1490    ///
1491    /// entity.modify_note(
1492    ///     id.clone(),
1493    ///     "fsmith".to_string(),
1494    ///     "This was updated again".as_bytes().to_vec(),
1495    ///     Some("private".to_string()),
1496    /// );
1497    /// ```
1498    fn modify_note(&mut self, id: String, auth: String, cont: Vec<u8>, acc: Option<String>);
1499
1500    /// Searches the notes for specific string and returns all the notes that were found.
1501    ///
1502    /// #Example
1503    ///
1504    /// ```rust
1505    /// extern crate scaffolding_core;
1506    ///  
1507    /// use scaffolding_core::*;
1508    ///
1509    /// #[scaffolding_struct("notes")]
1510    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingNotes)]
1511    /// struct MyEntity {}
1512    ///
1513    /// impl MyEntity {
1514    ///     #[scaffolding_fn("notes")]
1515    ///     fn new() -> Self {
1516    ///         Self {}
1517    ///     }
1518    /// }
1519    ///
1520    /// let mut entity = MyEntity::new();
1521    ///
1522    /// let _ = entity.insert_note(
1523    ///     "fsmith".to_string(),
1524    ///     "This was updated".as_bytes().to_vec(),
1525    ///     None,
1526    /// );
1527    /// let _ = entity.insert_note(
1528    ///     "fsmith".to_string(),
1529    ///     "Something to find here".as_bytes().to_vec(),
1530    ///     None,
1531    /// );
1532    /// let _ = entity.insert_note(
1533    ///     "fsmith".to_string(),
1534    ///     "Nonething to find here".as_bytes().to_vec(),
1535    ///     Some("private".to_string()),
1536    /// );
1537    ///  
1538    /// let search_results = entity.search_notes("thing".to_string());
1539    ///
1540    /// assert_eq!(search_results.len(), 2);
1541    /// ```
1542    fn search_notes(&mut self, search: String) -> Vec<Note>;
1543
1544    /// Removes a note for specific id.
1545    ///
1546    /// #Example
1547    ///
1548    /// ```rust
1549    /// extern crate scaffolding_core;
1550    ///  
1551    /// use scaffolding_core::*;
1552    ///
1553    /// #[scaffolding_struct("notes")]
1554    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingNotes)]
1555    /// struct MyEntity {}
1556    ///
1557    /// impl MyEntity {
1558    ///     #[scaffolding_fn("notes")]
1559    ///     fn new() -> Self {
1560    ///         Self {}
1561    ///     }
1562    /// }
1563    ///
1564    /// let mut entity = MyEntity::new();
1565    ///
1566    /// let _ = entity.insert_note(
1567    ///     "fsmith".to_string(),
1568    ///     "This was updated".as_bytes().to_vec(),
1569    ///     None,
1570    /// );
1571    /// let id = entity.insert_note(
1572    ///     "fsmith".to_string(),
1573    ///     "Something to find here".as_bytes().to_vec(),
1574    ///     None,
1575    /// );
1576    /// let _ = entity.insert_note(
1577    ///     "fsmith".to_string(),
1578    ///     "Nonething to find here".as_bytes().to_vec(),
1579    ///     Some("private".to_string()),
1580    /// );
1581    ///  
1582    /// entity.remove_note(id);
1583    ///
1584    /// assert_eq!(entity.notes.len(), 2);
1585    /// ```
1586    fn remove_note(&mut self, id: String);
1587}
1588
1589/// The phone number behavior of a Scaffolding object
1590pub trait ScaffoldingPhoneNumbers {
1591    /// Retrieves a related PhoneNumber based on the specific id.
1592    ///
1593    /// #Example
1594    ///
1595    /// ```rust
1596    /// extern crate scaffolding_core;
1597    ///  
1598    /// use scaffolding_core::*;
1599    ///
1600    /// #[scaffolding_struct("phone_numbers")]
1601    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingPhoneNumbers)]
1602    /// struct MyEntity {}
1603    ///
1604    /// impl MyEntity {
1605    ///     #[scaffolding_fn("phone_numbers")]
1606    ///     fn new() -> Self {
1607    ///         Self {}
1608    ///     }
1609    /// }
1610    ///
1611    /// let mut entity = MyEntity::new();
1612    /// let id = entity.insert_phone_number(
1613    ///     "home".to_string(),
1614    ///     "8482493561".to_string(),
1615    ///     "USA".to_string(),
1616    /// );
1617    ///
1618    /// assert_eq!(entity.get_phone_number(id).unwrap().number, "8482493561".to_string());
1619    /// ```
1620    fn get_phone_number(&self, id: String) -> Option<&PhoneNumber>;
1621
1622    /// Adds a related PhoneNumber to the Entity and returns the id for reference.
1623    ///
1624    /// #Example
1625    ///
1626    /// ```rust
1627    /// extern crate scaffolding_core;
1628    ///  
1629    /// use scaffolding_core::*;
1630    ///
1631    /// #[scaffolding_struct("phone_numbers")]
1632    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingPhoneNumbers)]
1633    /// struct MyEntity {}
1634    ///
1635    /// impl MyEntity {
1636    ///     #[scaffolding_fn("phone_numbers")]
1637    ///     fn new() -> Self {
1638    ///         Self {}
1639    ///     }
1640    /// }
1641    ///
1642    /// let mut entity = MyEntity::new();
1643    /// let _ = entity.insert_phone_number(
1644    ///     "home".to_string(),
1645    ///     "8482493561".to_string(),
1646    ///     "USA".to_string(),
1647    /// );
1648    ///
1649    /// assert_eq!(entity.phone_numbers.len(), 1);
1650    /// ```
1651    fn insert_phone_number(
1652        &mut self,
1653        category: String,
1654        number: String,
1655        country_code: String,
1656    ) -> String;
1657
1658    /// Retrieves all the PhoneNumber with the specified category.
1659    ///
1660    /// #Example
1661    ///
1662    /// ```rust
1663    /// extern crate scaffolding_core;
1664    ///  
1665    /// use scaffolding_core::*;
1666    ///
1667    /// #[scaffolding_struct("phone_numbers")]
1668    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingPhoneNumbers)]
1669    /// struct MyEntity {}
1670    ///
1671    /// impl MyEntity {
1672    ///     #[scaffolding_fn("phone_numbers")]
1673    ///     fn new() -> Self {
1674    ///         Self {}
1675    ///     }
1676    /// }
1677    ///
1678    /// let mut entity = MyEntity::new();
1679    /// let _ = entity.insert_phone_number(
1680    ///     "home".to_string(),
1681    ///     "8482493561".to_string(),
1682    ///     "USA".to_string(),
1683    /// );
1684    ///
1685    /// assert_eq!(entity.search_phone_numbers_by_category("home".to_string()).len(), 1);
1686    /// ```
1687    fn search_phone_numbers_by_category(&self, category: String) -> Vec<PhoneNumber>;
1688
1689    /// Removes a related PhoneNumber to the Entity.
1690    ///
1691    /// #Example
1692    ///
1693    /// ```rust
1694    /// extern crate scaffolding_core;
1695    ///  
1696    /// use scaffolding_core::*;
1697    ///
1698    /// #[scaffolding_struct("phone_numbers")]
1699    /// #[derive(Clone, Debug, Deserialize, Serialize, Scaffolding, ScaffoldingPhoneNumbers)]
1700    /// struct MyEntity {}
1701    ///
1702    /// impl MyEntity {
1703    ///     #[scaffolding_fn("phone_numbers")]
1704    ///     fn new() -> Self {
1705    ///         Self {}
1706    ///     }
1707    /// }
1708    ///
1709    /// let mut entity = MyEntity::new();
1710    /// let id = entity.insert_phone_number(
1711    ///     "home".to_string(),
1712    ///     "8482493561".to_string(),
1713    ///     "USA".to_string(),
1714    /// );
1715    /// assert_eq!(entity.phone_numbers.len(), 1);
1716    ///
1717    /// entity.remove_phone_number(id);
1718    /// assert_eq!(entity.phone_numbers.len(), 0);
1719    /// ```
1720    fn remove_phone_number(&mut self, id: String);
1721}
1722
1723/// The tagging behavior of a Scaffolding object
1724pub trait ScaffoldingTags {
1725    /// This function adds a tag to the object
1726    ///
1727    /// #Example
1728    ///
1729    /// ```rust
1730    /// extern crate scaffolding_core;
1731    ///  
1732    /// use scaffolding_core::*;
1733    ///
1734    /// #[scaffolding_struct("tags")]
1735    /// #[derive(Clone, Debug, Scaffolding, ScaffoldingTags)]
1736    /// struct MyEntity {}
1737    ///
1738    /// impl MyEntity {
1739    ///     #[scaffolding_fn("tags")]
1740    ///     fn new() -> Self {
1741    ///         Self {}
1742    ///     }
1743    /// }
1744    ///
1745    /// let mut entity = MyEntity::new();
1746    ///
1747    /// entity.add_tag("tag_1".to_string());
1748    /// // ignore any duplicates
1749    /// entity.add_tag("tag_1".to_string());
1750    /// entity.add_tag("tag_2".to_string());
1751    /// entity.add_tag("tag_3".to_string());
1752    ///
1753    /// assert_eq!(entity.tags.len(), 3);
1754    /// ```
1755    fn add_tag(&mut self, tag: String);
1756
1757    /// This function determines if the object has a specific tag
1758    ///
1759    /// #Example
1760    ///
1761    /// ```rust
1762    /// extern crate scaffolding_core;
1763    ///  
1764    /// use scaffolding_core::*;
1765    ///
1766    /// #[scaffolding_struct("tags")]
1767    /// #[derive(Clone, Debug, Scaffolding, ScaffoldingTags)]
1768    /// struct MyEntity {}
1769    ///
1770    /// impl MyEntity {
1771    ///     #[scaffolding_fn("tags")]
1772    ///     fn new() -> Self {
1773    ///         Self {}
1774    ///     }
1775    /// }
1776    ///
1777    /// let mut entity = MyEntity::new();
1778    ///
1779    /// entity.add_tag("tag_1".to_string());
1780    ///
1781    /// assert!(entity.has_tag("tag_1".to_string()));
1782    /// ```
1783    fn has_tag(&self, tag: String) -> bool;
1784
1785    /// This function removes a specific tag from the object
1786    ///
1787    /// #Example
1788    ///
1789    /// ```rust
1790    /// extern crate scaffolding_core;
1791    ///  
1792    /// use scaffolding_core::*;
1793    ///
1794    /// #[scaffolding_struct("tags")]
1795    /// #[derive(Clone, Debug, Scaffolding, ScaffoldingTags)]
1796    /// struct MyEntity {}
1797    ///
1798    /// impl MyEntity {
1799    ///     #[scaffolding_fn("tags")]
1800    ///     fn new() -> Self {
1801    ///         Self {}
1802    ///     }
1803    /// }
1804    ///
1805    /// let mut entity = MyEntity::new();
1806    ///
1807    /// entity.add_tag("tag_1".to_string());
1808    /// assert_eq!(entity.tags.len(), 1);
1809    /// entity.remove_tag("tag_1".to_string());
1810    /// assert_eq!(entity.tags.len(), 0);
1811    /// ```
1812    fn remove_tag(&mut self, tag: String);
1813}
1814
1815// modules
1816pub mod defaults;
1817pub mod errors;
1818
1819#[cfg(test)]
1820mod tests {
1821    use crate::{defaults, ActivityItem};
1822
1823    fn get_actionitem() -> ActivityItem {
1824        ActivityItem::new(
1825            "updated".to_string(),
1826            "The object has been updated.".to_string(),
1827        )
1828    }
1829    #[test]
1830    fn test_activityitem_new() {
1831        let ai = get_actionitem();
1832
1833        assert_eq!(ai.created_dtm, defaults::now());
1834        assert_eq!(ai.action, "updated".to_string());
1835        assert_eq!(ai.description, "The object has been updated.".to_string());
1836    }
1837
1838    #[test]
1839    fn test_activityitem_serialization() {
1840        let serialized = r#"{"created_dtm":1711760135,"action":"updated","description":"The object has been updated."}"#;
1841        let mut ai = ActivityItem::deserialized(&serialized.as_bytes()).unwrap();
1842
1843        assert_eq!(ai.created_dtm, 1711760135);
1844        assert_eq!(ai.action, "updated".to_string());
1845        assert_eq!(ai.description, "The object has been updated.".to_string());
1846        assert_eq!(ai.serialize(), serialized);
1847    }
1848}