multisql/executor/alter_row/
validate_unique.rs1use {
2 crate::{Column, Glue, NullOrd, Result, Row, ValidateError, Value},
3 std::cmp::Ordering,
4};
5
6macro_rules! some_or_continue {
7 ($option: expr) => {
8 match $option {
9 Some(value) => value,
10 None => return Some(Ok(())),
11 }
12 };
13}
14macro_rules! some_or {
15 ($option: expr, $or: block) => {
16 match $option {
17 Some(value) => value,
18 None => $or,
19 }
20 };
21}
22
23impl Glue {
24 pub(crate) async fn validate_unique(
25 &self,
26 database: &Option<String>,
27 table_name: &str,
28 column_defs: &[Column],
29 rows: &[Row],
30 ignore_keys: Option<&[Value]>,
31 ) -> Result<()> {
32 let unique_columns: Vec<usize> = column_defs
33 .iter()
34 .enumerate()
35 .filter_map(|(index, column_def)| {
36 if column_def.is_unique {
37 Some(index)
38 } else {
39 None
40 }
41 })
42 .collect();
43 let mut existing_values: Vec<Vec<Value>> = vec![vec![]; unique_columns.len()];
44 self.get_database(database)?
45 .scan_data(table_name)
46 .await?
47 .into_iter()
48 .try_for_each::<_, Result<_>>(|(key, row)| {
49 if let Some(ignore_keys) = ignore_keys {
50 if ignore_keys.iter().any(|ignore_key| ignore_key == &key) {
51 return Ok(());
52 }
53 }
54 let row = row.0;
55 unique_columns
56 .iter()
57 .enumerate()
58 .map(|(index, row_index)| {
59 existing_values
60 .get_mut(index)?
61 .push(row.get(*row_index)?.clone());
62 Some(())
63 })
64 .collect::<Option<()>>()
65 .ok_or_else(|| ValidateError::UnreachableUniqueValues.into())
66 })?;
67
68 let mut new_values: Vec<Vec<Value>> = vec![vec![]; unique_columns.len()];
69 rows.iter().try_for_each::<_, Result<_>>(|row| {
70 unique_columns
71 .iter()
72 .enumerate()
73 .map(|(index, row_index)| {
74 new_values
75 .get_mut(index)?
76 .push(row.0.get(*row_index)?.clone());
77 Some(())
78 })
79 .collect::<Option<()>>()
80 .ok_or_else(|| ValidateError::UnreachableUniqueValues.into())
81 })?;
82 let mut existing_values_iter = existing_values.into_iter();
83 new_values
84 .into_iter()
85 .map(|mut new_values| {
86 let mut existing_values = existing_values_iter.next()?;
87
88 existing_values.sort_unstable_by(|value_l, value_r| {
89 value_l.partial_cmp(value_r).unwrap_or(Ordering::Equal)
90 });
91 new_values.sort_unstable_by(|value_l, value_r| {
92 value_l.partial_cmp(value_r).unwrap_or(Ordering::Equal)
93 });
94
95 let mut existing_values = existing_values.into_iter();
96 let mut new_values = new_values.into_iter();
97
98 let mut new_value = some_or_continue!(new_values.next());
99 let mut existing_value = some_or!(existing_values.next(), {
100 loop {
101 let new_new = some_or_continue!(new_values.next());
102 if new_new == new_value {
103 return Some(Err(ValidateError::DuplicateEntryOnUniqueField.into()));
104 }
105 new_value = new_new;
106 }
107 });
108
109 loop {
110 match existing_value.null_cmp(&new_value) {
111 Some(Ordering::Equal) => {
112 return Some(Err(ValidateError::DuplicateEntryOnUniqueField.into()))
113 }
114 Some(Ordering::Greater) => {
115 let new_new = some_or_continue!(new_values.next());
116 if new_new == new_value {
117 return Some(
118 Err(ValidateError::DuplicateEntryOnUniqueField.into()),
119 );
120 }
121 new_value = new_new;
122 }
123 Some(Ordering::Less) => {
124 existing_value = some_or!(existing_values.next(), {
125 loop {
126 let new_new = some_or_continue!(new_values.next());
127 if new_new == new_value {
128 return Some(Err(
129 ValidateError::DuplicateEntryOnUniqueField.into(),
130 ));
131 }
132 new_value = new_new;
133 }
134 });
135 }
136 None => {
137 let new_new = some_or_continue!(new_values.next());
138 if new_new == new_value {
139 return Some(
140 Err(ValidateError::DuplicateEntryOnUniqueField.into()),
141 );
142 }
143 new_value = new_new;
144 existing_value = some_or!(existing_values.next(), {
145 loop {
146 let new_new = some_or_continue!(new_values.next());
147 if new_new == new_value {
148 return Some(Err(
149 ValidateError::DuplicateEntryOnUniqueField.into(),
150 ));
151 }
152 new_value = new_new;
153 }
154 });
155 }
156 }
157 }
158 })
159 .collect::<Option<Result<()>>>()
160 .ok_or(ValidateError::UnreachableUniqueValues)?
161 }
162}