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
110
111
112
113
114
115
116
117
118
119
120
121
use {
	super::{JoinManual, JoinType},
	crate::{
		executor::{
			fetch::fetch_columns,
			types::{ColumnInfo, ComplexTableName},
			MetaRecipe,
		},
		Context, JoinError, Result, StorageInner,
	},
	std::cmp::Ordering,
};

#[derive(Debug)]
pub struct JoinPlan {
	pub database: String,
	pub table: String,
	pub columns: Vec<ColumnInfo>,
	pub join_type: JoinType,
	pub constraint: MetaRecipe,
	pub needed_tables: Vec<usize>,
}
impl PartialEq for JoinPlan {
	fn eq(&self, _other: &Self) -> bool {
		false
	}
}
impl Eq for JoinPlan {}
impl PartialOrd for JoinPlan {
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
		Some(self.join_type.cmp(&other.join_type))
	}
}
impl Ord for JoinPlan {
	fn cmp(&self, other: &Self) -> Ordering {
		self.join_type.cmp(&other.join_type)
	}
}

impl JoinPlan {
	pub async fn new<'a>(
		join_manual: JoinManual,
		storages: &Vec<(String, &mut StorageInner)>,
		context: &Context,
	) -> Result<Self> {
		let JoinManual {
			table,
			constraint,
			join_type,
		} = join_manual;
		let columns = get_columns(storages, table.clone(), context).await?;
		let ComplexTableName {
			database,
			name: table,
			..
		} = table;
		Ok(Self {
			database,
			table,
			join_type,
			columns,
			constraint,
			needed_tables: vec![],
		})
	}
	pub fn calculate_needed_tables(&mut self, table_columns: &Vec<Vec<ColumnInfo>>) {
		self.needed_tables = table_columns
			.iter()
			.enumerate()
			.filter_map(|(index, columns)| {
				if columns.iter().any(|table_column| {
					self.constraint
						.meta
						.objects
						.iter()
						.any(|constraint_column| {
							constraint_column
								.as_ref()
								.map(|constraint_column| table_column == constraint_column)
								.unwrap_or(false)
						})
				}) {
					Some(index)
				} else {
					None
				}
			})
			.collect()
	}
}

async fn get_columns(
	storages: &Vec<(String, &mut StorageInner)>,
	table: ComplexTableName,
	context: &Context,
) -> Result<Vec<ColumnInfo>> {
	if let Some((context_table_labels, ..)) = context.tables.get(&table.name) {
		Ok(context_table_labels
			.iter()
			.map(|name| ColumnInfo {
				table: table.clone(),
				name: name.clone(),
				index: None,
			})
			.collect::<Vec<ColumnInfo>>())
	} else {
		let storage = storages
			.into_iter()
			.find_map(|(name, storage)| {
				if name == &table.database {
					Some(&**storage)
				} else {
					None
				}
			})
			.or(storages.get(0).map(|(_, storage)| &**storage))
			.ok_or(JoinError::TableNotFound(table.clone()))?;

		fetch_columns(storage, table).await
	}
}