214 lines
6.4 KiB
Perl
214 lines
6.4 KiB
Perl
package L3TDE::Model;
|
|
|
|
use v5.34.1;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use List::AllUtils qw/none any/;
|
|
use JSON;
|
|
|
|
use L3TDE::DB;
|
|
|
|
use Moo::Role;
|
|
|
|
requires 'table';
|
|
|
|
requires 'not_defaulted_fields';
|
|
|
|
requires 'defaulted_fields';
|
|
|
|
requires 'jsonb_fields';
|
|
|
|
requires 'find_fields';
|
|
|
|
requires 'id_fields';
|
|
|
|
sub _dbh {
|
|
return L3TDE::DB->connect;
|
|
}
|
|
|
|
sub create {
|
|
my $class = shift->_get_class;
|
|
my $dbh = $class->_dbh;
|
|
my %params = @_;
|
|
my $not_defaulted_fields = $class->not_defaulted_fields;
|
|
my $jsonb_fields = $class->jsonb_fields;
|
|
my $defaulted_fields = $class->defaulted_fields;
|
|
my @insert_fields = ( @$not_defaulted_fields, @$jsonb_fields );
|
|
my @fields = ( @insert_fields, @$defaulted_fields );
|
|
my $table = $class->table;
|
|
my $query = "INSERT INTO @{[$class->table]} (";
|
|
$query .= join ',', @insert_fields;
|
|
$query .= ") VALUES (";
|
|
$query .= join ',',
|
|
(
|
|
( map { '?' } @$not_defaulted_fields ),
|
|
( map { '?::jsonb' } @$jsonb_fields )
|
|
);
|
|
$query .= ") ";
|
|
$query .= $class->_generate_returning;
|
|
$query .= ';';
|
|
my $result = $dbh->selectrow_hashref(
|
|
$query,
|
|
{},
|
|
(
|
|
map {
|
|
my $param = $params{$_};
|
|
die "No $_ in @{['%params']} for $class" if !defined $param;
|
|
if ( $class->_is_jsonb($_) ) {
|
|
$param = encode_json($param);
|
|
}
|
|
$param;
|
|
} @insert_fields
|
|
)
|
|
);
|
|
|
|
if ( !defined $result ) {
|
|
die "Unable to create $class with args "
|
|
. Data::Dumper::Dumper \%params;
|
|
}
|
|
return $class->_result_to_object($result);
|
|
}
|
|
|
|
sub _generate_returning {
|
|
my $class = shift->_get_class;
|
|
my $returning = "RETURNING ";
|
|
$returning .= $class->_to_select_fields;
|
|
return $returning;
|
|
}
|
|
|
|
sub _to_select_fields {
|
|
my $class = shift->_get_class;
|
|
my $not_defaulted_fields = $class->not_defaulted_fields;
|
|
my $jsonb_fields = $class->jsonb_fields;
|
|
my $defaulted_fields = $class->defaulted_fields;
|
|
my @insert_fields = ( @$not_defaulted_fields, @$jsonb_fields );
|
|
my @fields = ( @insert_fields, @$defaulted_fields );
|
|
my $select .= join ',', @fields;
|
|
return $select;
|
|
}
|
|
|
|
sub _is_field_to_update {
|
|
my $class = shift->_get_class;
|
|
my $field = shift;
|
|
my $jsonb_fields = $class->jsonb_fields;
|
|
my $not_defaulted_fields = $class->not_defaulted_fields;
|
|
my $defaulted_fields = $class->defaulted_fields;
|
|
my @fields = ( @$not_defaulted_fields, @$defaulted_fields, @$jsonb_fields );
|
|
return any { $field eq $_ } (@fields);
|
|
}
|
|
|
|
sub update {
|
|
my $self = shift;
|
|
my $fields_to_update = shift;
|
|
my $table = $self->table;
|
|
my $dbh = $self->_dbh;
|
|
my $not_defaulted_fields = $self->not_defaulted_fields;
|
|
my $jsonb_fields = $self->jsonb_fields;
|
|
my $defaulted_fields = $self->defaulted_fields;
|
|
my $id_fields = $self->id_fields;
|
|
|
|
for my $field_to_update (@$fields_to_update) {
|
|
die "$field_to_update does not exists in @{[$self->_get_class]}"
|
|
if !$self->_is_field_to_update($field_to_update);
|
|
die "$field_to_update is not a method in @{[$self->_get_class]}"
|
|
if !$self->can($field_to_update);
|
|
}
|
|
my $query = "UPDATE $table SET ";
|
|
$query .= join ',', map {
|
|
my $key = $_;
|
|
my $return = "$key=?";
|
|
$return .= '::jsonb' if $self->_is_jsonb($key);
|
|
$return
|
|
} @$fields_to_update;
|
|
$query .= " WHERE ";
|
|
$query .= join 'AND', map { "$_=?" } @$id_fields;
|
|
$query .= " ";
|
|
$query .= $self->_generate_returning;
|
|
$query .= ";";
|
|
my $result = $dbh->selectrow_hashref( $query, {},
|
|
( map { $self->$_ } ( @$fields_to_update, @$id_fields ) ) );
|
|
return $self->_result_to_object($result);
|
|
}
|
|
|
|
sub _is_jsonb {
|
|
my $class = shift->_get_class;
|
|
my $key = shift;
|
|
my $jsonb_fields = $class->jsonb_fields;
|
|
return any { $key eq $_ } @$jsonb_fields;
|
|
}
|
|
|
|
sub _result_to_object {
|
|
my $self = shift;
|
|
my $class = $self->_get_class;
|
|
my $result = shift;
|
|
for my $key ( keys %$result ) {
|
|
$result->{$key} = decode_json $result->{$key} if $self->_is_jsonb($key);
|
|
}
|
|
return $class->new(%$result);
|
|
}
|
|
|
|
sub _get_class {
|
|
my $self = shift;
|
|
return $self if !ref $self;
|
|
return ref $self;
|
|
}
|
|
|
|
sub _validate_find_fields {
|
|
my $class = shift->_get_class;
|
|
my $fields_to_search = shift;
|
|
my $find_fields = $class->find_fields;
|
|
for my $field_to_search (@$fields_to_search) {
|
|
if ( none { return $_ eq $field_to_search } @$find_fields ) {
|
|
die
|
|
"$field_to_search is not declared in the list of searchable fields for $class.";
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
sub _generate_select {
|
|
my $class = shift->_get_class;
|
|
my $fields_to_search = shift;
|
|
my $table = $class->table;
|
|
my $query = "SELECT @{[$class->_to_select_fields]} FROM $table";
|
|
if (@$fields_to_search) {
|
|
$query .= " WHERE ";
|
|
$query .= join 'AND', map { '$_=?' } @$fields_to_search;
|
|
}
|
|
return $query;
|
|
}
|
|
|
|
sub find_one {
|
|
my $class = shift->_get_class;
|
|
my %params = @_;
|
|
my $dbh = $class->_dbh;
|
|
my @fields_to_search = sort { $a cmp $b } keys %params;
|
|
$class->_validate_find_fields(\@fields_to_search);
|
|
my $query = $class->_generate_select( \@fields_to_search );
|
|
$query .= ' LIMIT 1;';
|
|
my $result =
|
|
$dbh->selectrow_hashref( $query, {}, @params{@fields_to_search} );
|
|
return $class->_result_to_object($result);
|
|
}
|
|
|
|
sub find {
|
|
my $class = shift->_get_class;
|
|
my %params = @_;
|
|
my $page = delete $params{page} // 0;
|
|
my $dbh = $class->_dbh;
|
|
my @fields_to_search = sort { $a cmp $b } keys %params;
|
|
$class->_validate_find_fields(\@fields_to_search);
|
|
my $query = $class->_generate_select( \@fields_to_search );
|
|
$query .= ' OFFSET ? * 10 LIMIT 10;';
|
|
my $result =
|
|
$dbh->selectall_arrayref( $query, {Slice => {}}, @params{@fields_to_search}, $page );
|
|
my @return;
|
|
for my $row (@$result) {
|
|
push @return, $class->_result_to_object($row);
|
|
}
|
|
return \@return;
|
|
}
|
|
1;
|