1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
//! Object-oriented programming (OOP) has been around since the 1960s and was first introduced in the late 1950s
//! in artificial intelligence by an MMIT group. It is no wonder then that over the years, the concept of objects
//! being represented by classes and attributes with inheritanted behavior.
//!
//! Rust addresses this design by providing structures, traits, and implementations. However, the native ability to
//! `extend` a class (like in other languages) makes OOP a bit of a challenge. To address this gap, `Scaffolding` utilizes
//! Rust's [procedural macros](https://doc.rust-lang.org/reference/procedural-macros.html) to mimic the ability to
//! `extend` a class - both data structure and behavior.
//!
//! ## Scaffolding Concept
//! I. A class that `extends` the "Scaffolding class" should inherate all the "parent" data structure and behavior,
//! as well as append the "child" specific data structure and behavior
//! II. The developer should have the flexibility to adopt the default "parent" characteristics or overwrite them as desired.
//! III. There are common class attributes that are required in order to manage it using CRUD
//! + `id` - The unique identifier of the object.
//! + `created_dtm` - The unix epoch (UTC) representation of when the object was created
//! + `modified_dtm` - The unix epoch (UTC) representation of when the object was last updated
//! + `inactive_dtm` - The unix epoch (UTC) representation of when the object was/will be considered obsolete
//! + `expired_dtm` - The unix epoch (UTC) representation of when the object was/will be ready for deletion
//! IV. There is common class behaviors that are required in order to manage it using CRUD
//! + The `id` is not optional. It must be either provided or automatically generated during instantiation.
//! This can be done by calling the `Scaffolding` trait's `id()` method
//! + The `created_dtm` is not optional. It must be either provided or automatically generated during instantiation.
//! This can be done by calling one of the `Scaffolding` trait's many datetime related methods, (e.g.: `now()`)
//! + The `modified_dtm` is not optional. It must be either provided or automatically generated during instantiation or updates to the object.
//! This can be done by calling one of the `Scaffolding` trait's many datetime related methods, (e.g.: `now()`)
//! + The `inactive_dtm` is not optional. It must be either provided or automatically generated during instantiation or updates to the object.
//! This can be done by calling one of the `Scaffolding` trait's many datetime related methods, (e.g.: `add_months()` in conjuctions with `now()`)
//! + The `expire_dtm` is not optional. It must be either provided or automatically generated during instantiation or updates to the object.
//! This can be done by calling one of the `Scaffolding` trait's many datetime related methods, (e.g.: `never()`)
//!
//! ### Example
//!
//! ```rust
//! extern crate scaffolding_core;
//!
//! use scaffolding_core::*;
//! use scaffolding_macros::*;
//!
//! #[as_entity]
//! #[derive(Debug, Clone, Scaffolding)]
//! struct MyEntity {
//! b: bool,
//! }
//!
//! impl MyEntity {
//! fn new(arg: bool) -> Self {
//! Self {
//! id: <Self as Scaffolding>::id(),
//! created_dtm: <Self as Scaffolding>::now(),
//! modified_dtm: <Self as Scaffolding>::now(),
//! inactive_dtm: <Self as Scaffolding>::add_months(<Self as Scaffolding>::now(), 12),
//! expired_dtm: <Self as Scaffolding>::add_years(<Self as Scaffolding>::now(), 3),
//! b: arg,
//! }
//! }
//!
//! fn my_func(&self) -> String {
//! "my function".to_string()
//! }
//! }
//!
//! let entity = MyEntity::new(true);
//! println!("{:?}", entity);
//!
//! // extended attributes
//! assert_eq!(entity.b, true);
//!
//! // extended behavior
//! assert_eq!(entity.my_func(), "my function");
//! ```
use chrono::{DateTime, Duration, Months, Utc};
use uuid::Uuid;
/// The core behavior of an Scaffolding object
pub trait Scaffolding {
/// generates a uuid v4 value
fn id() -> String {
Uuid::new_v4().to_string()
}
/// adds x days to the timestamp
fn add_days(dtm: i64, days: i64) -> i64 {
let dt = DateTime::from_timestamp(dtm, 0).unwrap() + Duration::try_days(days).unwrap();
dt.timestamp()
}
/// adds x months to the timestamp
fn add_months(dtm: i64, months: u32) -> i64 {
let dt = DateTime::from_timestamp(dtm, 0).unwrap() + Months::new(months);
dt.timestamp()
}
/// adds x years to the timestamp
fn add_years(dtm: i64, years: u32) -> i64 {
let dt = DateTime::from_timestamp(dtm, 0).unwrap() + Months::new(years * 12);
dt.timestamp()
}
/// provided the default unix epoch time (UTC) as seconds
/// for the timestamp: 9999-12-31 23:59:59
fn never() -> i64 {
253402261199
}
/// generate the current unix epoch time (UTC) as seconds
fn now() -> i64 {
Utc::now().timestamp()
}
}