Создание классов схемы

В части 1 мы заложили основу нашего проекта, а в этой части мы сосредоточимся на создании базы данных и схемы классов. Схема классов относится к классам, основанным на базе данных и ее таблицах.

После того, как мы сгенерируем классы, мы создадим средство доступа для возврата данных особым образом, а затем метод для выполнения настраиваемого поиска. После каждого этапа мы можем запускать тесты, чтобы проверить, что отсутствует, а что работает.

Генерация схемы

Теперь мы воспользуемся функцией make_schema_at, которая экспортируется DBIx :: Class :: Schema :: Loader, для создания классов схемы. make_schema_at просто считывает схему СУБД, в нашем случае app.db, и создает классы на основе своих таблиц.

Создать сценарий схемы

Откройте файл scripts / make_schema.pl и введите следующие строки.

#!/usr/bin/env perl
use strict;
use warnings;
use DBIx::Class::Schema::Loader qw(make_schema_at);
my @dsn     = 'dbi:SQLite:dbname=app.db';
my %options = (
    dump_directory => './lib'
);
make_schema_at('App::Schema' => \%options, \@dsn);

Краткое объяснение этого файла - @dsn определяет, как устанавливается соединение с базой данных, а % options содержит информацию, которая может использоваться для создания классов. В этом случае dump_directory указывает, в каком каталоге будут созданы классы. Наконец, вызывается make_schema_at для генерации классов в пространстве имен App :: Schema.

Теперь запустим наш скрипт генерации:

perl scripts/make_schema.pl

Теперь содержимое каталога lib должно выглядеть следующим образом:

lib/
└── App
    ├── Schema
    │   └── Result
    │       └── User.pm
    └── Schema.pm

Запустите тест с помощью verify -lv t / basic.t, и результат должен быть похож на следующий.

ok 1 — use App::Schema;
not ok 2 — App::Schema::Result::User->can('fullname')
…

Первый тест должен пройти, поскольку App :: Schema теперь существует. Однако остальные четыре завершатся ошибкой, потому что ни метод доступа fullname, ни метод age_less_than еще не реализованы. Это рассматривается в следующих разделах.

Настраиваемые поля и поисковые запросы

Хорошо, теперь, когда схема класса сгенерирована, пора добавить к ней некоторые настраиваемые функции. Мы начнем с определения настраиваемого средства доступа, возвращающего полное имя пользователя. Это более короткий способ, чем необходимость вручную связывать имя и фамилию везде, где требуется полное имя пользователя.

Добавление метода доступа полного имени

Откройте файл lib / App / Schema / Result / User.pm и добавьте следующий метод.

sub fullname {
    my $self = shift;
    return $self->firstname . ' ' . $self->lastname;
}

Примечание. Вышеупомянутая подпрограмма должна быть определена под строкой следующего содержания:

# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016–08–07 10:02:31
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:

Если вы вносите изменения в свою базу данных, например добавляете новый столбец в таблицу пользователей, повторный запуск make_schema.pl обновит модуль User.pm, чтобы отразить изменения. Однако он не удаляет код, написанный под указанной строкой. Внесение любых изменений выше этой строки может привести к сбою создания схемы класса.

Протестируйте аксессор

Запустите тест еще раз, и результаты должны выглядеть так:

ok 1 — use App::Schema;
ok 2 — App::Schema::Result::User->can('fullname')
ok 3 — Should read from set using a custom accessor
not ok 4 — App::Schema::ResultSet::User->can('age_less_than')

Второй и третий тесты теперь пройдены, поскольку fullname определено и работает правильно.

Как видите, метод доступа fullname действует как виртуальный столбец в SQL. Поле полное имя считается виртуальным, поскольку оно не является столбцом в таблице пользователей, но выглядит так. Вместо этого полное имя вычисляется с использованием полей имени и фамилии.

Определите метод пользовательского поиска

Теперь мы определим метод для выполнения пользовательского поиска по пользователям. Этот метод будет определен в классе ResultSet, который можно создать следующим образом:

mkdir -p lib/App/Schema/ResultSet && \
touch lib/App/Schema/ResultSet/User.pm

Теперь откройте файл lib / App / Schema / ResultSet / User.pm и введите следующий код:

package App::Schema::ResultSet::User;
use base 'DBIx::Class::ResultSet';
sub age_less_than {
   my $self = shift;
   my $age  = shift;
   return $self->find({ age => { '<' => $age }});
}
1;

Протестируйте собственный метод

Запустите тест еще раз, и результат должен быть следующим.

t/basic.t ..
ok 1 — use App::Schema;
ok 2 — App::Schema::Result::User->can('fullname')
ok 3 — should read from set using a custom accessor
ok 4 — App::Schema::ResultSet::User->can('age_less_than')
ok 5 — should perform search using a custom method
1..5
ok
All tests successful.

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

Резюме

Этот пост завершает краткое введение в ORM на Perl из двух частей с помощью DBIx :: Class. Создание схемы класса было достигнуто с помощью одного вызова make_schema_at. Для добавления настраиваемого средства доступа и метода требовалось лишь добавить подпрограмму к модулям Result :: User и ResultSet :: User соответственно. Мы также доказали свою функциональность с помощью Test Driven Development.

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

Код для обеих частей этой статьи можно найти здесь.