#database #generics #rust #rust-diesel
#База данных #общие #Ржавчина #rust-дизель
Вопрос:
У меня есть функция, которая использует diesel для получения объекта из базы данных на основе заданного идентификатора:
fn get_db_site(pool: web::Data<Pool>, site_id: u32) -> Result<Site, diesel::result::Error> {
let conn = pool.get().unwrap();
dsl::site.find(site_id).get_result::<Site>(amp;conn)
}
Эта функция будет точно такой же для каждой таблицы, в которой я хочу ее запустить, поэтому я надеюсь поместить ее в собственный файл utils, чтобы мне не приходилось вводить одно и то же каждый раз. Единственная проблема заключается в том, что для вызова этой находки мне нужно сделать
crate::schema::site::dsl::site.find
и я не уверен, как я могу сделать этот вызов универсальным для любого типа. Я знаю, что есть аргументы типа, но я не думаю, что это сработает здесь
Ответ №1:
Обычно я не советую делать вещи diesel более универсальными, поскольку это довольно быстро приводит к действительно сложным границам признаков. Обычно вы никогда не захотите делать это в коде приложения. (Это другое дело для библиотек, которые должны быть универсальными). Обычно я сравниваю ситуацию с обычным SQL. Например, если кто-то жалуется, что это users::table.find(pk)
похоже на дублирование, задайте себе следующий вопрос: считаете ли вы, что это SELECT … FROM users
дублируется в соответствующем запросе SELECT … FROM users WHERE id = $
. (Оператор diesel dsl в основном тот же).
Итак, чтобы ответить на ваш актуальный вопрос, общие функции должны выглядеть примерно так: (Не уверен, правильно ли я определил все границы без тестирования)
fn get_db_thing<T, U, PK>(pool: web::Data<Pool>, primary_key: PK) -> Result<U, diesel::result::Error>
where T: Table HasTable<Table = T>,
T: FindDsl<PK>,
U: Queryable<SqlTypeOf<Find<T, PK>>, Pg>
{
let conn = pool.get().unwrap();
T::table().find(primary_key).get_result::<U>(amp;conn)
}
Как вы можете видеть, список границ признаков уже намного длиннее, чем просто загрузка, встроенная в соответствующие функции. Кроме того, все детали, добавленные при построении запроса, теперь будут требоваться в качестве аргумента универсальной функции. По крайней мере, тип для T
не может быть определен компилятором, поэтому с точки зрения размера кода это решение не «проще», чем просто не делать его универсальным.