Skip to content

Instantly share code, notes, and snippets.

@preaction
Created August 10, 2020 21:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save preaction/4ba85579c6bea18dc8b7e2b91bb3a46e to your computer and use it in GitHub Desktop.
Save preaction/4ba85579c6bea18dc8b7e2b91bb3a46e to your computer and use it in GitHub Desktop.
package Yancy::Backend::DBI;
use Mojo::Base -base, -signatures;
use Yancy::Util qw( fill_brackets );
use SQL::Abstract;
my %MAP = (
# schema_name => mapping
# Mapping can be...
# { table => $table_name } # Standard SQL from SQL::Abstract
# { view => $view_name } # Standard SQL, no writes
# { select, insert, update, delete } # Custom SQL
# For custom SQL, there are template fields to fill:
# {WHERE} - where clause will go here, w/o 'WHERE' label
# {ORDER} - ORDER BY clause will go here, w/o 'ORDER BY' label
# {LIMIT} - LIMIT/OFFSET clause will go here, w/o label
);
has dbh => sub { die 'dbh is required' };
has schema => sub { {} }; # Overrides from the constructor
has sqla => sub { SQL::Abstract->new };
sub new( $class, $db, $schema={} ) {
my $self = $class->SUPER::new( dbh => $db, schema => $schema );
$self->dbh( $db );
return $self;
}
sub get( $self, $schema_name, $id ) {
my $schema = $MAP{ $schema_name }{ schema } //= $self->read_schema( $schema_name );
my $sql = $self->_get_sql_for(
$schema_name,
select => {
WHERE => $schema->{ 'x-id-field' } . ' = ?',
LIMIT => 1,
},
);
return $self->dbh->selectrow_hashref( $sql, {}, $id ) || undef;
}
sub find( $self, $schema_name, $query, $opt ) {
my $map = $MAP{ $schema_name };
my $schema = $map->{ schema } //= $self->read_schema( $schema_name );
my ( $where, @args ) = $self->sqla->where( $query, $opt->{order_by} // {} );
my $rows_sql = $map->{ select }
? fill_brackets( $map->{ select }, {
SCHEMA => $schema_name,
SELECT => join( ', ', keys %{ $schema->{properties} } ),
WHERE => $where // '1=1',
LIMIT => join( ', ', $opt->{limit}//2**32, $opt->{offset}//0 ),
} )
: $self->sqla->select(
$schema_name,
[ keys %{ $schema->{ properties } } ],
$query,
$opt->{ order_by },
)
;
my $total_sql = $self->_get_sql_for(
$schema_name,
select => {
SELECT => 'COUNT(*)',
WHERE => $where // '1=1',
LIMIT => join( ', ', 1, 0 ),
},
);
return {
items => $self->dbh->selectall_arrayref( $rows_sql, {}, @args ),
total => $self->dbh->selectrow_arrayref( $total_sql, {}, @args )->[0],
};
}
sub update( $self, $schema_name, $id, $data ) {
}
sub delete( $self, $schema_name, $id ) {
}
sub create( $self, $schema_name, $data ) {
}
sub _get_sql_for( $self, $schema_name, $op, $data={} ) {
my $map = $MAP{ $schema_name };
my $sql = $map->{ $op };
if ( !$sql && $map->{ table } ) {
$sql = $self->_get_table_sql_for( $schema_name, $op );
}
$data{ SCHEMA } = $schema_name;
return fill_brackets( $sql, $data );
}
my %TABLE_SQL = (
select => q{
SELECT {SELECT} FROM {SCHEMA} WHERE {WHERE} ORDER BY {ORDER} LIMIT {LIMIT}
},
);
sub _get_table_sql_for( $self, $op ) {
return $TABLE_SQL{ $op };
}
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment