NAME
D - Simple interface to work with DB tables
SYNOPSIS
use D;
my $schema = D::db; # DBIx::Class::Schema
my $dbh = D::dbh; # DBI handle
my $users = D::S User => { active => 1 };
my $user = D::SS User => 1;
my $count = D::q00 'SELECT count(*) FROM "User"';
# Find by ID, another PK or set of conditions
my $row = D::T User => 7;
my $row = D::T User => { id => 7 };
my $row = D::T User => { email => 'a@example.com' };
my $row = D::T User => [ { f1 => 'v1' }, { f2 => 'v2' } ]; # See SQL::Abstract
my $row = D::T User => { field1 => 'cond1', field2 => 'cond2' };
# Find existing or create by merging COND and DATA. COND merged only if it is a HASH.
# The create dies if user will try to use custom values for PKs
my $row = D::T User => { email => 'a@example.com' }, { name => 'Alice' };
my $row = D::T User => undef, { name => 'Alice' } # Save as D::C User => { name => 'Alice' };
# Find and update. If not found `{ f2 => 'v2' }` will be created.
# NOTE: It is still not clear should we create when nothing was found and 'update'
# flag is true. Or should we return `undef`.
my $row = D::T User => { f1 => 'value1' }, { f2 => 'v2' }, 'update';
# Update $row
D::RU $row, { f1 => 'v1' };
# Delete $row
D::RD $row;
# Work with transaction
my $atomic = D::txn; # ->txn_scope_guard
...
if( ... ) { return; } # transaction will be rolled back automatically
$atomic->commit;
# All methods from DBIx::Class::Storage are available
my $db = D::db;
$db->txn_begin;
$db->svp_begin;
$db->txn_do( $coderef );
$db->svp_release;
$db->svp_rollback;
$db->txn_rollback;
$db->txn_commit;
DESCRIPTION
D is a small convenience layer around DBIx::Class and DBI.
It provides shortcuts for:
- Getting a schema/DBI handle - Running raw SQL queries - Basic CRUD helpers using a DBIx::Class resultset
Most helpers accept a table name (Result class moniker) as the first argument.
CONFIGURATION
If you call "db" or "connect" without arguments, configuration is read from C::config->{DbAccess}.
Expected keys:
schema DBIx::Class::Schema class name (required)
DRVR DBI driver name (for example: Pg)
NAME database name
HOST database host
PORT database port (optional)
USER database user
PASS database password
DSN optional prebuilt DBI DSN (will be generated if missing)
Timezone:
- If possible, "connect" sets PostgreSQL timezone from $ENV{PGTZ} or $ENV{TZ}; otherwise it defaults to Europe/Zaporozhye.
FUNCTIONS
db
my $schema = D::db;
my $schema = D::db $schema;
Return (and cache) a DBIx::Class::Schema instance. When called without arguments, it calls "connect".
dbh
my $dbh = D::dbh;
Shortcut for D::db->storage->dbh.
txn
my $guard = D::txn;
Return a transaction scope guard (see "txn_scope_guard" in DBIx::Class::Storage).
do
D::do $statement, @bind;
Shortcut for D::dbh->do. See "do" in DBI.
q
my $rows = D::q $statement, \%attr, @bind;
my $rows = D::q 'SELECT * FROM users';
Shortcut for DBI::selectall_arrayref.
q00
my $value = D::q00 $statement, \%attr, @bind;
Return the first field of the first row from "q". This is useful for queries like:
SELECT count(*) FROM table
SELECT name FROM table LIMIT 1
rs
my $result_set = D::rs $statement, @bind;
Prepare and execute a statement and return resultset.
qh
my $rows = D::qh $statement, \%attr, @bind;
Query and return an array of hashes.
report
my $rs = D::report $sql, \@columns, @bind;
Run arbitrary SQL using DBIx::Class::Report and return its resultset.
dsn
my $dsn = D::dsn \%db_conf;
Build a DBI DSN from config keys.
connect
my $schema = D::connect; # Pass through to DBI->connect
my $schema = D::connect( $schema_class, $dsn, $user, $pass );
Connect to the database and return a schema instance. See "connect" in DBI. Here `$schema_class` is DBIx::Class schema of your application. See Schema.
obtain_data
my $row = D::obtain_data($table, $cond, $data, $update);
Try to find a row by:
- ID (when $cond is a scalar) - Condition (when $cond is a hashref)
If $update is true and $data is provided, the found row is updated.
If nothing was found, and the search was not done by ID, a new row is created from the merged $cond and $data.
This helper refuses to create rows with an explicit primary key id.
T
my $rs = D::T 'User';
my $row = D::T 'User', $id;
my $row = D::T 'User', \%cond, \%data;
my $row = D::T 'User', \%cond, \%data, 'update';
Entry point for table access:
- With one argument returns a resultset (see "S"). - With more arguments calls "obtain_data".
INSECURE
my $rs = D::INSECURE 'User';
my $row = D::INSECURE 'User', \%cond, \%data;
Like "T", but disables security guard logic for the duration of the call.
C
my $row = D::C $table, \%data;
Create a row in $table.
S
my $rs = D::S $table, \%cond, @attrs;
Search rows in $table and return a resultset.
SS
my $row = D::SS $table, \%cond;
Search and return a single row.
RU
D::RU $row, \%data;
Update a row with provided data.
RD
D::RD $row;
D::RD $table, \%cond;
Delete a row.
In secure mode, table access routes through $rs->guard(C::C) (see "SECURITY NOTES").
columns_info
my $info = D::columns_info 'User';
my $req = D::columns_info 'User', { required => 1 };
Return column metadata from the result source. If required is true, nullable columns and columns with defaults are excluded. See "columns_info" in DBIx::Class::ResultSource.
SECURITY NOTES
Secure mode is enabled by default and is meant to restrict data access and mutations through per-resultset guard logic.
This distribution includes only a stub guard implementation in Schema::ResultSet; applications are expected to override it.
Even in insecure mode, "obtain_data" refuses to create rows with an explicit primary key id.
SEE ALSO
Mojolicious::Plugin::DbAccess, DBIx::Class, DBI
COPYRIGHT AND LICENSE
Copyright (c) 2026 Eugen Konkov.
This program is free software, you can redistribute it and/or modify it under the terms of the MIT License.