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}