use crate::Field;
use chrono::{DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime};
use json::{object, JsonValue};
use std::time::{Duration, UNIX_EPOCH};
pub struct Year {
pub require: bool,
pub field: String,
pub mode: String,
pub title: String,
pub def: String,
pub show: bool,
pub describe: String,
pub example: JsonValue,
}
impl Year {
pub fn new(require: bool, field: &str, title: &str, default: &str) -> Self {
Self {
field: field.to_string(),
mode: "year".to_string(),
title: title.to_string(),
def: default.to_string(),
require,
show: true,
describe: String::new(),
example: JsonValue::Null,
}
}
pub fn year() -> String {
let now: DateTime<Local> = Local::now();
let dft = now.format("%Y");
dft.to_string()
}
pub fn timestamp_to_year(timestamp: i64) -> String {
let d = UNIX_EPOCH + Duration::from_secs(timestamp as u64);
let datetime = DateTime::<Local>::from(d);
let timestamp_str = datetime.format("%Y").to_string();
timestamp_str
}
}
impl Field for Year {
fn sql(&mut self, model: &str) -> String {
let not_null = if self.require { " not null" } else { "" };
match model {
"sqlite" => format!(
"`{}` INTEGER{} default '{}'",
self.field, not_null, self.def
),
"pgsql" => {
let sql = format!(r#""{}" SMALLINT default '{}'"#, self.field, self.def);
format!(
"{} --{}|{}|{}|{}",
sql, self.title, self.mode, self.require, self.def
)
}
_ => {
let sql = format!("`{}` year{} default '{}'", self.field, not_null, self.def);
format!(
"{} comment '{}|{}|{}|{}'",
sql, self.title, self.mode, self.require, self.def
)
}
}
}
fn hide(&mut self) -> &mut Self {
self.show = false;
self
}
fn describe(&mut self, text: &str) -> &mut Self {
self.describe = text.to_string();
self
}
fn field(&mut self) -> JsonValue {
let mut field = object! {};
field
.insert("require", JsonValue::from(self.require))
.unwrap();
field
.insert("field", JsonValue::from(self.field.clone()))
.unwrap();
field
.insert("mode", JsonValue::from(self.mode.clone()))
.unwrap();
field
.insert("title", JsonValue::from(self.title.clone()))
.unwrap();
field
.insert("def", JsonValue::from(self.def.clone()))
.unwrap();
field.insert("show", JsonValue::from(self.show)).unwrap();
field
.insert("describe", JsonValue::from(self.describe.clone()))
.unwrap();
field.insert("example", self.example.clone()).unwrap();
field
}
fn swagger(&mut self) -> JsonValue {
object! {
"type": self.mode.clone(),
"example": self.example.clone(),
}
}
fn example(&mut self, data: JsonValue) -> &mut Self {
self.example = data.clone();
self
}
}
pub struct YearMonth {
pub require: bool,
pub field: String,
pub mode: String,
pub title: String,
pub def: i64,
pub show: bool,
pub describe: String,
pub example: JsonValue,
}
impl YearMonth {
pub fn new(require: bool, field: &str, title: &str, default: i64) -> Self {
Self {
field: field.to_string(),
mode: "yearmonth".to_string(),
title: title.to_string(),
def: default,
require,
show: true,
describe: String::new(),
example: JsonValue::Null,
}
}
pub fn year_month() -> i64 {
let now: DateTime<Local> = Local::now();
let first_day = format!("{}-01 00:00:00", now.format("%Y-%m"));
let t = NaiveDateTime::parse_from_str(&first_day, "%Y-%m-%d %H:%M:%S").unwrap();
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
t.and_local_timezone(tz).unwrap().timestamp()
}
#[allow(clippy::should_implement_trait)]
pub fn from_str(year_month: &str) -> i64 {
let date_str = if year_month.len() == 7 {
format!("{}-01 00:00:00", year_month)
} else {
format!("{} 00:00:00", year_month)
};
let t = match NaiveDateTime::parse_from_str(&date_str, "%Y-%m-%d %H:%M:%S") {
Ok(t) => t,
Err(_) => return 0,
};
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
t.and_local_timezone(tz).unwrap().timestamp()
}
pub fn to_str(timestamp: i64) -> String {
let d = UNIX_EPOCH + Duration::from_secs(timestamp as u64);
let datetime = DateTime::<Local>::from(d);
datetime.format("%Y-%m").to_string()
}
}
impl Field for YearMonth {
fn sql(&mut self, model: &str) -> String {
let not_null = if self.require { " not null" } else { "" };
let max = 10;
match model {
"sqlite" => {
format!("`{}` REAL{} default {}", self.field, not_null, self.def)
}
"pgsql" => {
let sql = format!(
r#""{}" decimal({},0) default {}"#,
self.field, max, self.def
);
format!(
"{} --{}|{}|{}|{}",
sql, self.title, self.mode, self.require, self.def
)
}
_ => {
let sql = format!(
"`{}` decimal({},0){} default {}",
self.field, max, not_null, self.def
);
format!(
"{} comment '{}|{}|{}|{}'",
sql, self.title, self.mode, self.require, self.def
)
}
}
}
fn hide(&mut self) -> &mut Self {
self.show = false;
self
}
fn describe(&mut self, text: &str) -> &mut Self {
self.describe = text.to_string();
self
}
fn field(&mut self) -> JsonValue {
let mut field = object! {};
field
.insert("require", JsonValue::from(self.require))
.unwrap();
field
.insert("field", JsonValue::from(self.field.clone()))
.unwrap();
field
.insert("mode", JsonValue::from(self.mode.clone()))
.unwrap();
field
.insert("title", JsonValue::from(self.title.clone()))
.unwrap();
field.insert("def", JsonValue::from(self.def)).unwrap();
field.insert("show", JsonValue::from(self.show)).unwrap();
field
.insert("describe", JsonValue::from(self.describe.clone()))
.unwrap();
field.insert("example", self.example.clone()).unwrap();
field
}
fn swagger(&mut self) -> JsonValue {
object! {
"type": self.mode.clone(),
"example": self.example.clone(),
}
}
fn example(&mut self, data: JsonValue) -> &mut Self {
self.example = data.clone();
self
}
}
pub struct Datetime {
pub require: bool,
pub field: String,
pub mode: String,
pub title: String,
pub def: i64,
pub show: bool,
pub describe: String,
pub example: JsonValue,
}
impl Datetime {
pub fn new(require: bool, field: &str, title: &str, default: i64) -> Self {
Self {
field: field.to_string(),
mode: "datetime".to_string(),
title: title.to_string(),
def: default,
require,
show: true,
describe: String::new(),
example: JsonValue::Null,
}
}
pub fn datetime() -> i64 {
Local::now().timestamp()
}
pub fn timestamp_to_datetime(timestamp: i64) -> String {
let d = UNIX_EPOCH + Duration::from_secs(timestamp as u64);
let datetime = DateTime::<Local>::from(d);
datetime.format("%Y-%m-%d %H:%M:%S").to_string()
}
pub fn datetime_to_timestamp(datetime: &str) -> i64 {
if datetime.is_empty() || datetime == "0001-01-01 00:00:00" {
return 0;
}
let t = NaiveDateTime::parse_from_str(datetime, "%Y-%m-%d %H:%M:%S");
match t {
Ok(d) => {
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
d.and_local_timezone(tz).unwrap().timestamp()
}
Err(_) => 0,
}
}
pub fn datetime_format(format: &str) -> String {
let now: DateTime<Local> = Local::now();
let dft = now.format(format);
dft.to_string()
}
}
impl Field for Datetime {
fn sql(&mut self, model: &str) -> String {
let not_null = if self.require { " not null" } else { "" };
let max = 10;
match model {
"sqlite" => {
format!("`{}` REAL{} default {}", self.field, not_null, self.def)
}
"pgsql" => {
let sql = format!(
r#""{}" decimal({},0) default {}"#,
self.field, max, self.def
);
format!(
"{} --{}|{}|{}|{}",
sql, self.title, self.mode, self.require, self.def
)
}
_ => {
let sql = format!(
"`{}` decimal({},0){} default {}",
self.field, max, not_null, self.def
);
format!(
"{} comment '{}|{}|{}|{}'",
sql, self.title, self.mode, self.require, self.def
)
}
}
}
fn hide(&mut self) -> &mut Self {
self.show = false;
self
}
fn describe(&mut self, text: &str) -> &mut Self {
self.describe = text.to_string();
self
}
fn field(&mut self) -> JsonValue {
let mut field = object! {};
field
.insert("require", JsonValue::from(self.require))
.unwrap();
field
.insert("field", JsonValue::from(self.field.clone()))
.unwrap();
field
.insert("mode", JsonValue::from(self.mode.clone()))
.unwrap();
field
.insert("title", JsonValue::from(self.title.clone()))
.unwrap();
field.insert("def", JsonValue::from(self.def)).unwrap();
field.insert("show", JsonValue::from(self.show)).unwrap();
field
.insert("describe", JsonValue::from(self.describe.clone()))
.unwrap();
field.insert("example", self.example.clone()).unwrap();
field
}
fn swagger(&mut self) -> JsonValue {
object! {
"type": self.mode.clone(),
"example": self.example.clone(),
}
}
fn example(&mut self, data: JsonValue) -> &mut Self {
self.example = data.clone();
self
}
}
#[derive(Debug, Clone)]
pub struct Time {
pub require: bool,
pub field: String,
pub mode: String,
pub title: String,
pub def: String,
pub show: bool,
pub describe: String,
pub example: JsonValue,
}
impl Time {
pub fn new(require: bool, field: &str, title: &str, default: &str) -> Self {
Self {
field: field.to_string(),
mode: "time".to_string(),
title: title.to_string(),
def: default.to_string(),
require,
show: true,
describe: String::new(),
example: JsonValue::Null,
}
}
pub fn time() -> String {
let now: DateTime<Local> = Local::now();
let dft = now.format("%H:%M:%S");
dft.to_string()
}
}
impl Field for Time {
fn sql(&mut self, model: &str) -> String {
let not_null = if self.require { " not null" } else { "" };
match model {
"sqlite" => format!("`{}` time{} default '{}'", self.field, not_null, self.def),
"pgsql" => {
let sql = format!(r#""{}" time default '{}'"#, self.field, self.def);
format!(
"{} --{}|{}|{}|{}",
sql, self.title, self.mode, self.require, self.def
)
}
_ => {
let sql = format!("`{}` time{} default '{}'", self.field, not_null, self.def);
format!(
"{} comment '{}|{}|{}|{}'",
sql, self.title, self.mode, self.require, self.def
)
}
}
}
fn hide(&mut self) -> &mut Self {
self.show = false;
self
}
fn describe(&mut self, text: &str) -> &mut Self {
self.describe = text.to_string();
self
}
fn field(&mut self) -> JsonValue {
let mut field = object! {};
field
.insert("require", JsonValue::from(self.require))
.unwrap();
field
.insert("field", JsonValue::from(self.field.clone()))
.unwrap();
field
.insert("mode", JsonValue::from(self.mode.clone()))
.unwrap();
field
.insert("title", JsonValue::from(self.title.clone()))
.unwrap();
field
.insert("def", JsonValue::from(self.def.clone()))
.unwrap();
field.insert("show", JsonValue::from(self.show)).unwrap();
field
.insert("describe", JsonValue::from(self.describe.clone()))
.unwrap();
field.insert("example", self.example.clone()).unwrap();
field
}
fn swagger(&mut self) -> JsonValue {
object! {
"type": self.mode.clone(),
"example": self.example.clone(),
}
}
fn example(&mut self, data: JsonValue) -> &mut Self {
self.example = data.clone();
self
}
}
#[derive(Debug, Clone)]
pub struct Date {
pub require: bool,
pub field: String,
pub mode: String,
pub title: String,
pub def: i64,
pub show: bool,
pub describe: String,
pub example: JsonValue,
}
impl Date {
pub fn new(require: bool, field: &str, title: &str, default: i64) -> Self {
Self {
field: field.to_string(),
mode: "date".to_string(),
title: title.to_string(),
def: default,
require,
show: true,
describe: "".to_string(),
example: JsonValue::Null,
}
}
pub fn date() -> i64 {
let now: DateTime<Local> = Local::now();
let today = now.format("%Y-%m-%d").to_string();
let t = NaiveDate::parse_from_str(&today, "%Y-%m-%d").unwrap();
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
t.and_hms_opt(0, 0, 0)
.unwrap()
.and_local_timezone(tz)
.unwrap()
.timestamp()
}
pub fn timestamp_to_date(timestamp: i64) -> String {
let d = UNIX_EPOCH + Duration::from_secs(timestamp as u64);
let datetime = DateTime::<Local>::from(d);
let timestamp_str = datetime.format("%Y-%m-%d").to_string();
timestamp_str
}
pub fn date_to_timestamp(date: &str) -> i64 {
if date.is_empty() || date == "0001-01-01" {
return 0;
}
let t = NaiveDate::parse_from_str(date, "%Y-%m-%d");
match t {
Ok(d) => {
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
d.and_hms_opt(0, 0, 0)
.unwrap()
.and_local_timezone(tz)
.unwrap()
.timestamp()
}
Err(_) => 0,
}
}
}
impl Field for Date {
fn sql(&mut self, model: &str) -> String {
let not_null = if self.require { " not null" } else { "" };
let max = 10;
match model {
"sqlite" => {
format!("`{}` REAL{} default {}", self.field, not_null, self.def)
}
"pgsql" => {
let sql = format!(
r#""{}" decimal({},0) default {}"#,
self.field, max, self.def
);
format!(
"{} --{}|{}|{}|{}",
sql, self.title, self.mode, self.require, self.def
)
}
_ => {
let sql = format!(
"`{}` decimal({},0){} default {}",
self.field, max, not_null, self.def
);
format!(
"{} comment '{}|{}|{}|{}'",
sql, self.title, self.mode, self.require, self.def
)
}
}
}
fn hide(&mut self) -> &mut Self {
self.show = false;
self
}
fn describe(&mut self, text: &str) -> &mut Self {
self.describe = text.to_string();
self
}
fn field(&mut self) -> JsonValue {
let mut field = object! {};
field
.insert("require", JsonValue::from(self.require))
.unwrap();
field
.insert("field", JsonValue::from(self.field.clone()))
.unwrap();
field
.insert("mode", JsonValue::from(self.mode.clone()))
.unwrap();
field
.insert("title", JsonValue::from(self.title.clone()))
.unwrap();
field.insert("def", JsonValue::from(self.def)).unwrap();
field.insert("show", JsonValue::from(self.show)).unwrap();
field
.insert("describe", JsonValue::from(self.describe.clone()))
.unwrap();
field.insert("example", self.example.clone()).unwrap();
field
}
fn swagger(&mut self) -> JsonValue {
object! {
"type": self.mode.clone(),
"example": self.example.clone(),
}
}
fn example(&mut self, data: JsonValue) -> &mut Self {
self.example = data.clone();
self
}
}
#[derive(Debug, Clone)]
pub struct Timestamp {
pub require: bool,
pub field: String,
pub mode: String,
pub title: String,
pub def: f64,
pub dec: i32,
pub show: bool,
pub describe: String,
pub example: JsonValue,
}
impl Timestamp {
pub fn new(require: bool, field: &str, title: &str, dec: i32, default: f64) -> Self {
Self {
require,
field: field.to_string(),
mode: "timestamp".to_string(),
title: title.to_string(),
def: default,
dec,
show: true,
describe: "".to_string(),
example: JsonValue::Null,
}
}
pub fn timestamp() -> i64 {
Local::now().timestamp()
}
pub fn timestamp_ms() -> i64 {
Local::now().timestamp_millis()
}
pub fn timestamp_ms_f64() -> f64 {
Local::now().timestamp_millis() as f64 / 1000.0
}
pub fn timestamp_μs() -> i64 {
Local::now().timestamp_micros()
}
pub fn timestamp_μs_f64() -> f64 {
Local::now().timestamp_micros() as f64 / 1000.0 / 1000.0
}
pub fn timestamp_ns() -> i64 {
Local::now().timestamp_nanos_opt().unwrap()
}
pub fn date_to_timestamp(date: &str) -> i64 {
let t = NaiveDate::parse_from_str(date, "%Y-%m-%d").unwrap();
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
t.and_hms_opt(0, 0, 0)
.unwrap()
.and_local_timezone(tz)
.unwrap()
.timestamp()
}
pub fn datetime_to_rfc2822(datetime: &str) -> String {
let t = NaiveDateTime::parse_from_str(datetime, "%Y-%m-%d %H:%M:%S").unwrap();
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
t.and_local_timezone(tz).unwrap().to_rfc2822()
}
pub fn datetime_utc_rfc2822(datetime: &str) -> String {
let t = NaiveDateTime::parse_from_str(datetime, "%Y-%m-%d %H:%M:%S").unwrap();
t.and_utc().to_rfc2822()
}
pub fn datetime_to_fmt(datetime: &str, fmt: &str) -> String {
let t = NaiveDateTime::parse_from_str(datetime, "%Y-%m-%d %H:%M:%S").unwrap();
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
t.and_local_timezone(tz).unwrap().format(fmt).to_string()
}
pub fn datetime_to_timestamp(datetime: &str, fmt: &str) -> i64 {
let t = NaiveDateTime::parse_from_str(datetime, fmt).unwrap();
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
t.and_local_timezone(tz).unwrap().timestamp()
}
pub fn datetime_timestamp(datetime: &str) -> i64 {
let t = NaiveDateTime::parse_from_str(datetime, "%Y-%m-%d %H:%M:%S").unwrap();
let tz = FixedOffset::east_opt(Local::now().offset().local_minus_utc()).unwrap();
t.and_local_timezone(tz).unwrap().timestamp()
}
}
impl Field for Timestamp {
fn sql(&mut self, model: &str) -> String {
let not_null = if self.require { " not null" } else { "" };
let max = 10 + self.dec;
match model {
"sqlite" => {
let def = format!("{0:.width$}", self.def, width = self.dec as usize)
.parse::<f64>()
.unwrap();
format!("`{}` REAL{} default {}", self.field, not_null, def)
}
"pgsql" => {
let def = format!("{0:.width$}", self.def, width = self.dec as usize);
let def_value = def.parse::<f64>().unwrap();
let sql = format!(
r#""{}" decimal({},{}) default {}"#,
self.field, max, self.dec, def_value
);
format!(
"{} --{}|{}|{}|{}|{}",
sql, self.title, self.mode, self.require, self.dec, def_value
)
}
_ => {
let def = format!("{0:.width$}", self.def, width = self.dec as usize);
let def_value = def.parse::<f64>().unwrap();
let sql = format!(
"`{}` decimal({},{}){} default {}",
self.field, max, self.dec, not_null, def_value
);
format!(
"{} comment '{}|{}|{}|{}|{}'",
sql, self.title, self.mode, self.require, self.dec, def_value
)
}
}
}
fn hide(&mut self) -> &mut Self {
self.show = false;
self
}
fn describe(&mut self, text: &str) -> &mut Self {
self.describe = text.to_string();
self
}
fn field(&mut self) -> JsonValue {
let mut field = object! {};
field
.insert("require", JsonValue::from(self.require))
.unwrap();
field
.insert("field", JsonValue::from(self.field.clone()))
.unwrap();
field
.insert("mode", JsonValue::from(self.mode.clone()))
.unwrap();
field
.insert("title", JsonValue::from(self.title.clone()))
.unwrap();
field.insert("def", JsonValue::from(self.def)).unwrap();
field.insert("dec", JsonValue::from(self.dec)).unwrap();
field.insert("show", JsonValue::from(self.show)).unwrap();
field
.insert("describe", JsonValue::from(self.describe.clone()))
.unwrap();
field.insert("example", self.example.clone()).unwrap();
field
}
fn swagger(&mut self) -> JsonValue {
object! {
"type": self.mode.clone(),
"example": self.example.clone(),
}
}
fn example(&mut self, data: JsonValue) -> &mut Self {
self.example = data.clone();
self
}
}