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
use {
	crate::{Convert, Result, Value, ValueError},
	std::cmp::min,
};

macro_rules! protect_null {
	($protect: expr) => {
		if matches!($protect, Value::Null) {
			return Ok($protect);
		}
	};
}

impl Value {
	pub fn if_null(self, alternative: Self) -> Self {
		if !matches!(self, Value::Null) {
			self
		} else {
			alternative
		}
	}
	pub fn null_if(self, evaluate: Self) -> Result<Self> {
		Ok(if self == evaluate { Value::Null } else { self })
	}
	pub fn iif(self, case_true: Self, case_false: Self) -> Result<Self> {
		Ok(if self.convert()? {
			case_true
		} else {
			case_false
		})
	}

	pub fn to_uppercase(self) -> Result<Self> {
		protect_null!(self);
		let string: String = self.convert()?;
		Ok(string.to_uppercase().into())
	}
	pub fn to_lowercase(self) -> Result<Self> {
		protect_null!(self);
		let string: String = self.convert()?;
		Ok(string.to_lowercase().into())
	}
	pub fn left(self, length: Value) -> Result<Value> {
		protect_null!(self);
		protect_null!(length);
		let length: i64 = length.convert()?;
		if length < 0 {
			return Err(ValueError::BadInput(length.into()).into());
		}
		let length: usize = length as usize;
		let string: String = self.convert()?;

		let truncated = string
			.get(..length)
			.map(|result| result.to_string())
			.unwrap_or(string);
		Ok(Value::Str(truncated))
	}
	pub fn right(self, length: Value) -> Result<Value> {
		protect_null!(self);
		protect_null!(length);
		let length: i64 = length.convert()?;
		if length < 0 {
			return Err(ValueError::BadInput(length.into()).into());
		}
		let length: usize = length as usize;
		let string: String = self.convert()?;

		let truncated = string
			.get(string.len() - min(string.len(), length)..)
			.map(|result| result.to_string())
			.unwrap_or(string);
		Ok(Value::Str(truncated))
	}
	pub fn length(self) -> Result<Value> {
		let string: String = self.convert()?;
		Ok(Value::I64(string.len() as i64))
	}

	pub fn concat(self, strings: Vec<Value>) -> Result<Value> {
		strings
			.into_iter()
			.try_fold(self, |all, this| all.string_concat(this))
	}

	pub fn replace(self, from: Value, to: Value) -> Result<Value> {
		protect_null!(self);
		let string: String = self.convert()?;
		let from: String = from.convert()?;
		let to: String = to.convert()?;

		Ok(string.replace(&from, &to).into())
	}

	pub fn round(self, places: Value) -> Result<Value> {
		if matches!(self, Value::Null) {
			return Ok(self);
		}
		let value: f64 = self.convert()?;
		let places: i64 = places.convert()?;
		let raiser: f64 = 10_u32.pow(places as u32).into();
		Ok(Value::F64((value * raiser).round() / raiser))
	}
	pub fn pow(self, power: Value) -> Result<Value> {
		let value: f64 = self.convert()?;
		let power: f64 = power.convert()?;
		Ok(Value::F64(value.powf(power)))
	}
}