use chrono::{NaiveDate, NaiveDateTime};
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArrayField<T> {
base_type: String,
size: Option<usize>,
default: Option<Vec<T>>,
_phantom: PhantomData<T>,
}
impl<T> ArrayField<T> {
pub fn new(base_type: impl Into<String>) -> Self {
Self {
base_type: base_type.into(),
size: None,
default: None,
_phantom: PhantomData,
}
}
pub fn with_size(mut self, size: usize) -> Self {
self.size = Some(size);
self
}
pub fn with_default(mut self, default: Vec<T>) -> Self {
self.default = Some(default);
self
}
pub fn base_type(&self) -> &str {
&self.base_type
}
pub fn size(&self) -> Option<usize> {
self.size
}
pub fn sql_type(&self) -> String {
if let Some(size) = self.size {
format!("{}[{}]", self.base_type, size)
} else {
format!("{}[]", self.base_type)
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JSONBField {
default: Option<serde_json::Value>,
}
impl JSONBField {
pub fn new() -> Self {
Self { default: None }
}
pub fn with_default(mut self, default: serde_json::Value) -> Self {
self.default = Some(default);
self
}
pub fn sql_type(&self) -> &'static str {
"JSONB"
}
pub fn default(&self) -> Option<&serde_json::Value> {
self.default.as_ref()
}
}
impl Default for JSONBField {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HStoreField {
default: Option<std::collections::HashMap<String, String>>,
}
impl HStoreField {
pub fn new() -> Self {
Self { default: None }
}
pub fn with_default(mut self, default: std::collections::HashMap<String, String>) -> Self {
self.default = Some(default);
self
}
pub fn sql_type(&self) -> &'static str {
"HSTORE"
}
}
impl Default for HStoreField {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IntegerRangeField {
default: Option<(Option<i32>, Option<i32>)>,
}
impl IntegerRangeField {
pub fn new() -> Self {
Self { default: None }
}
pub fn with_default(mut self, lower: Option<i32>, upper: Option<i32>) -> Self {
self.default = Some((lower, upper));
self
}
pub fn sql_type(&self) -> &'static str {
"INT4RANGE"
}
}
impl Default for IntegerRangeField {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BigIntegerRangeField {
default: Option<(Option<i64>, Option<i64>)>,
}
impl BigIntegerRangeField {
pub fn new() -> Self {
Self { default: None }
}
pub fn with_default(mut self, lower: Option<i64>, upper: Option<i64>) -> Self {
self.default = Some((lower, upper));
self
}
pub fn sql_type(&self) -> &'static str {
"INT8RANGE"
}
}
impl Default for BigIntegerRangeField {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DateRangeField {
default: Option<(Option<NaiveDate>, Option<NaiveDate>)>,
}
impl DateRangeField {
pub fn new() -> Self {
Self { default: None }
}
pub fn with_default(mut self, lower: Option<NaiveDate>, upper: Option<NaiveDate>) -> Self {
self.default = Some((lower, upper));
self
}
pub fn sql_type(&self) -> &'static str {
"DATERANGE"
}
}
impl Default for DateRangeField {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DateTimeRangeField {
default: Option<(Option<NaiveDateTime>, Option<NaiveDateTime>)>,
}
impl DateTimeRangeField {
pub fn new() -> Self {
Self { default: None }
}
pub fn with_default(
mut self,
lower: Option<NaiveDateTime>,
upper: Option<NaiveDateTime>,
) -> Self {
self.default = Some((lower, upper));
self
}
pub fn sql_type(&self) -> &'static str {
"TSTZRANGE"
}
}
impl Default for DateTimeRangeField {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CITextField {
max_length: Option<usize>,
default: Option<String>,
}
impl CITextField {
pub fn new() -> Self {
Self {
max_length: None,
default: None,
}
}
pub fn with_max_length(mut self, max_length: usize) -> Self {
self.max_length = Some(max_length);
self
}
pub fn with_default(mut self, default: impl Into<String>) -> Self {
self.default = Some(default.into());
self
}
pub fn sql_type(&self) -> &'static str {
"CITEXT"
}
}
impl Default for CITextField {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_array_field_basic() {
let field = ArrayField::<i32>::new("INTEGER");
assert_eq!(field.base_type(), "INTEGER");
assert_eq!(field.sql_type(), "INTEGER[]");
}
#[test]
fn test_array_field_with_size() {
let field = ArrayField::<String>::new("VARCHAR(50)").with_size(10);
assert_eq!(field.size(), Some(10));
assert_eq!(field.sql_type(), "VARCHAR(50)[10]");
}
#[test]
fn test_jsonb_field() {
let field = JSONBField::new();
assert_eq!(field.sql_type(), "JSONB");
}
#[test]
fn test_jsonb_field_with_default() {
let default = serde_json::json!({"key": "value"});
let field = JSONBField::new().with_default(default.clone());
assert_eq!(field.default(), Some(&default));
}
#[test]
fn test_hstore_field() {
let field = HStoreField::new();
assert_eq!(field.sql_type(), "HSTORE");
}
#[test]
fn test_integer_range_field() {
let field = IntegerRangeField::new();
assert_eq!(field.sql_type(), "INT4RANGE");
}
#[test]
fn test_biginteger_range_field() {
let field = BigIntegerRangeField::new();
assert_eq!(field.sql_type(), "INT8RANGE");
}
#[test]
fn test_date_range_field() {
let field = DateRangeField::new();
assert_eq!(field.sql_type(), "DATERANGE");
}
#[test]
fn test_datetime_range_field() {
let field = DateTimeRangeField::new();
assert_eq!(field.sql_type(), "TSTZRANGE");
}
#[test]
fn test_citext_field() {
let field = CITextField::new();
assert_eq!(field.sql_type(), "CITEXT");
}
#[test]
fn test_citext_field_with_max_length() {
let field = CITextField::new().with_max_length(255);
assert_eq!(field.sql_type(), "CITEXT");
}
}