Базы данных. Наведем порядок
Когда-то давно, мне надоело припоминать форматы таблиц и значения их полей, возвращаясь к какому-то Веб-проекту, сданному два, три месяца, полгода назад. На бумажную память надежды у меня мало — к сожалению бумаги слишком легко теряются и путаются, в записях нет единства, да и найти в груде бумаги последнюю версию описания проблематично.
Устав бороться со своей и чужой ленью, я решил принять какие-то меры, чтобы облегчить жизнь себе и другим. Одна из таких мер — файл описания таблиц, который мы теперь вкладываем в корневой директорий каждого проекта. Я обычно называю его .tables (естественно в настройках Apache прописывается запрет на получение этого файла через Web), где в достаточно свободном формате описываются таблицы, поля, связи между ними и все остальные объекты.
Естественно, что файл предназначен для описания достаточно небольших баз данных (менее 7—10 таблиц). В этом случае больших баз без хорошо составленной наглядной документации все равно не обойтись. Не надейтесь. :)
Четкий формат представления имеют пока только таблицы, в силу того, что остальными объектами приходится пользоваться достаточно редко, да и синтаксис их описания различается для разных СУБД, но, возможно, в следующих версиях формата появятся правила и их описания тоже.
Вот пример описания двух таблиц, связанных между собой
[/usr/local/pgsql/bin/psql eshop]
items / товары
-----------------------
id serial / идентификатор
gid int4 / категория товара -> group.id
name text / наименование
price real / цена
comment text / описание товара
CREATE INDEX items_price_idx ON items (price)
group / категории
-----------------------
id serial / идентификатор -> items.gid
parent int4 / родитель в дереве. -1, если верхний уровень -> id
name text / наименование
Думаю из примера и так все понятно, но я все-таки дам пару комментариев.
Строчка, заключенная в квадратные скобки, — команда, принимающая данные. Пустые строки и строки, начинающиеся с двух минусов игнорируются. В абзаце, где описывается таблица, первым идет ее имя, ниже — описания ее полей: наименования, через табуляцию тип. В конце каждой значимой строки через пробел и слеш находится ее краткое описание.
Инструкции заведения секвенсоров, представлений и хранимых процедур записываются в одну строку.
Так как формат файла представлений достаточно легко может быть разобран и преобразован в команды мониторов mSQL, PostgreSQL и MySQL я, пару дней назад, выбрав время, написал небольшую программку на Перле. Правда толком ее еще не обкатал, но не думаю, что с ее эксплуатацией возникнут какие-то проблемы.
Интепретатор файлов таблиц: intp.pl
#!/usr/bin/perl
sub StripComment
{
my ($line) = @_;
unless ($line=~s{^([^/]*)\s+/.+}{$1}o)
{
print "Предупреждение: не указан комментарий [ $line ].\n"
unless ($line=~/^CREATE/o);
};
return $line;
};
sub AddData
{
my ($table, @query) = @_;
my $query = join ',', @query;
my $result = '';
if ($todrop)
{
for (@query)
{
if (/([^ ]+) serial$/)
{
$result.= "DROP SEQUENCE ${table}_${1}_seq\\g\n";
last;
};
};
$result.= "DROP TABLE $table\\g\n";
};
$result.= "CREATE TABLE $table ($query)\\g\n";
return $result."\n";
};
sub AddDrop
{
my $table = $_[0];
if ($todrop && $table=~/^CREATE ([^ ]+ +[^ ]+)/o)
{
return "DROP $1\\g\n$table\\g\n";
} else
{
return "$table\\g\n";
};
};
unless (open F, (shift or '.tables'))
{
print <DATA>;
die "\n"
};
@query = ();
$table = '';
$result = '';
$comm = '';
$todrop = shift or 0;
while (<F>)
{
chomp;
next if ($_ eq '' || /^\-\-/);
if (/^\[(.+?)\]$/)
{
$comm = $1;
next;
};
@data = split (/ +/,StripComment $_);
if (@data < 2)
{
$result.= @query?AddData($table, @query):AddDrop ($table)
if ($table ne '');
$table = $data[0];
@query = ();
} else
{
push @query, "$data[0] $data[1]";
};
};
close F;
$result.= AddData ($table, @query) if (@query);
if ($result ne '')
{
if ($comm ne '')
{
open F, "|$comm";
print F "$result\\q";
close F;
} else
{
print "Ошибка: не указана команда для приема данных.";
};
} else
{
print "Ошибка: файл для обработки пуст.";
};
__END__
Интерпретатор файлов таблиц для СУБД.
Написал Евгений Степанищев (2000 год).
Использование: inpt.pl имя_файла [DROP]
DROP - предварительно сделать DROP для таблиц и SEQUENCE
Формат:
-- БД stat комментарий
tablename / описание имя таблицы
--------------------- оформительский элемент
поле1 тип / описание поля таблицы,
поле2 тип / описание описание интепретатор игнорирует
и т.д.
[/usr/local/mysql/bin/mysql stat] комманда, принимающая данные
P.S. Если кто-то разовьет этот формат или предложит мне адекватную замену буду очень рад опубликовать и его тоже.
P.P.S. Вышеописанное ни в коем случае не претендует на панацею и всеобъемлющий инструмент, а всего лишь на роль мелочи, которая поможет избежать некоторых возможных трудностей.