Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Базы данных. Наведем порядок

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

Устав бороться со своей и чужой ленью, я решил принять какие-то меры, чтобы облегчить жизнь себе и другим. Одна из таких мер — файл описания таблиц, который мы теперь вкладываем в корневой директорий каждого проекта. Я обычно называю его .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. Вышеописанное ни в коем случае не претендует на панацею и всеобъемлющий инструмент, а всего лишь на роль мелочи, которая поможет избежать некоторых возможных трудностей.

Ctrl ←Mu/\EHHuyM