2022-02-23 02:52:14 +01:00
|
|
|
package Peace::DB;
|
|
|
|
|
|
|
|
use v5.30.0;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
|
|
|
|
use Params::ValidationCompiler qw/validation_for/;
|
|
|
|
use Types::Standard qw/HashRef/;
|
|
|
|
|
|
|
|
use DBI;
|
|
|
|
use Const::Fast;
|
|
|
|
|
|
|
|
my @migrations = (
|
|
|
|
'CREATE TABLE options (
|
|
|
|
key TEXT PRIMARY KEY,
|
2022-03-14 15:31:37 +01:00
|
|
|
value INTEGER
|
2022-02-23 02:52:14 +01:00
|
|
|
);',
|
|
|
|
'CREATE EXTENSION "pgcrypto";',
|
2022-03-14 15:31:37 +01:00
|
|
|
'CREATE TABLE customers (
|
|
|
|
uuid UUID NOT NULL DEFAULT gen_random_uuid(),
|
2022-03-14 19:14:05 +01:00
|
|
|
date_creation timestamp DEFAULT NOW(),
|
2022-03-15 02:45:16 +01:00
|
|
|
secret_bcrypt TEXT NOT NULL,
|
2022-03-14 19:14:05 +01:00
|
|
|
stripe_id TEXT,
|
2022-03-14 15:31:37 +01:00
|
|
|
PRIMARY KEY (uuid)
|
2022-02-23 02:52:14 +01:00
|
|
|
);',
|
2022-03-14 15:31:37 +01:00
|
|
|
'CREATE TABLE developers (
|
2022-02-23 02:52:14 +01:00
|
|
|
uuid UUID NOT NULL DEFAULT gen_random_uuid(),
|
2022-03-14 19:14:05 +01:00
|
|
|
date_creation timestamp DEFAULT NOW(),
|
2022-03-15 02:45:16 +01:00
|
|
|
secret_bcrypt TEXT NOT NULL,
|
2022-02-23 02:52:14 +01:00
|
|
|
name TEXT NOT NULL,
|
2022-03-14 15:31:37 +01:00
|
|
|
surname TEXT NOT NULL,
|
|
|
|
email TEXT NOT NULL,
|
2022-03-15 17:41:42 +01:00
|
|
|
stripe_id TEXT,
|
2022-03-14 15:31:37 +01:00
|
|
|
country TEXT NOT NULL,
|
|
|
|
verified BOOL DEFAULT false,
|
|
|
|
PRIMARY KEY (uuid)
|
|
|
|
);',
|
|
|
|
'CREATE TABLE applications (
|
|
|
|
uuid UUID NOT NULL DEFAULT gen_random_uuid(),
|
2022-03-14 19:14:05 +01:00
|
|
|
date_creation timestamp DEFAULT NOW(),
|
2022-02-23 02:52:14 +01:00
|
|
|
name TEXT NOT NULL,
|
2022-03-16 16:11:27 +01:00
|
|
|
description TEXT NOT NULL,
|
2022-03-14 15:31:37 +01:00
|
|
|
url TEXT NOT NULL,
|
|
|
|
developer UUID NOT NULL,
|
2022-02-23 02:52:14 +01:00
|
|
|
price INTEGER NOT NULL,
|
2022-03-14 15:31:37 +01:00
|
|
|
git_repo TEXT NOT NULL,
|
|
|
|
flatpak_builder_file TEXT NOT NULL,
|
2022-03-24 23:57:09 +01:00
|
|
|
flatpak_repo TEXT NOT NULL,
|
2022-03-16 16:11:27 +01:00
|
|
|
verified BOOL DEFAULT false,
|
2022-03-14 15:31:37 +01:00
|
|
|
PRIMARY KEY (uuid),
|
|
|
|
FOREIGN KEY (developer) REFERENCES developers (uuid)
|
|
|
|
);',
|
|
|
|
'CREATE TABLE releases (
|
|
|
|
uuid UUID NOT NULL DEFAULT gen_random_uuid(),
|
2022-03-24 23:57:09 +01:00
|
|
|
date_creation timestamp DEFAULT NOW(),
|
2022-03-24 18:52:35 +01:00
|
|
|
application UUID NOT NULL,
|
2022-03-14 15:31:37 +01:00
|
|
|
tag TEXT NOT NULL,
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
PRIMARY KEY (uuid),
|
|
|
|
FOREIGN KEY (application) REFERENCES applications (uuid)
|
|
|
|
);',
|
|
|
|
'CREATE TABLE builds (
|
|
|
|
uuid UUID NOT NULL DEFAULT gen_random_uuid(),
|
|
|
|
release UUID NOT NULL,
|
2022-03-27 20:22:26 +02:00
|
|
|
date_creation timestamp DEFAULT NOW(),
|
2022-03-14 15:31:37 +01:00
|
|
|
arch TEXT NOT NULL,
|
|
|
|
PRIMARY KEY (uuid),
|
|
|
|
FOREIGN KEY (release) REFERENCES releases (uuid)
|
|
|
|
);',
|
|
|
|
'CREATE TABLE purchases (
|
|
|
|
customer UUID NOT NULL,
|
|
|
|
application UUID NOT NULL,
|
2022-03-27 20:22:26 +02:00
|
|
|
date_purchase timestamp DEFAULT NOW(),
|
2022-03-14 19:14:05 +01:00
|
|
|
PRIMARY KEY (customer, application),
|
2022-03-14 15:31:37 +01:00
|
|
|
FOREIGN KEY (application) REFERENCES applications (uuid),
|
|
|
|
FOREIGN KEY (customer) REFERENCES customers (uuid)
|
|
|
|
);',
|
2022-02-23 02:52:14 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
{
|
|
|
|
my $validator = validation_for(
|
|
|
|
params => {
|
|
|
|
config => { type => HashRef }
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
sub dbh {
|
2022-03-14 15:31:37 +01:00
|
|
|
my $self = shift;
|
2022-02-23 02:52:14 +01:00
|
|
|
my %params = $validator->(@_);
|
|
|
|
my $config = $params{config};
|
|
|
|
my $db_config = $config->{db_config};
|
|
|
|
my $dbname = $db_config->{dbname} or die 'No dbnabe in db_config';
|
|
|
|
my $host = $db_config->{host} or die 'No host in db_config';
|
|
|
|
my $username = $db_config->{username} or die 'No username in db_config';
|
|
|
|
my $password = $db_config->{password} or die 'No password in db_config';
|
2022-03-14 15:31:37 +01:00
|
|
|
my $port = $db_config->{port};
|
2022-02-23 02:52:14 +01:00
|
|
|
my $dsn =
|
|
|
|
"dbi:Pg:"
|
|
|
|
. ( defined $dbname ? "dbname=$dbname;" : "" )
|
|
|
|
. ( defined $host ? "host=$host;" : "" )
|
|
|
|
. ( defined $port ? "port=$port;" : "" );
|
|
|
|
|
|
|
|
my $dbh = DBI->connect_cached(
|
2022-03-14 15:31:37 +01:00
|
|
|
$dsn,
|
|
|
|
$username,
|
|
|
|
$password,
|
2022-02-23 02:52:14 +01:00
|
|
|
{
|
|
|
|
AutoCommit => 1,
|
|
|
|
RaiseError => 1,
|
|
|
|
sqlite_unicode => 1,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
state $migrations_run = 0;
|
|
|
|
|
|
|
|
if ( !$migrations_run ) {
|
|
|
|
run_migrations($dbh);
|
|
|
|
$migrations_run = 1;
|
|
|
|
}
|
|
|
|
return $dbh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_migrations {
|
|
|
|
my $dbh = shift;
|
|
|
|
my $current_migration = _get_current_migration_number($dbh);
|
2022-03-14 15:31:37 +01:00
|
|
|
local $dbh->{RaiseError} = 0;
|
2022-02-23 02:52:14 +01:00
|
|
|
if ( $current_migration < scalar @migrations ) {
|
|
|
|
my @needed_migrations =
|
|
|
|
@migrations[ $current_migration .. $#migrations ];
|
|
|
|
for my $migration (@needed_migrations) {
|
|
|
|
$dbh->do($migration);
|
2022-03-14 15:31:37 +01:00
|
|
|
my $update_result =
|
2022-03-15 02:45:16 +01:00
|
|
|
$dbh->do( <<'EOF', undef, ++$current_migration );
|
|
|
|
UPDATE options SET value = ? WHERE key = 'migration';
|
|
|
|
EOF
|
2022-03-14 15:31:37 +01:00
|
|
|
|
2022-03-15 02:45:16 +01:00
|
|
|
unless ( defined $update_result && 0+$update_result ) {
|
|
|
|
say $dbh->do( <<'EOF', undef, $current_migration);
|
|
|
|
INSERT INTO options (key, value) VALUES ('migration', ?);
|
|
|
|
EOF
|
2022-02-23 02:52:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub _get_current_migration_number {
|
|
|
|
my $dbh = shift;
|
|
|
|
local $dbh->{RaiseError} = 0;
|
|
|
|
my $migration = $dbh->selectrow_hashref( <<'EOF', {} );
|
|
|
|
SELECT value FROM options WHERE key = 'migration'
|
|
|
|
EOF
|
|
|
|
my $value = 0;
|
|
|
|
if ( defined $migration ) {
|
|
|
|
$value = $migration->{value};
|
|
|
|
}
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
1;
|
2022-03-17 05:08:05 +01:00
|
|
|
|
|
|
|
=encoding utf8
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
Peace::DB - Database handler generator for the Peace shop.
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
2022-03-17 18:18:30 +01:00
|
|
|
my $peace = Peace->new;
|
|
|
|
my $home = $ENV{HOME};
|
2022-03-17 05:08:05 +01:00
|
|
|
my $config =
|
2022-03-17 18:18:30 +01:00
|
|
|
$peace->plugin(
|
2022-03-17 05:08:05 +01:00
|
|
|
JSONConfig => {
|
|
|
|
file => "$home/.config/peace/peace.conf"
|
|
|
|
}
|
|
|
|
);
|
|
|
|
my $dbh = Peace::DB->dbh( config => $config );
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
This module helps to recover a database handle and runs
|
|
|
|
the migrations automatically when doing so.
|
|
|
|
|
|
|
|
=head1 FUNCTIONS
|
|
|
|
|
|
|
|
Peace::DB implements the following functions:
|
|
|
|
|
|
|
|
=head2 dbh
|
|
|
|
|
|
|
|
Recovers a database handle, requires the config of the app as
|
|
|
|
its parameter.
|
|
|
|
|
|
|
|
my $dbh = Peace::DB->dbh( config => $config );
|
|
|
|
|
|
|
|
=head2 run_migrations
|
|
|
|
|
|
|
|
Runs the migrations manually.
|
|
|
|
|
|
|
|
Peace::DB->run_migrations($dbh);
|
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
2022-03-17 18:18:30 +01:00
|
|
|
L<DBI>, L<DBD::Pg>, L<Peace>
|