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
use {
	crate::{
		executor::types::Row, Column, Error, Recipe, RecipeUtilities, Resolve, Result, SimplifyBy,
		ValueDefault, ValueType,
	},
	rayon::prelude::*,
	serde::Serialize,
	sqlparser::ast::Ident,
	thiserror::Error as ThisError,
};

#[derive(ThisError, Serialize, Debug, PartialEq)]
pub enum ValidateError {
	#[error("expected value for column which neither accepts NULL nor has a default")]
	MissingValue,
	#[error("wrong number of values in insert statement")]
	WrongNumberOfValues,
	#[error("default value failed to be calculated")]
	BadDefault,
	#[error("column '{0}' not found")]
	ColumnNotFound(String),
	#[error("found duplicate value on unique field")]
	//#[error("column '{0}' is unique but '{1:?}' was attempted to be stored twice")]
	DuplicateEntryOnUniqueField, /*(String, Value)*/

	#[error("this should be impossible, please report")]
	UnreachableUniqueValues,
}

pub fn columns_to_positions(column_defs: &[Column], columns: &[Ident]) -> Result<Vec<usize>> {
	if columns.is_empty() {
		Ok((0..column_defs.len()).collect())
	} else {
		columns
			.iter()
			.map(|stated_column| {
				column_defs
					.iter()
					.position(|column_def| stated_column.value == column_def.name)
					.ok_or_else(|| {
						ValidateError::ColumnNotFound(stated_column.value.clone()).into()
					})
			})
			.collect::<Result<Vec<usize>>>()
	}
}

pub fn validate(columns: &[Column], stated_columns: &[usize], rows: &mut Vec<Row>) -> Result<()> {
	if rows.iter().any(|row| row.len() != stated_columns.len()) {
		return Err(ValidateError::WrongNumberOfValues.into());
	}

	let column_info = columns
		.iter()
		.enumerate()
		.map(|(column_def_index, column)| {
			let index = stated_columns
				.iter()
				.position(|stated_column| stated_column == &column_def_index);

			let nullable = column.is_nullable || column.default.is_some();

			let failure_recipe = if let Some(ValueDefault::Recipe(expr)) = &column.default {
				Some(Recipe::new_without_meta(expr.clone())?)
			} else if nullable {
				Some(Recipe::NULL)
			} else {
				None
			};
			Ok((index, failure_recipe, nullable, &column.data_type))
		})
		.collect::<Result<Vec<(Option<usize>, Option<Recipe>, bool, &ValueType)>>>()?;
	*rows = rows
		.into_par_iter()
		.map(|row| {
			column_info
				.iter()
				.map(|(index, failure_recipe, nullable, data_type)| {
					let mut value = index
						.and_then(|index| row.get(index).cloned())
						.ok_or(Error::Validate(ValidateError::MissingValue))
						.and_then(|value| value.validate_null(*nullable).map(|_| value))
						.or_else(|_| {
							let recipe = failure_recipe
								.clone()
								.ok_or(Error::Validate(ValidateError::MissingValue))?;
							recipe
								.simplify(SimplifyBy::Basic)?
								.as_solution()
								.ok_or(Error::Validate(ValidateError::BadDefault))
						})?;

					value.is(data_type)?;
					Ok(value)
				})
				.collect::<Result<Row>>()
		})
		.collect::<Result<Vec<Row>>>()?;
	Ok(())
}