-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added insert multiple rows support #8
Added insert multiple rows support #8
Conversation
Thanks for the PR! Looks good to me. This setup works if all the fields are of the same type - in the example all the fields are of the type let rows = vec![
vec![
("name", "Alice"),
("email", "[email protected]"),
("age", 21),
],
vec![("name", "Bob"), ("email", "[email protected]"), ("age", 22)],
];
let query = Eloquent::query().table("users").insert_many(rows);
assert_eq!(
query.sql().unwrap(),
"INSERT INTO users (name, email, age) VALUES ('Alice', '[email protected]' 21), ('Bob', '[email protected]', 22)"
); |
Hi, thank you for reviewing the PR and for raising this excellent point! To handle fields of mixed types we can update the implementation to use Box for the value type. The throwback will be the need to construct rows using Box::new() let rows = vec![
vec![
("name", Box::new("Alice") as Box<dyn ToSql>),
("email", Box::new("[email protected]") as Box<dyn ToSql>),
("age", Box::new(21) as Box<dyn ToSql>),
],
vec![
("name", Box::new("Bob") as Box<dyn ToSql>),
("email", Box::new("[email protected]") as Box<dyn ToSql>),
("age", Box::new(22) as Box<dyn ToSql>),
],
]; But we can introduce some kind of rows builder for simpler code. |
Thanks for adjustments. That works but I don't really like the wrapping in a Box and typing it every time with What do you think of this? Feel free to adjust. let rows = vec![
eloquent_sql_row! {
"name" => "Alice",
"email" => "[email protected]",
"age" => 21,
"is_active" => true,
},
eloquent_sql_row! {
"name" => "Bob",
"email" => "[email protected]",
"age" => 22,
"is_active" => false,
},
];
let query = Eloquent::query().table("users").insert_many(rows);
assert_eq!(
query.sql().unwrap(),
"INSERT INTO users (name, email, age, is_active) VALUES ('Alice', '[email protected]', 21, true), ('Bob', '[email protected]', 22, false)"
); and then in the #[macro_export]
macro_rules! eloquent_sql_row {
($($key:expr => $value:expr),* $(,)?) => {
vec![
$(($key, Box::new($value) as Box<dyn ToSql>)),*
]
};
} pub fn insert_many(mut self, rows: Vec<Vec<(&str, Box<dyn ToSql>)>>) -> Self {
rows.into_iter().for_each(|row| self.add_row(row));
self
}
fn add_insert(&mut self, column: &str, value: Box<dyn ToSql>) {
if let Some(insert) = self.inserts.iter_mut().find(|i| i.column == column) {
insert.values.push(value);
} else {
self.inserts.push(Insert {
column: column.to_string(),
values: vec![value],
});
}
}
fn add_row(&mut self, row: Vec<(&str, Box<dyn ToSql>)>) {
row.into_iter()
.for_each(|(column, value)| self.add_insert(column, value));
} I also did try this using a HashMap that does work but as the hash is different each time the order of the columns to be inserted is too - and that prevented me to get the assertion to work every time. |
Great suggestion!
#[macro_export]
macro_rules! eloquent_sql_row {
($($key:expr => $value:expr),* $(,)?) => {
vec![
$(($key, Box::new($value) as Box<dyn $crate::ToSql>)),*
]
};
}
|
Created validator that checks for equal number of values per column across inserts, prevents creating query with rows with different values. Please let me know if you want to adjust something! |
Thanks a lot. Nice addition! Will merge it. |
Updated
inserts
Field:value
property tovalues: Vec<Box<dyn ToSql>>
.Refactored
insert
Method:insert
method to store values in new property.Added
insert_many
Method:insert_many
method to handle bulk insertion of multiple rows.