Acrux-DBI
view release on metacpan or search on metacpan
[//]: # ( README.md Fri 19 Apr 2024 13:16:21 MSK )
# Acrux::DBI
**Acrux::DBI** - Database independent interface for Acrux applications
Acrux::DBI ÑÑо модÑлÑ-оболоÑка Ð´Ð»Ñ [DBI](https://metacpan.org/pod/DBI) пÑизваннÑй конÑепÑÑалÑно замениÑÑ ÑÑÑаÑеваÑÑий [CTK::DBI](https://metacpan.org/pod/CTK::DBI). ÐÐ°ÐºÐµÑ Acrux::DBI ...
- колиÑеÑÑво завиÑимоÑÑей Ñведено к минимÑÐ¼Ñ (на ÑекÑÑий Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¸Ñ
вÑего 3);
- облаÑÑÑ Ð¿ÑÐ¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð´ÑÐ»Ñ ÑиÑе, Ñем Ñ ÐµÐ³Ð¾ пÑедÑеÑÑвенника [CTK::DBI](https://metacpan.org/pod/CTK::DBI);
- в модÑле ÑознаÑелÑно оÑÑÑÑÑÑвÑÐµÑ Ð½Ð°Ð±Ð¾Ñ Ð¼ÐµÑодов Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ñ Ð°ÑинÑ
ÑонноÑÑи (Ð´Ð»Ñ ÑÑиÑ
Ð·Ð°Ð´Ð°Ñ Ð¿Ð¾ÑÑебÑÑÑÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе ÑаÑÑиÑениÑ);
- в модÑле имееÑÑÑ Ð¼ÐµÑ
анизм оÑганизаÑии Ñ
ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð¸ ÑазмеÑÐµÐ½Ð¸Ñ SQL блоков и SQL дампов;
- модÑÐ»Ñ Ð¿Ð¾Ð´Ñ
Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ SQL СУÐÐ *MySQL*, *MariaDB*, *PostgreSQL*, *SQLite* и *Oracle*
- ÑаÑÑиÑÑÑ Ð¼Ð¾Ð´ÑÐ»Ñ Ð² ÑвоиÑ
пÑиложениÑÑ
можно добиÑÑÑÑ Ð¼Ð°ÐºÑималÑной "кÑаÑоÑÑ" ваÑиÑ
моделей
- Ð½ÐµÑ Ð½Ð¸Ñего лиÑнего
ÐнакомÑÑво Ñ Ð¼Ð¾Ð´Ñлем лÑÑÑе вÑего наÑаÑÑ Ñ Ð¿ÑакÑики. ÐÐ»Ñ Ð¿ÑимеÑа Ñ Ð±ÑÐ´Ñ Ð² опиÑании иÑполÑзоваÑÑ ÑеÑÑовÑй WEB пÑÐ¾ÐµÐºÑ Ð¿Ð¾Ð´ именем *altair*, напиÑÐ...
## Constructor
РпÑоекÑе *altair* Ð¼Ð¾Ð´ÐµÐ»Ñ Ð±ÑÐ´ÐµÑ ÑоздаваÑÑÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð°ÑÑибÑÑа `model`:
```perl
package WWW::Altair::Server;
use Mojo::Base 'WWW::Suffit::Server';
use WWW::Altair::Model;
has 'model' => sub {
WWW::Altair::Model->new(
$_[0]->conf->latest("/modelurl")
);
};
```
Ð ÑÑом пÑимеÑе модÑÐ»Ñ Ð¼Ð¾Ð´ÐµÐ»Ð¸ подклÑÑаеÑÑÑ Ð² оÑновном клаÑÑе ÑеÑвеÑа [WWW::Suffit::Server](https://metacpan.org/pod/WWW::Suffit::Server), а ÑкземплÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ ÑоздаÑÑÑÑ Ð...
```text
mysql://username:password@hostname/altair?mysql_auto_reconnect=1
mariadb://username:password@hostname/altair?mariadb_auto_reconnect=1
sqlite:///var/lib/altair/altair.db?sqlite_unicode=1
```
Ðалее ÑÐºÐ°Ð·Ð°Ð½Ð½Ð°Ñ URL ÑÑÑока бÑÐ´ÐµÑ Ð¿ÑеобÑазована авÑомаÑиÑеÑки в DSN бÑдÑÑего ÑоединениÑ
## Connect
ÐÑи запÑÑке WEB ÑеÑвеÑа и пеÑеÑ
оде на главнÑÑ ÑÑÑаниÑÑ ÑеÑÑового ÑайÑа бÑÐ´ÐµÑ Ð¾ÑÑÑеÑÑвлен "вÑ
од" в обÑабоÑÑик ÑÑого маÑÑÑÑÑа `WWW::Altair::Server::Alp...
```perl
my $model = $self->app->model->init;
return $self->reply->error(500 => "E0500" => $model->error)
if $model->error;
```
Сам код иниÑиализаÑии наÑ
одиÑÑÑ Ð² клаÑÑе `WWW::Altair::Model`:
```perl
package WWW::Altair::Model;
use parent 'Acrux::DBI';
use Acrux::Util qw/ touch dformat /;
use Acrux::RefUtil qw/ is_hash_ref is_void /;
sub init {
my $self = shift->connect_cached;
my $is_new = 0;
my $dbh = $self->dbh;
if (defined($dbh)) {
if ($self->is_sqlite) {
my $file = $dbh->sqlite_db_filename();
unless ($file && (-e $file) && !(-z $file)) {
touch($file);
chmod(0666, $file);
$is_new = 1;
}
} elsif ($self->is_mysql) {
if (my $res = $self->query("SHOW TABLES FROM
`" . $self->database() . "` LIKE 'altair'")) {
$is_new = 1 if is_void($res->array);
}
}
}
# Check DB handler
return $self->error(sprintf("Can't connect to database \"%s\": %s",
$self->dsn, $self->errstr || "unknown error")) unless $dbh;
# Import schema
if ($is_new) {
$self->dump->from_data->poke("ddl_" . $self->driver());
return $self if $self->error;
}
# Check connect
return $self->error(sprintf("Can't init database \"%s\". Ping failed: %s",
$self->dsn, $self->errstr() || "unknown error")) unless $self->ping;
return $self;
}
sub is_mysql {
my $self = shift;
my $dr = $self->driver;
return ($dr eq 'mysql' or $dr eq 'mariadb' or $dr eq 'maria') ? 1 : 0;
}
sub is_sqlite {
my $self = shift;
return $self->driver eq 'sqlite' ? 1 : 0;
}
```
ÐниÑиализаÑÐ¸Ñ Ð½Ð°ÑинаеÑÑÑ Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐµÑиÑованного ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ð±Ð°Ð·Ð¾Ð¹ даннÑÑ
. Ðалее идÑÑ Ð¿ÑовеÑка иниÑиализаÑии ÑÑ
емÑ, еÑли ÑÑ
ема не инÐ...
```sql
__DATA__
@@ schema
-- # ddl_sqlite
CREATE TABLE IF NOT EXISTS "altair" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
"status" INTEGER DEFAULT NULL,
"comment" TEXT DEFAULT NULL
)
-- # ddl_mysql
CREATE TABLE IF NOT EXISTS `altair` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`status` INT(11) DEFAULT NULL,
`comment` TEXT DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
```
ÐоÑле ÑÑпеÑной иниÑиализаÑии пÑоиÑÑ
Ð¾Ð´Ð¸Ñ ÐºÐ¾Ð½ÑÑолÑнÑй вÑзов пÑовеÑки акÑивноÑÑи ÑоединениÑ, и возвÑÐ°Ñ Ð¾Ñибки еÑли ÑÑо-Ñо поÑло не Ñак
## Using
РобÑабоÑÑикаÑ
маÑÑÑÑÑов клаÑÑа `WWW::Altair::Server::Alpha` иниÑиализаÑÐ¸Ñ Ñже не поÑÑебÑеÑÑÑ, а ÑÑиÑ
обÑабоÑÑикаÑ
пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¸ÑполÑзование Ñанее и...
```perl
sub tail { # GET /tail
my $self = shift;
# Get model
my $model = $self->app->model->connect_cached;
return $self->reply->json_error(500 => "E9003", $model->error)
if $model->error;
# Get log tail
my @tail = $model->get_log_tail;
return $self->reply->json_error(500 => "E9004", $model->error)
if $model->error;
# Render
return $self->reply->json_ok({tail => \@tail});
}
```
РклаÑÑе модели меÑод `get_log_tail` вÑглÑÐ´Ð¸Ñ Ñак:
```perl
use constant DML_LOG_TAIL => <<'DML';
SELECT * FROM altair ORDER BY `id` DESC LIMIT 100
DML
sub get_log_tail {
my $self = shift;
return () unless $self->ping;
# Log tail
my $tbl = {};
if (my $res = $self->query(DML_LOG_TAIL)) {
$tbl = $res->hashed_by( 'id' );
} else {
return ();
}
# Last 100 records (tail)
my @tail = ();
foreach my $id (sort {$b <=> $a} keys %$tbl) {
my $v = $tbl->{$id};
foreach my $k (keys %$v) {
$v->{$k} //= "";
}
push @tail, $v;
}
return @tail;
}
```
( run in 0.731 second using v1.01-cache-2.11-cpan-d8267643d1d )