LINUX.ORG.RU

Проверки во время компиляции.

 , , ,


0

3

Предположим, что программа — интерфейс к БД. Насколько адекватно будет во время компиляции анализировать схему и на её основании генерировать классы, поля, контракты? Или хотя бы также (во время компиляции) проверять корректность написанных запросов.

Если неадекватно, то как правильно?

★★★★★
Ответ на: комментарий от anonymous

Зачем человеку, который компилирует приложение, знать пароли доступа к моей БД?

То есть тестовой базы у него тоже нет, разрабатывает он вслепую, а тестируешь результат разработки сам на своей базе. Это разве нормально?

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Даже elisp в байткоде не распространяется.

По лицензионным соображениям.

feofan ★★★★★
()
Ответ на: комментарий от monk

Ну раз проверка на ошибки происходит во время компиляции, то и перекомпилировать, очевидно, надо при изменении структуры базы. И никак иначе не выйдет.

anonymous
()
Ответ на: комментарий от monk

Он компилирует, а не разрабатывает. У него вообще кроме компилятора ничего нет и быть не должно.

anonymous
()
Ответ на: комментарий от anonymous

Он компилирует, а не разрабатывает.

А, прошу прощения, зачем? Разработчику компиляция нужна для тестирования. Заказчику — для выполнения программы (или должны точно совпадать процессор + среда лисп у разработчика и заказчика). А специальному человеку, который копирует с другой машины исходники, компилирует, и отдаёт на третью машину бинарники... а зачем там вообще человек?

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Ну раз проверка на ошибки происходит во время компиляции, то и перекомпилировать, очевидно, надо при изменении структуры базы.

Именно проверку ошибок (соответствие типов полей) можно и во время выполнения сделать. Но смысла нет. Если при компиляции такая проверка работает как облегчённый вариант статической типизации (нет необходимости проверять на опечатки все возможные запросы), то во время выполнения у заказчика уже неважно, среда тебе ошибку кинет или СУБД, разработчика уже нет за консолью.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Ну то есть проблем в такой перекомпиляции нет. Тогда непонятно в чем проблема и смысл треда? Я думал ты хочешь, чтобы были компайл-тайм проверки без перекомпиляции.

anonymous
()
Ответ на: комментарий от anonymous

Тогда непонятно в чем проблема и смысл треда?

Смысл — понять, почему такой метод не пользуется популярностью. Несколько раз из разных источников читал, что крайне желательно, чтобы экспанд макроса являлся чистой функцией.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Смысл — понять, почему такой метод не пользуется популярностью.

Потому что вещества вредны для здоровья.

archimag ★★★
()
Ответ на: комментарий от monk

Смысл — понять, почему такой метод не пользуется популярностью.

А с чего ты решил что не пользуется? Вон те же тайп-провайдеры.

anonymous
()
Ответ на: комментарий от anonymous

Смысл — понять, почему такой метод не пользуется популярностью.

Вон те же тайп-провайдеры.

В F# ? Я же про лисп спрашиваю. Или дай ссылку на пример тайп-провайдера на любом лиспе.

monk ★★★★★
() автор топика
Ответ на: комментарий от archimag

Потому что вещества вредны для здоровья.

Можно развернуть мысль? Или опять «мне это не нравится, значит так делать нельзя!» ?

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Ну раз проверка на ошибки происходит во время компиляции

Это смотря, что считать ошибкой. Отсутсвие валидного результата по запросу на этапе компиляции (например, просишь что-то по связанному primary_key, а данных еще нет) или несовпадение с существующей сигнатурой таблицы. В первом случае всегда обмазываются исключениями, второй случай редчайшая редкость, скорее всего связанная с нетипичной ситуацией, когда у базы много администраторов, активно меняющих ее структуру. Но даже при таком условии - ты можешь просто почаще синхронизироваться на тестовом сервере.

то и перекомпилировать, очевидно, надо при изменении структуры базы. И никак иначе не выйдет.

А кто как не разраб (или разраб в связке с архитектором бд) в курсе изменений базы? Имхо все норм.

alienclaster ★★★
()
Ответ на: комментарий от monk

Именно проверку ошибок (соответствие типов полей) можно и во время выполнения сделать.

Зачем? :)

Но смысла нет.

Вот именно.

Если при компиляции такая проверка работает как облегчённый вариант статической типизации

Опа-па, оказывается кому-то кроме меня нужны внешние настраиваемые статические чекеры для (частей) динамического языка :)

нет необходимости проверять на опечатки все возможные запросы

Почему? Есть.

то во время выполнения у заказчика уже неважно, среда тебе ошибку кинет или СУБД, разработчика уже нет за консолью.

Если боевая и тестовая база синхронизированы по структуре - никаких ошибок не может быть даже теоретически.

alienclaster ★★★
()
Ответ на: комментарий от monk

Смысл — понять, почему такой метод не пользуется популярностью.

Если не ошибаюсь, Ritmik говорил, что в Clojure, а точнее в sqlkorma и каком-то там редакторе (http://www.chris-granger.com/lighttable/ что ле), есть «интеллисенс» на тему существующих полей и параметров бд в запросе sql-dsl и что-то еще по мелочам. Должно быть удобно.

alienclaster ★★★
()
Ответ на: комментарий от alienclaster

А кто как не разраб (или разраб в связке с архитектором бд) в курсе изменений базы?

База не наша, а от другого проекта. Поэтому надо сверять. Ну например, надо сделать сверку по остаткам из 1С и SAP (и то и другое лежит в SQL). Есть структура БД на момент разработки, но нет гарантии, что при обновлении поля не переименуются, например. Соответственно нужен контроль схемы либо при каждом запуске, либо при компиляции (как в C# Linq).

monk ★★★★★
() автор топика
Ответ на: комментарий от alienclaster

Опа-па, оказывается кому-то кроме меня нужны внешние настраиваемые статические чекеры для (частей) динамического языка :)

Не смотрел метаданные clojure?

feofan ★★★★★
()
Ответ на: комментарий от alienclaster

Если боевая и тестовая база синхронизированы по структуре - никаких ошибок не может быть даже теоретически.

База у заказчика может меняться.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

База не наша, а от другого проекта. Поэтому надо сверять.

Ну вы же с ней все равно работаете в тестовом окружении. И, соответственно, синхронизируетесь. Или ты о том, что _структура_ меняется достаточно часто, и при очередном изменении на продакшн сервере посыпятся ошибки? Ну, тогда, во-первых это уже будут ошибки в рантайме, а во-вторых придется писать триггер на автоматическую синхронизацию структуры базы и имен таблиц / полей, и даже возможную автоматическую перекомпиляцию, да.

Есть структура БД на момент разработки, но нет гарантии, что при обновлении поля не переименуются, например. Соответственно нужен контроль схемы либо при каждом запуске, либо при компиляции (как в C# Linq).

При запуске, а лучше по факту самого изменения, если нет каких-то специальных ограничений.

alienclaster ★★★
()
Ответ на: комментарий от feofan

Не смотрел метаданные clojure?

Здесь походу немного другое, в метаданные можно запихнуть тип и что-то еще (например что?), для той же автоподстановки действительных полей таблицы нужно нечто большее - доступ к слепку структуры бд и, скорее всего, поддержка со стороны ide.

alienclaster ★★★
()
Ответ на: комментарий от alienclaster

Для данной конкретной задачи это неприменимо, да. Я у тебя в общем поинтересовался =)

в метаданные можно запихнуть тип и что-то еще (например что?)

Тут сказано, что кроме типов можно добавить мало полезного. Но можно придумать свои теги и делать что-то в зависимости от них.

feofan ★★★★★
()
Последнее исправление: feofan (всего исправлений: 1)
Ответ на: комментарий от alienclaster

по факту самого изменения, если нет каких-то специальных ограничений

Примерно это я и пытаюсь решить проверкой при компиляции. Фактически, после обновления БД заказчик запускает компиляцию клиента. При этом по всем запросам пройдут проверки на наличие полей + в некоторых местах исправятся преобразования типов (изменение длины поля или смена с TEXT на VARCHAR не должна ломать код).

Для проверки при запуске придётся куда-то занести все используемые запросы. Хотя можно (sql expr) -> (progn (pushnew expr *sqls*) (real-sql expr)) и при загрузке проверять все запросы упомянутые в программе. + 1% потерь времени на выбор преобразования типов в момент перед выполнением запроса.

Решение с проверкой во время компиляции мне показалось красивее.

monk ★★★★★
() автор топика
Ответ на: комментарий от feofan

Тут сказано, что кроме типов можно добавить мало полезного. Но можно придумать свои теги и делать что-то в зависимости от них.

Ну да, каменты любовнице понаписать. А вообще с метаданными все ясно: от состояний-то (загрязнился-нет, сериализуем-нет, любовь-нелюбовь) где-то хранить нужно в чистом языке. Вот часть «объекта» делают немутируемым и с STM, а всю «мета»-информацию по-старинке в изменяемый контейнер :)

alienclaster ★★★
()
Ответ на: комментарий от monk

При этом по всем запросам пройдут проверки на наличие полей + в некоторых местах исправятся преобразования типов (изменение длины поля или смена с TEXT на VARCHAR не должна ломать код).

Это мечты или уже что-то написано? :)

Для проверки при запуске придётся куда-то занести все используемые запросы

Поясни.

Решение с проверкой во время компиляции мне показалось красивее.

Тогда неизбежно придется писать «триггер», систему автоматической перекомпиляции, короче.

alienclaster ★★★
()
Ответ на: комментарий от alienclaster

Это мечты или уже что-то написано? :)

Пока в таком стиле написан биндинг к GTK. На стадии компиляции вытаскивается информация о типах параметров, а потом в нужных местах делается coerce float, coerce double, преобразование символ->строка или кейворд->число + контроль количества параметров в обработчике сигнала. Недостаток: после обновления GTK надо перекомпилировать.

БД — больше для примера.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Или дай ссылку на пример тайп-провайдера на любом лиспе.

Понятие тайппровайдера очевидно неприменимо, так как типов в лиспе нету. Ну а в CL например сделать eval at compile на ту штуку с mop и будут у тебя классы для базы генериться во время компиляции.

anonymous
()
Ответ на: комментарий от anonymous

например сделать eval at compile на ту штуку с mop и будут у тебя классы для базы генериться во время компиляции

Так почему такое никто не сделал? У C# есть linq к SQL, XML, парсерам... А в CL не припомню ни одного такого проекта. Даже xml читают как на C++, а не в стиле

(defvar *context* (load-xml "persons.xml"))


(iter (for i in (person *context*))
    (collect (list (name i) (surname i)))

хотя, казалось бы, что мешает...

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

хотя, казалось бы, что мешает...

Если не затрагивать вопросы, зачем это вообще надо и в чём профит, то есть такое простое соображение, что существующая инфраструктура CL, так сказать, первичного уровня. Для того же xml есть явная проблема с библиотеками (скажем, cxml имеет уродский дизайн). Что бы строить библиотеки более высокого уровня надо иметь базу, а с базой плохо. Ну а под конкретный свой проект делать какое-то «навороченное» решение с нуля просто не рационально.

archimag ★★★
()

Схему запущенной где-то базы? Совсем не адекватно. По причине того что в реальности может быть другая база.

Если неадекватно, то как правильно?

Если хочешь что-то генерировать из схемы - положи схему в проект. Если предполагается развертывание с пустой базой, а не подключение к существующей - создавай структуру программой.

r ★★★★★
()
Ответ на: комментарий от r

Схему запущенной где-то базы? Совсем не адекватно. По причине того что в реальности может быть другая база.

Почему где-то? Там, где будет использоваться программа

Если хочешь что-то генерировать из схемы - положи схему в проект

А если схема известна частично?

Вот пример из F#:

type private EntityConnection = SqlEntityConnection<ConnectionString="Server=SERVER\InstanceName;Initial Catalog=School;Integrated Security=SSPI;MultipleActiveResultSets=true", Pluralize = true>
 >

let context = EntityConnection.GetDataContext()

query { for person in context.People do
        select person }
|> Seq.iter (fun person -> printfn "%s %s" person.FirstName person.LastName)

Как предлагаешь такое делать в CL? Руками defclass и аккуратно переписывать руками типы из describe table People? Причём у пользователя типы могут быть другие, точно известно только то, что они преобразуются в строку, то есть VARCHAR/CHAR/TEXT (OR NULL). Или, как предлагали внешней командой

$ generate-schema > schema.lisp
а потом уже подключать созданный файл? А чтобы пользователь мог запустить, то писать инсталлятор...

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

хотя, казалось бы, что мешает...

Как правильно архимаг сказал - под лиспы и так библиотек раз два и обчелся, а ты хочешь чтобы оно еще и с блекджеком и шлюхами было.

anonymous
()
Ответ на: комментарий от monk

Как предлагаешь такое делать в CL? Руками defclass и аккуратно переписывать руками типы из describe table People?

Ну напиши сам макрос, который в нужные дефклассы раскроется. Делов-то на 20 строк.

anonymous
()
Ответ на: комментарий от anonymous

Ну напиши сам макрос, который в нужные дефклассы раскроется. Делов-то на 20 строк.

Делать нормально — чуть больше. Точнее не так. Делать единоразово под свою задачу — быстро. Делать так, чтобы могли воспользоваться другие — хочу понять, надо ли оно кому-то кроме меня.

Похоже, не надо.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Мне идея понравилась, но для своего проекта я выбрал clojure (ввиду наличия библиотек предметной области), а проект обещает занять меня надолго. Думаю найдутся люди, желающие поддержать ваше начинание.

feofan ★★★★★
()
Ответ на: комментарий от monk

Чтобы имело смысл раскрываться макросом в объявления о структуре бд, надо сначала сделать нормальный ОRM.

anonymous
()
Ответ на: комментарий от anonymous

надо сначала сделать нормальный ОRM

Так есть hu.dwim.perec

Вот описание:
http://pinterface.livejournal.com/35935.html
http://lichteblau.blogspot.ru/2009/08/cl-perec-blog-series-by-pinterface.html

Вот его порт на Allegro + Oracle:
http://src.knowledgetools.de/tomas/porting/

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Почему где-то? Там, где будет использоваться программа

Ее что - «собирать» будут перед каждым запуском?

Как предлагаешь такое делать в CL? Руками defclass и аккуратно переписывать руками типы из describe table People?

Зачем тебе это надо? Есть варианты:
1. Есть структура бд, есть твоя логика которая работает с конкретными полями этой бд. Следовательно ты рассчитываешь что они должны быть. Следовательно это статические требования твоей программы - могут лежать в твоей программе. Все что она может это проверить что если подключаемая база не соответствует требованиями - обматерить пользователя.

2. Есть структура БД. Есть твое ядрор которой наплевать на структуру БД (пример - phpmyadmin). Следовательно она должна в рантайме читать метаданныё и работать с ними.

3. Есть структура, тебе надо часть полей. Остальные твоя программа не обрабатывает. Ну и наплевать - реляционная база позволяет работать с конкретными полями вне зависимости от их количества. Если там конечно будут констрейнты которыё твоя прога не учитывает то ты попал - но сделать ты ничего не можешь.

4. Есть структура, тебе надо часть, остальные поля твоя прога обрабатывает неким обобщенным способом. Ну так и сделай - есть фиксированная схема которая учитывает что часть может поменятся, и будет обрабатываться определенным обобщенным подходом но если отсутствует другая часть - жутко ругаться.

а потом уже подключать созданный файл?

А если тебя подключили вообще к левой херне?
Нафига тебе дефинишены полей с которыми ты вообще не работаешь?

r ★★★★★
()
Последнее исправление: r (всего исправлений: 1)
Ответ на: комментарий от r

Ее что - «собирать» будут перед каждым запуском?

При установке. И при обновлении структуры БД. Также как запускают autoconf/automake (при установке или обновлении дистрибутива).

Есть структура, тебе надо часть полей. Остальные твоя программа не обрабатывает.

Обработка полей зависит от их типа в БД. В большинстве ORM'ов (clsql, perec, postmodern) эта обработка задаётся полем слота класса.

Нафига тебе дефинишены полей с которыми ты вообще не работаешь?

Максимум, пара тысяч символов сильно нагрузят лисп-образ? И если так подходить, то нафига мне в CL: over 900 символов, из которых в программе используется максимум сто.

Про framework'и я уж не говорю...

P.S. Согласен, что имена полей разумно указывать в коде, с точки зрения очевидности для читателя, откуда взялся символ. Остаётся вытаскивание типов для подключения правильных трансляторов.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

При установке.

RDBMS - другая программа. Ее структура - вообще пользовательская настройка. Ты пишешь программу которая рассчитывает на исключительноспециичную настройку другой программы и выдвигает условием «она никогда не будет менятся»?

Также как запускают autoconf/automake (при установке или обновлении дистрибутива).

ИМенно эпические звездецы к которым это приводило при обновлении/изменении других частей породил пакетне менджеры с зависимостями.

Обработка полей зависит от их типа в БД.

Ты пишешь ORM? «Обработка» - слово очень общее. Что оно с ними делает. Показывает как phpmyadmin или зарплату считает?

Максимум, пара тысяч символов сильно нагрузят лисп-образ?

Поинт был не в этом. Не мешают и ладно.

Все просто. RDBMS - внешняя система со своим жизненным циклом. Если она может быть изменена без участия твоей программы - значит генерировать что-то из нее - глупая идея.

r ★★★★★
()
Ответ на: комментарий от r

Ты пишешь ORM? «Обработка» - слово очень общее. Что оно с ними делает. Показывает как phpmyadmin или зарплату считает?

У меня задача такая: соединяеюсь к двум БД (возможно потом больше), созданным разными учётными системами. Затем вытаскиваю список объектов из каждой и сравниваю данные. Условно, сравниваю, что «зарплата» везде введена одинаковая. Соответствие поле объекта — поле БД учётные системы умеют выдавать. Имена полей меняются крайне редко, а вот типы определяются движками этих учётных систем (то есть float в double или varchar в text может преобразоваться просто изменением длины поля в настройках).

Фактически, после обновления любой учётной системы пользователь должен мочь щелкнуть какую-нибудь кнопку и программа должна сказать «ОК, работаем дальше» или «Зовите программиста, БД сильно поменялась» (если вдруг исчезла таблица или поле из используемых).

Так вот, в существующих ORM тип в классе обязателен. Ну, или не писать классы, а просто получать таблицы из SQL-запросов...

Идея с генератором мне не нравится тем, что процесс компиляции становится трудно автоматизируемым. С макросом просто: asdf:load-system и готово. А с файлом, надо в asdf добавить проверку на существование файла и его создание, в случае необходимости. Причём для создания часть программы уже должна быть скомпилирована (в которой прописано, как открывать БД). Боюсь, что будет хрупко. Хотя, скорее всего, просто не хватает опыта по написанию сложных систем для asdf

monk ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.