ASDF Style ver. 1.02 Стиль ASDF включает в себя набор соглашений, использование которых позволяет решать некоторые вопросы magically и упрошает написание и поддержку программ. Некоторые соглашения "прошиты" в коде модулей и нарушение этих соглашений нарушает корректную работу этих модулей. ******************************************************************************* 1) В каждой таблице первое поле определено как PRIMARY KEY. 2) Автоматический JOIN таблиц только по PRIMARY KEY. 3) Имена полей в таблице начинаются на [a-z_] и не содержат "-" или "__". 4) Поля в таблице начинающиеся на "_" считаются вычисляемыми, а не устанавливаемыми пользователем. 5) Поля _cdate и _mdate устанавливаются автоматически. 6) Параметры cgi, в которых задается значение для поля таблицы называются так-же, как это поле (возможно, с добавлением "__функция" к имени поля), а остальные параметры cgi начинаются с [A-Z]. 7) Имена файлов строятся по принципу Группа+Тип. 8) В каждой таблице содержащей записи принадлежащие другой записи из другой таблицы должно быть поле - id той записи. 9) Несколько значений принимается только для полей содержащих "__функция" или для управляющих ключей (начинающихся на "-"). 10) ENUM поля делать NOT NULL. Добавлять явно в ENUM поля вариант "". 11) Имена функций используемых как "__функция" не должны начинаться на "_". ******************************************************************************* СОГЛАШЕНИЕ N 1 В каждой таблице первое поле определено как PRIMARY KEY. МОТИВАЦИЯ Модуль POWER::SQL использует упрощенный анализ структуры таблиц и считает первое поле PRIMARY KEY. Это (теоретически) ускоряет анализ и упрощает код POWER::SQL. Кроме этого, в данный момент не понятно, как должны работать $dbh->ID() и автоматический JOIN нескольких таблиц, если PRIMARY KEY состоит не из одного поля или его вообще нет в таблице. РЕАЛИЗАЦИЯ В модуле POWER::SQL. ******************************************************************************* СОГЛАШЕНИЕ N 2 Две таблицы всегда связываются (JOIN) по полю, которое является хотя-бы в одной из них PRIMARY KEY и называется одинаково в обоих таблицах. Приоритет имеет ключ правой таблицы. Если связывается более двух таблиц, то каждая таблица начиная со второй пытается подключиться по очереди ко всем предыдущим таблицам до нахождения первой связи. Если связь найти не удалось, то связываемая таблица исключается из запроса. МОТИВАЦИЯ Модуль POWER::SQL magically связывает все участвующие в запросе таблицы, и данное соглашение определяет единственный способ связать любую комбинацию таблиц. РЕАЛИЗАЦИЯ В модуле POWER::SQL. ******************************************************************************* СОГЛАШЕНИЕ N 3 В таблице не должно быть полей, содержаших в имени "-" или "__". МОТИВАЦИЯ В POWER::SQL все необходимые для составления SQL-запроса данные передаются в одном хеше (для простоты). Для определения частей SQL-запроса "ORDER BY" и "GROUP BY" используются ключи этого хеша {-order} и {-group}. И если в таблице есть поля с такими-же именами, доступ к ним через POWER::SQL оказывается невозможен. Кроме этого, в POWER::SQL иногда нужно передавать плюс к имени поля и его значению дополнительную информацию - функцию, которую нужно применить к этому полю. Эта информация сейчас храниться в имени поля отделенная через "__". Далее, POWER::SQL в некоторых случаях генерирует alias к полю. Для того, чтобы не перекрыть alias-ом существующее поле, в alias-е будет использоватся "__" (например "count(*) as __count"). РЕАЛИЗАЦИЯ В модуле POWER::SQL. ******************************************************************************* СОГЛАШЕНИЕ N 4 Поля в таблице начинающиеся на "_" являются не устанавливаемыми, а вычисляемыми (пользователь не имеет права передать напрямую значение для таких полей). МОТИВАЦИЯ Модуль POWER::SQL проектировался таким образом, чтобы в него можно было безопасно передавать любые введенные пользователем параметры. Но в случае с полями типа "balance" это не приемлемо - информацию в таких полях должна вычислять и изменять программа, и установка этих полей в любое заданное пользователем значение не приемлемо. РЕАЛИЗАЦИЯ Один из вариантов - игнорировать все переданные пользователем в CGI параметры, начинающиеся на "_", а значения для таких полей вычислять используя другие параметры CGI. В модуле POWER::SQL поля начинающиеся на "_" обрабатываются как обычные поля. ******************************************************************************* СОГЛАШЕНИЕ N 5 Если в таблице есть поля с именами _cdate и _mdate то они будут автоматически устанавливаться в дату создания записи и дату изменения записи функциями $dbh->Insert(), $dbh->Update() и $dbh->Replace(). МОТИВАЦИЯ Автоматизирование типичной задачи по аналогии с ctime и mtime в файловой системе. РЕАЛИЗАЦИЯ В модуле POWER::SQL. ******************************************************************************* СОГЛАШЕНИЕ N 6 Параметры cgi, в которых задается значение для поля таблицы называются так-же, как это поле (возможно, с добавлением "__функция" к имени поля), а остальные параметры cgi начинаются с [A-Z]. МОТИВАЦИЯ Модуль POWER::SQL проектировался таким образом, чтобы в него можно было безопасно передавать любые введенные пользователем параметры. Если формат параметров cgi совпадают с форматом параметров POWER::SQL, то появляется возможность передавать в POWER::SQL все принятые от пользователя параметры без перечисления имен конкретных полей. Но если cgi будет использовать в своих целях параметр, случайно совпавший с именем поля в таблице, то возможны нечанные искажения значений таких полей в таблице. РЕАЛИЗАЦИЯ В HTML шаблоне. ******************************************************************************* СОГЛАШЕНИЕ N 7 Имена файлов строятся по принципу Группа+Тип, например: Admin_List.html, Category_List.html, .lib/email/Admin_BugReport.txt. Имена типов и разделители группы и типа могут быть любыми, требуется лишь чтобы в имени файла присутствовали раздельно оба компонента. МОТИВАЦИЯ Это позволяет задавать в шаблонах заранее тип ссылок и подставлять только имя группы, которое полностью зависит от предметной области. РЕАЛИЗАЦИЯ В HTML шаблоне. ******************************************************************************* СОГЛАШЕНИЕ N 8 В каждой таблице (например Site) содержащей записи принадлежащие другой записи из другой таблицы (например Member) должно быть поле - id той записи (т.е. Site.id_member). МОТИВАЦИЯ Это позволит делать две вещи. Первое - автоматическое удаление всех записей принадлежащих member-у из всех таблиц с помошью $dbh->Delete(). Второе - в сложной ситуации (member [Member] владеет сайтом [Site], а сайт находится в нескольких категориях [Site2Cat]) это соглажение гарантирует наличие id_member в Site2Cat (хотя реально в Site2Cat требуются только id_site и id_cat), что позволяет просто и единообразно контролировать доступ member-а к своим/чужим записям. РЕАЛИЗАЦИЯ В модуле POWER::SQL. ******************************************************************************* СОГЛАШЕНИЕ N 9 Несколько значений принимается только для полей содержащих "__функция" или для управляющих ключей (начинающихся на "-"). МОТИВАЦИЯ Так как {field=>[1,2,3]} полностью по смыслу идентично {field__eq=>[1,2,3]} и в большинстве случаев в field ожидается скаляр а не список, списки разрешаются только для фукнций. Если в field можно передавать список, то могут возникнуть проблемы в ситуации когда ожидается скаляр, а передан список. Например, Insert(), Update() и Replace() в принципе не могут обработать список в данной ситуации, и неоднозначность состоит в том, что параметр _есть_, но этими функциями игнорируется. Другая неоднозначность состоит в том, что при ожидании скаляра в id_site и проверке его на корректность с помошью Select(), ID() или Count() если id_site=13 корректен, то так-же будет признан корректным id_site=>["qwe",13,"asd"]. РЕАЛИЗАЦИЯ В главной CGI и в модуле POWER::SQL. ******************************************************************************* СОГЛАШЕНИЕ N 10 ENUM поля делать NOT NULL. Добавлять явно в ENUM поля вариант "". МОТИВАЦИЯ Поскольку MySQL позволяет в ENUM поле записать пустую строку, и если это поле может быть NULL, то получается два разных _специальных_ значения для этого поля (обычно достаточно одного такого значения). Кроме того, нет удобного способа передать undef/NULL значение для поля через параметры CGIшки. Если не добавить в ENUM поле явно вариант "", то это значение все-равно можно будет записать в это поле, но его нельзя будет сделать значением по умолчанию. Адекватная замена полю name enum('Y') это name enum('','Y') not null РЕАЛИЗАЦИЯ В "CREATE TABLE". :-) ******************************************************************************* СОГЛАШЕНИЕ N 11 Имена функций дописываемых к полям в стиле "__функция" не должны начинаться на "_". МОТИВАЦИЯ Т.к. поле в базе может заканчиваться на "_", то запись "поле___функция" должно обрабатываться однозначно - имя поля: "поле_", функция: "функция". РЕАЛИЗАЦИЯ В err_choice(), POWER::SQL и др. ******************************************************************************* СОГЛАШЕНИЕ N . МОТИВАЦИЯ . РЕАЛИЗАЦИЯ . *******************************************************************************