lezeh_db/psql/
relation_insert.rs1use std::collections::{HashMap, HashSet};
2use std::rc::Rc;
3
4use itertools::Itertools;
5
6use crate::psql::dto::FromSqlSink;
7use crate::psql::dto::PsqlTable;
8use crate::psql::dto::PsqlTableIdentity;
9use crate::psql::dto::PsqlTableRow;
10use lezeh_common::types::ResultAnyError;
11
12pub struct TableInsertStatement<'a> {
13 table: PsqlTable,
14 columns: TableInsertRowColumns<'a>,
15 row_values: Vec<TableInsertRowValues>,
16}
17
18impl<'a> std::fmt::Display for TableInsertStatement<'a> {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 return write!(
23 f,
24 indoc::indoc! {"
25 ------------------------------------------------
26 -- insert into table {}
27 ------------------------------------------------
28 insert into {} ({}) VALUES
29 {};
30 ---------------
31
32 "},
33 self.table.id,
34 self.table.id,
35 self.columns,
36 self
37 .row_values
38 .iter()
39 .map(|val| format!("{}", val))
40 .collect::<Vec<String>>()
41 .join(",\n"),
42 );
43 }
44}
45
46pub struct TableInsertRowColumns<'a> {
47 column_names: Vec<&'a str>,
48}
49
50impl<'a> std::fmt::Display for TableInsertRowColumns<'a> {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 let column_string: String = self
53 .column_names
54 .iter()
55 .map(|column_name| {
56 return format!("\"{}\"", column_name);
57 })
58 .collect::<Vec<String>>()
59 .join(", ");
60
61 return write!(f, "{}", column_string);
62 }
63}
64
65pub struct TableInsertRowValues {
66 values: Vec<String>,
67}
68
69impl std::fmt::Display for TableInsertRowValues {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 return write!(f, "({})", self.values.join(", "));
72 }
73}
74
75pub struct RelationInsert {}
76
77impl RelationInsert {
78 pub fn into_insert_statements(
79 mut rows_by_level: HashMap<i32, HashSet<&Rc<PsqlTableRow>>>,
80 ) -> ResultAnyError<Vec<String>> {
81 let mut levels: Vec<i32> = rows_by_level.keys().cloned().collect();
82 let mut insert_statement_map: HashMap<String, bool> = Default::default();
83
84 levels.sort();
85
86 let insert_statements: ResultAnyError<Vec<Vec<String>>> = levels
87 .iter()
88 .map(|level| {
89 let rows: &mut HashSet<_> = rows_by_level.get_mut(level).unwrap();
90
91 rows.retain(|row| {
92 let row_key = format!("{}.{}", row.table.id, row.row_id_representation);
93 let found = insert_statement_map.contains_key(&row_key);
94
95 insert_statement_map.insert(row_key, true);
96
97 return !found;
100 });
101
102 return RelationInsert::table_rows_into_insert_statement(rows);
103 })
104 .collect();
105
106 return Ok(insert_statements?.into_iter().flatten().collect());
107 }
108
109 pub fn table_rows_into_insert_statement(
110 rows: &HashSet<&Rc<PsqlTableRow>>,
111 ) -> ResultAnyError<Vec<String>> {
112 let psql_table_by_id: HashMap<PsqlTableIdentity, PsqlTable> = rows
117 .iter()
118 .map(|row| (row.table.id.clone(), row.table.clone()))
119 .collect();
120
121 let psql_rows_by_table_id: HashMap<PsqlTableIdentity, Vec<&Rc<PsqlTableRow>>> = rows
122 .iter()
123 .map(|psql_table_row| (psql_table_row.table.id.clone(), psql_table_row.clone()))
124 .into_group_map();
125
126 let rows_by_table_id: HashMap<PsqlTableIdentity, Vec<&Rc<PsqlTableRow>>> =
127 psql_rows_by_table_id
128 .into_iter()
129 .map(
130 |(table_identity, row): (PsqlTableIdentity, Vec<&Rc<PsqlTableRow>>)| {
131 return (table_identity, row);
132 },
133 )
134 .collect();
135
136 return rows_by_table_id
137 .iter()
138 .map(|(table_id, rows)| {
139 return RelationInsert::table_row_into_insert_statement(
140 psql_table_by_id.get(table_id).unwrap(),
141 rows,
142 );
143 })
144 .collect::<ResultAnyError<Vec<String>>>();
145 }
146
147 pub fn table_row_into_insert_statement(
148 table: &PsqlTable,
149 rows: &Vec<&Rc<PsqlTableRow>>,
150 ) -> ResultAnyError<String> {
151 let first_row: &PsqlTableRow = rows.get(0).unwrap();
152 let table_insert_row_columns = TableInsertRowColumns {
153 column_names: first_row.get_column_names(),
154 };
155
156 let row_values: Vec<TableInsertRowValues> = rows
157 .iter()
158 .map(|row| {
159 let column_value_map: HashMap<&str, FromSqlSink> = row.get_column_value_map();
160
161 return table_insert_row_columns
163 .column_names
164 .iter()
165 .map(|column_name| {
166 let from_sql_sink = column_value_map.get(column_name).unwrap();
167
168 return from_sql_sink.to_string_for_statement();
169 })
170 .collect::<ResultAnyError<Vec<String>>>()
171 .map(|values_in_string| {
172 return TableInsertRowValues {
173 values: values_in_string,
174 };
175 });
176 })
177 .collect::<ResultAnyError<Vec<TableInsertRowValues>>>()?;
178
179 let table_insert_statement = TableInsertStatement {
180 table: table.clone(),
181 columns: table_insert_row_columns,
182 row_values,
183 };
184
185 return Ok(format!("{}", table_insert_statement));
186 }
187}