|
1 | 1 | // Sync available crate categories from `src/categories.toml`.
|
2 | 2 | // Runs when the server is started.
|
3 | 3 |
|
| 4 | +use diesel; |
| 5 | +use diesel::prelude::*; |
4 | 6 | use toml;
|
5 | 7 |
|
6 | 8 | use db;
|
| 9 | +use schema::categories; |
7 | 10 | use util::errors::{CargoResult, ChainError, internal};
|
8 | 11 |
|
9 | 12 | #[derive(Debug)]
|
@@ -87,45 +90,54 @@ fn categories_from_toml(
|
87 | 90 | Ok(result)
|
88 | 91 | }
|
89 | 92 |
|
| 93 | +#[derive(Insertable)] |
| 94 | +#[table_name = "categories"] |
| 95 | +struct NewCategory { |
| 96 | + slug: String, |
| 97 | + category: String, |
| 98 | + description: String, |
| 99 | +} |
| 100 | + |
90 | 101 | pub fn sync() -> CargoResult<()> {
|
91 |
| - let conn = db::connect_now_old(); |
92 |
| - let tx = conn.transaction().unwrap(); |
| 102 | + use diesel::pg::upsert::*; |
| 103 | + use diesel::expression::dsl::any; |
| 104 | + |
| 105 | + let conn = db::connect_now().unwrap(); |
93 | 106 |
|
94 | 107 | let categories = include_str!("./categories.toml");
|
95 | 108 | let toml: toml::value::Table =
|
96 | 109 | toml::from_str(categories).expect("Could not parse categories.toml");
|
97 | 110 |
|
98 |
| - let categories = |
99 |
| - categories_from_toml(&toml, None).expect("Could not convert categories from TOML"); |
100 |
| - |
101 |
| - for category in &categories { |
102 |
| - tx.execute( |
103 |
| - "\ |
104 |
| - INSERT INTO categories (slug, category, description) \ |
105 |
| - VALUES (LOWER($1), $2, $3) \ |
106 |
| - ON CONFLICT (slug) DO UPDATE \ |
107 |
| - SET category = EXCLUDED.category, \ |
108 |
| - description = EXCLUDED.description;", |
109 |
| - &[&category.slug, &category.name, &category.description], |
110 |
| - )?; |
111 |
| - } |
112 |
| - |
113 |
| - let in_clause = categories |
114 |
| - .iter() |
115 |
| - .map(|category| format!("LOWER('{}')", category.slug)) |
116 |
| - .collect::<Vec<_>>() |
117 |
| - .join(","); |
118 |
| - |
119 |
| - tx.execute( |
120 |
| - &format!( |
121 |
| - "\ |
122 |
| - DELETE FROM categories \ |
123 |
| - WHERE slug NOT IN ({});", |
124 |
| - in_clause |
125 |
| - ), |
126 |
| - &[], |
127 |
| - )?; |
128 |
| - tx.set_commit(); |
129 |
| - tx.finish().unwrap(); |
130 |
| - Ok(()) |
| 111 | + let categories = categories_from_toml(&toml, None) |
| 112 | + .expect("Could not convert categories from TOML") |
| 113 | + .into_iter() |
| 114 | + .map(|c| { |
| 115 | + NewCategory { |
| 116 | + slug: c.slug.to_lowercase(), |
| 117 | + category: c.name, |
| 118 | + description: c.description, |
| 119 | + } |
| 120 | + }) |
| 121 | + .collect::<Vec<_>>(); |
| 122 | + |
| 123 | + let to_insert = categories.on_conflict( |
| 124 | + categories::slug, |
| 125 | + do_update().set(( |
| 126 | + categories::category.eq(excluded(categories::category)), |
| 127 | + categories::description.eq( |
| 128 | + excluded(categories::description), |
| 129 | + ), |
| 130 | + )), |
| 131 | + ); |
| 132 | + |
| 133 | + conn.transaction(|| { |
| 134 | + let slugs = diesel::insert(&to_insert) |
| 135 | + .into(categories::table) |
| 136 | + .returning(categories::slug) |
| 137 | + .get_results::<String>(&conn)?; |
| 138 | + |
| 139 | + let to_delete = categories::table.filter(categories::slug.ne(any(slugs))); |
| 140 | + diesel::delete(to_delete).execute(&conn)?; |
| 141 | + Ok(()) |
| 142 | + }) |
131 | 143 | }
|
0 commit comments