NAME
DBIO - Native relational mapping for Perl, built on DBI
VERSION
version 0.900004
SYNOPSIS
The classes shown below can also be generated from an existing database with dbiogen, powered by DBIO::Generate.
Schema class
package MyApp::Schema;
use DBIO 'Schema', -pg;
__PACKAGE__->load_namespaces();
1;
Vanilla style (import sugar)
package MyApp::Schema::Result::Artist;
use DBIO; # Role is auto-detected from the package name: Core
__PACKAGE__->table('artist');
__PACKAGE__->add_columns(qw/ artistid name /);
__PACKAGE__->set_primary_key('artistid');
__PACKAGE__->has_many(cds => 'MyApp::Schema::Result::CD', 'artistid');
1;
The classic equivalent (still supported):
package MyApp::Schema::Result::Artist;
use base 'DBIO::Core';
...
Candy style (import sugar)
DBIO::Candy removes the __PACKAGE__-> boilerplate:
package MyApp::Schema::Result::Artist;
use DBIO::Candy;
table 'artist';
column artistid => { data_type => 'int', is_auto_increment => 1 };
primary_key 'artistid';
column name => { data_type => 'varchar', size => 100 };
has_many cds => 'MyApp::Schema::Result::CD', 'artistid';
1;
Cake style (DDL-like DSL)
DBIO::Cake provides type functions that read like DDL:
package MyApp::Schema::Result::Artist;
use DBIO::Cake;
table 'artist';
col artistid => integer, auto_inc;
col name => varchar(100);
primary_key 'artistid';
has_many cds => 'MyApp::Schema::Result::CD', 'artistid';
1;
Using your schema
use MyApp::Schema;
my $schema = MyApp::Schema->connect($dbi_dsn, $user, $pass, \%dbi_params);
my @all_artists = $schema->resultset('Artist')->all;
my $johns_rs = $schema->resultset('Artist')->search(
{ name => { like => 'John%' } }
);
# Joins are automatic from relationship conditions
my @rock_cds = $schema->resultset('CD')->search(
{ 'artist.name' => 'John Doe' }
)->all;
# Prefetch related data in a single query
my $millennium_cds_rs = $schema->resultset('CD')->search(
{ year => 2000 },
{ prefetch => 'artist' }
);
my $cd = $millennium_cds_rs->next;
my $artist_name = $cd->artist->name; # no extra query
# Create, update, delete
my $new_cd = $schema->resultset('CD')->create({ title => 'Spoon' });
$schema->txn_do(sub { $new_cd->update({ title => 'Fork' }) });
$millennium_cds_rs->update({ year => 2002 });
See t/dbio_sugar_pragma.t for a runnable example of the use DBIO import-sugar and role auto-detection shown above.
DESCRIPTION
DBIO (DBI Objects) is a relational mapper for Perl built on top of DBI. It combines an object model for rows and result classes with a resultset API for building queries without giving up database-native behavior.
Three styles are available for defining result classes: DBIO::Cake (DDL-like DSL), DBIO::Candy (import sugar), and the classic Vanilla style (use DBIO; or use base 'DBIO::Core').
Database-specific features are provided by native driver distributions (DBIO::PostgreSQL, DBIO::MySQL, DBIO::SQLite, etc.) that speak each database's dialect natively.
Key features:
Automatic joins from relationship conditions
Lazy ResultSets that only query when you ask for rows
Prefetch for efficient eager loading
Multi-column primary and foreign keys
Database-level paging, driver-specific SQL features
Three result class styles: Cake, Candy, Vanilla
DBIO is pre-1.0. The core API is substantial and usable, but some edges are still being refined. Please report anything that looks wrong or surprising.
METHODS
skill
my $markdown = DBIO->skill('postgresql-database');
Class-level shortcut for "skill" in DBIO::Skills: returns the markdown text of the named agent skill from whatever DBIO distributions are currently loaded, or undef. The leading dbio- is optional.
skills
my @names = DBIO->skills;
Class-level shortcut for "skills" in DBIO::Skills: the sorted names of all skills available from the currently loaded DBIO distributions.
apply_driver
DBIO->apply_driver($caller, 'PostgreSQL');
Applies a driver named $name to $caller by the DBIO::<Name>::{Storage,Result} convention: on a DBIO::Schema subclass it pins $caller->storage_type("+DBIO::${name}::Storage"); on a DBIO::Core subclass it loads the driver's Result component, but only if DBIO::${name}::Result exists. Called by driver shortcut stubs (DBIO::Shortcut::*) and by the use DBIO '-name' fallback path; not normally called directly.
On a schema this declares the driver, exactly as loading the driver's component does: the class pinned is the driver's base storage class, the same for every DBD the driver is reached through. The storage adapts itself to the access path of a connection from there ("_adapt_to_access_path" in DBIO::Storage::DBI, ADR 0059).
driver_for
my $driver = DBIO->driver_for($dsn, $user, $password, \%attrs); # 'PostgreSQL'
my $driver = DBIO->driver_for(sub { DBI->connect(...) });
Returns the name of the driver a connection leads to -- the <Name> of DBIO::<Name>, as "apply_driver" takes it -- for the cases where it is not known in advance, such as loading a schema from an existing database (ADR 0067). Takes connect info as "connect" in DBIO::Schema does: a DSN with user, password and attributes, a hash with dsn or dbh_maker, or a code reference returning a database handle.
The answer is the exact driver and nothing else: the driver the DBD is registered for ("register_driver" in DBIO::Storage::DBI) -- the DBD named in the DSN, read without connecting, or, for a code reference, the DBD of the handle it returns (the code reference is called for that). No question is put to the server, and no driver is moved to another product.
A DBD that names no driver -- DBD::ODBC, DBD::ADO, a proxy, a DBD nothing is registered for -- throws: a connection through it does not say which engine is behind it. Declare the driver instead; a driver that runs over such an access path knows it and adapts itself to it ("_adapt_to_access_path" in DBIO::Storage::DBI). A driver that registers its DBD only when its storage class is loaded is known after that load.
schema_for
my $schema = DBIO->schema_for($dsn, $user, $password, \%attrs);
Takes the same connect info as "driver_for" and returns a connected schema object with that driver applied ("apply_driver") and no sources -- the starting point for loading a schema from an existing database. It is an ordinary schema with a driver: everything after the connect is the driver's, as for any schema that declares it.
The schema class is DBIO::SchemaFor::<Driver> (for example DBIO::SchemaFor::PostgreSQL), a subclass of DBIO::Schema built on the first call for that driver and shared by every later one. It carries no sources; register sources on the returned object, which has its own source registry, or derive a schema class of your own. For a code reference the reference is called twice: once by "driver_for", once by the connection.
USE-AS-PRAGMA
Since DBIO.pm itself is a sugar pragma (analogous to Moose.pm), it can be used directly to declare a DBIO class. The role to inherit from is auto-detected from the package name, or can be specified explicitly.
package MyApp::Schema::Result::Artist;
use DBIO; # -> @ISA = ('DBIO::Core')
package MyApp::Schema::ResultSet::Artist;
use DBIO; # -> @ISA = ('DBIO::ResultSet')
package MyApp::Schema;
use DBIO 'Schema', -pg; # -> @ISA = ('DBIO::Schema'), driver PostgreSQL
package MyApp::Schema::Result::Photo;
use DBIO 'Core'; # explicit override
Shortcuts can be combined with role selection, separated by leading dashes. A shortcut applies a driver: on a Result class it loads the driver's ::Result component, on a Schema it pins the driver's storage class:
use DBIO -pg; # Core + load the PostgreSQL::Result component
use DBIO 'Schema', -pg; # Schema + storage_type('+DBIO::PostgreSQL::Storage')
Shortcuts are owned by the driver distributions, not by core; core never names a single driver. A shortcut resolves in two tiers:
An explicit stub
DBIO::Shortcut::<key>, which a driver ships for each curated alias (-pg,-mysql, ...). Core lazy-loads it and calls itsapply($caller), which usually just delegates toDBIO->apply_driver:package DBIO::Shortcut::pg; sub apply { DBIO->apply_driver($_[1], 'PostgreSQL') } 1;If there is no stub, core falls back to an already-loaded driver whose name matches the key case-insensitively -- so
-postgresqlresolves toDBIO::PostgreSQLonce that driver is loaded, with no stub needed.
apply_driver($caller, $name) applies the driver by convention: on a Schema it pins storage_type('+DBIO::<name>::Storage'); on a Result class it loads the <name>::Result component if the driver ships one. So every driver gets a shortcut (the Schema path works for all), and a ::Result component is just an extra. A shortcut that resolves to nothing dies with a helpful message -- it only works when its driver is installed (and, for the bare canonical name, loaded).
On a schema the shortcut declares the driver, and a schema always declares its driver -- by a shortcut, or by loading the driver's component (__PACKAGE__->load_components('PostgreSQL')), which pins the same class. The declared storage class stands, whatever DSN the schema is connected with: the driver adapts itself to the access path of the connection -- the DBD and client library the DSN leads through -- within its own classes ("_adapt_to_access_path" in DBIO::Storage::DBI), and the storage never becomes the class of another driver. A DSN that leads through the DBD of another driver, or a server the driver notices is not its engine, is reported: a warning by default, an error with "driver_strict" in DBIO::Schema, nothing with driver_warnings(0) ("driver_warnings" in DBIO::Schema).
A schema class that declares no driver is refused when it connects ("connection" in DBIO::Schema, ADR 0067). Where the driver is not known in advance, "driver_for" names the driver of a DSN and "schema_for" returns a connected schema with it.
Role auto-detection rules:
package matches
/::Result::WORD$/→ roleCorepackage matches
/::ResultSet::WORD$/→ roleResultSetanything else → role
Core(the most common case)
use DBIO; additionally enables strict and warnings in the caller, matching the behavior of DBIO::Candy, DBIO::Cake, DBIO::Moo and DBIO::Moose.
In a class that is a DBIO::Schema, use DBIO also installs two declaration keywords for the schema's skill overrides (see "skills" in DBIO::Schema):
package MyApp::Schema;
use DBIO 'Schema', -pg;
skills { 'mysql-database' => $markdown, core => $more }; # set the whole map
skill 'postgresql-database' => $markdown; # add or replace one entry
skills takes a hashref or a key/value list and replaces the map; skill merges a single entry into it. Both keywords are removed from the class once it has compiled, so afterwards MyApp::Schema->skills and MyApp::Schema->skill($name) are the methods inherited from DBIO::Schema.
WHERE TO START
See DBIO::Manual::DocMap for the full documentation map. New users should start with DBIO::Manual::QuickStart.
HERITAGE
DBIO is a fork of DBIx::Class with a clean namespace break. Key changes:
Namespace:
DBIO::replacesDBIx::Class::SQL::Abstract replaces SQL::Abstract::Classic
LIMIT/OFFSET via
apply_limiton the driver's SQLMaker instead of string-based dialect dispatchSQL::Translator has been removed; schema introspection, diff, and deployment are handled by DB-specific native modules
Shared utilities (DBIO::SQL::Util) provide
_quote_identand_split_statementsfor cross-driver useDBIx::Class::TimeStamp and DBIx::Class::Helpers functionality integrated into core
Native driver distributions for each database (DBIO::PostgreSQL, DBIO::MySQL, DBIO::SQLite, DBIO::DuckDB) use desired-state deployment via test-and-compare; extracted drivers (DBIO::DB2, DBIO::Firebird, DBIO::MSSQL, DBIO::Oracle, DBIO::Sybase) follow the same pattern
Meta-infrastructure has been split into DBIO::Base (inherited by all internal classes);
DBIO.pmis now a pure sugar pragma
GETTING HELP
Codeberg Issues: https://codeberg.org/dbio/dbio/issues
IRC:
#dbioonirc.perl.org
CONTRIBUTING
Contributions are welcome: bug reports, documentation improvements, pull requests, or patches.
Repository: https://codeberg.org/dbio/dbio
AUTHORS
DBIO is built on top of DBIx::Class, which was a long-running collaborative effort by many contributors. See the AUTHORS file for the full list.
AUTHOR
DBIO & DBIx::Class Authors
COPYRIGHT AND LICENSE
Copyright (C) 2026 DBIO Authors Portions Copyright (C) 2005-2025 DBIx::Class Authors Based on DBIx::Class, heavily modified.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.