Да. Я скоро зайду домой и напишу. Сюда напишу, вдруг кому пригодится (НИНАДА ТАК)
Я написал макрос, который генерирует запросы в компайл-тайме и подаёт их sqlx. Потом я понял, что макросы sqlx тоже было бы использовать, но есть одно "но" - они не понимают кастомные типы(енамы), которые фетчат из базы и говорят, что error: unsupported type userrole for param $2. Для этого нужно ставить явные пропуски тайпчека через role as "role: _". Как я могу это сделать в своём процмакросе без информации о типах? Мне ведь ещё нужно соотвественно самому протайпчекать енамы за sqlx, что аргумент номер $n является енамом и если нет, выдать предупреждение при компиляции, как это делает sqlx для того, что тайпчекать умеет. sqlx для этого лезет в базу, я не могу(не умею и не хочу реимплементить их макросы целиком), как и не могу получить его выхлоп. А вот сходить в свой же проект по файловой системе за структурами и типами я могу... Вот и появилась идея перед компиляцией проиндексировать свой крейт через build.rs, потом в процмакросах вытащить типы и сделать нужное.
А точно не понимают? У меня вроде чекалось что-то
https://github.com/launchbadge/sqlx/issues/1004
Хм… так суть же в том, что для user defined типов как раз надо в базу ходить, ибо иначе ты никак не чекнешь правильное ли у тебя отображение на правильный тип.
С другой стороны, прочекав файлы и найдя в атрибутном макросе sqlx type_name="userrole", я буду знать название таблицы. В таком случае я могу сделать часть работы за sqlx, то есть всё таки сходить в базу за типами. Мне нужно получить их Describe, но у них в sqlx-macros всё приватное. Вариант только форкать, если хочу такую же инфу. Либо форкать sqlx-core ради connection.describe
Угу. Либо просто завозить эту фичу напрямую им)
? Какую, в каком смысле?
Всмысле контрибьютнуть им, чтоб их макрос умел то, что ты хочешь.
А как их макрос сможет залезть в использующий его крейт? Я-то сам у себя в воркспейсе.
Из вариантов только заставлять пользователей указывать OUT_DIR в свою директорию, либо другую ENV-переменную. Притом абсолютным путём, ибо target так же может быть перемещён и от него через "../../" не пойдёшь назад. Получится, ещё один фичафлаг которому нужна энв-вара, только ему нужен не DATABASE_URL, а CRATE_DIR какой-нибудь. К тому же давать парсить чужому крейту свой код... Да и на CI юзерам придётся эту переменную указывать для верной работы. Как и DATABASE_URL и ту штуку с оффлайном.
ну по идее если в макрос передавать имя своего типа + на самом типе будет дерайв чего-нибудь из sqlx то должно сработать
Если я правильно помню, во время работы макросов типы ещё не существуют, мне дерайв sqlx'а не поможет.
ну смотри, ты передаешь свой тип в макрос, тогда макрос сможет для него сгенерировать все что нужно. Единственная проблема - ты передаешь только имя типа, а макросу наверняка нужна метаинформация: какие там у него поля и т.п. Это решается дервайвом. Звучит как что-то рабочее
Я всё ещё не понимаю, как это решается дерайвом, если у меня function-like macro? Как я могу что-то извлечь из дерайва? Он на момент компиляции внешнего крейта ещё не раскроется даже. То, что я делаю с User::TABLE_NAME - эта константа сущестсвует на момент компиляции бинарника, но на момент компиляции процмакроса о ней ещё неизвестно же. Я не понимаю :(
если тлдр то авторы sqlx должны поддержать кастомные структуры. Тупо взять описание из БД, взять описание из кода и сравнить. Окей, для встроенных типов оно умеет так делать. Теперь нужно добавить поддержку произвольных. Пассаж про констант которых не существует немного не понял: макросы sqlx в юзеркоде раскрываются тогда когда он собирается. То есть обычно - в самом конце сборки. Соответственно он может конечно ссылаться на типы из юзерского конечного приложения
Вот я и не понимаю, как ссылаться на типы из конечного юзерского приложения :(
ну вот в примере выше есть же retrieve_one!(User, login="john"); - взяли и передали юзера, макрос дальше должен раскрыться как обычно и проверить его. Не понимаю в каком моменте затык) Возможно в sqlx это не реализовано - но это повод им ишшую завести чтобы они сделали
Затык с тем, что... а как проверить? Есть у меня Ident(User). И чо с ним делать?
ну а тут вступает в дело #[derive(SuperDuperMetadata)] struct Ident(User); Который должен сгенерировать все нужные для retreieve_one! функции на этом самом Ident(User)
Это же просто набор букв. И в макросе я работаю с ним как с набором букв. Слово такое, User, без типа и чего-то ещё. Известно что Ident. Я просто не понимаю, как мне получить доступ хоть к чему-то на этапе, когда код ещё представляет из себя набор букв.
Набор букв про который известно что у него есть функция возвращающая метаданные (навроде strum::VariantNames) уже становится чуть более полезным Я не знаю структуру sqlx сильно и макросы раста действительно довольно ограничены в плане получения метаданных, но что-то рабочее изобразить я думаю можно. В том же дотнете например для подобной работы используется конвертер, выбирается юзер-тип и на какой тип в БД маппить, ну и маппинги описыаются usertype <-> dbtype. Тогда движок просто при десерилаизации сначала маппит на известный ему тип а потом вызывает переданную лямбду и можно получить свой. Ну и в обратную сторону так же. Мб что-то в таком духе может сработать
Мне нужны конкретно что типы. Получить их так, чтобы использовать в макросе я не могу. Я могу задерайвить нечто и использовать знание, что "на той стороне" та функция уже будет существовать, как я уже делаю с TABLE_NAME. Но мне нужна именно подстановка в запрос. Если делать const VARIANTS - мне надо знать число аргументов, чтобы подставить тип как User::VARIANTS[0usize]. И расставить числа нужно опять таки процмакросом. Всё упирается в то, что мне нужно знать, что там у User написано в опредлении структуры, знать хотя бы порядок и число полей.
можно в том же дерайве нагенерировать алиас LOGIN = User::VARIANTS[0usize] и его использовать.
А что я буду делать с остальными типами? Да и о "LOGIN" я не буду знать - мне ж может прийти что угодно. Может мне придёт UserAttachment.
Обсуждают сегодня