NAME

DBIO::Cake - DDL-like DSL for defining DBIO result classes

VERSION

version 0.900000

SYNOPSIS

package MyApp::Schema::Result::Artist;
use DBIO::Cake;

table 'artists';

col id         => integer auto_inc;
col name       => varchar(100);
col bio        => text null;
col active     => boolean default(1);
col created_at => timestamp;
col updated_at => timestamp on_update;

primary_key 'id';
unique artist_name => ['name'];

has_many cds => 'MyApp::Schema::Result::CD', 'artist_id';

1;

PostgreSQL-specific example:

package MyApp::Schema::Result::User;
use DBIO::Cake -inflate_json;

table 'users';

col id         => uuid;
col name       => varchar(100);
col role       => enum(qw( admin moderator user guest )), null;
col metadata   => jsonb \"{}";
col embedding  => vector(1536);
col tags       => array(text), null;
col tsv        => tsvector null;
col created_at => timestamp;
col updated_at => timestamp on_update;
col deleted_at => timestamp null;

primary_key 'id';
idx user_tags => ['tags'], using => 'gin';

1;

DESCRIPTION

DBIO::Cake is the most concise way to define DBIO result classes. It keeps the same underlying schema metadata as vanilla DBIO::Core, but replaces verbose hashref-heavy declarations with a DDL-like DSL.

Use Cake when you want result classes to read like schema definitions without changing how the rest of DBIO behaves.

When you use DBIO::Cake, it automatically:

  • Enables strict and warnings

  • Sets the calling class to inherit from DBIO::Core

  • Exports all DSL functions into the calling package

  • Cleans up exported symbols after the scope ends (via namespace::clean)

COMMA-FREE SYNTAX

Cake supports a DDL-like comma-free syntax. All type functions and modifiers pass @_ through, so Perl chains them via nested function calls:

col id => integer auto_inc;     # parsed as: integer(auto_inc())
col bio => text null;           # parsed as: text(null())
col active => boolean default(1); # parsed as: boolean(default(1))

When you need a comma: after a number or closing parenthesis, Perl needs a comma before the next bareword:

col name => varchar(100), null;   # comma after (100)
col name => varchar 100, null;    # comma after 100

This matches DBIx::Class::ResultDDL conventions.

IMPORT OPTIONS

use DBIO::Cake;                            # defaults
use DBIO::Cake -inflate_datetime;          # load InflateColumn::DateTime
use DBIO::Cake -inflate_json;              # auto-inflate json/jsonb columns
use DBIO::Cake -retrieve_defaults;         # set retrieve_on_insert for columns with defaults
use DBIO::Cake -no_autoclean;              # don't clean up symbols

Multiple options can be combined:

use DBIO::Cake -inflate_datetime, -inflate_json;

SMART DEFAULTS

Cake automatically sets sensible defaults based on column type and nullability.

Timestamp columns

The behavior depends on nullability and the on_update modifier:

col created_at => timestamp;                  # NOT NULL -> set_on_create
col updated_at => timestamp on_update;        # NOT NULL -> set_on_create + set_on_update
col deleted_at => timestamp null;             # nullable -> no auto-set
col last_login => timestamp null, on_update;  # nullable -> only set_on_update

The logic: NOT NULL timestamp columns must have a value on create, so set_on_create is implied. Nullable columns don't need a value on create, so only explicit on_update is applied.

This integrates with the DBIO::Timestamp component built into DBIO core.

UUID columns

NOT NULL uuid columns automatically get retrieve_on_insert so the database-generated default (e.g. PostgreSQL's gen_random_uuid()) is retrieved after INSERT:

col id => uuid;
# -> retrieve_on_insert => 1

Scalar references as defaults

A scalar reference anywhere in a col declaration is treated as a default_value. This is a shorthand for default(\...):

col id      => uuid \"gen_random_uuid()";
col active  => boolean \1;
col created => timestamp \"now()";

# equivalent to:
col id      => uuid default(\"gen_random_uuid()");

For literal SQL defaults, use a reference to a string. For Perl-side defaults, use default($value) without a reference.

COLUMN TYPES

All type functions return flat key-value lists and pass through @_, enabling the comma-free syntax.

Integer types

integer, tinyint, smallint, bigint

col id    => integer auto_inc;
col count => bigint;

Serial types (auto-increment shortcuts)

serial, bigserial, smallserial

col id => serial;   # integer + auto_inc in one

Numeric types

numeric($precision, $scale), decimal($precision, $scale)

col price => numeric(10, 2);

Floating point types

real (alias: float4), double (alias: float8), float($bits)

String types

char($size), varchar($size)

col code => char(3);
col name => varchar(100), null;

Text types

text, tinytext, mediumtext, longtext

col bio => text null;

Binary types

blob, tinyblob, mediumblob, longblob, bytea

Boolean

boolean (alias: bool)

col active => boolean default(1);

Date/Time types

date, datetime, timestamp, time, timetz, timestamptz, interval

col created_at => timestamp;             # auto set_on_create
col updated_at => timestamp on_update;   # auto set_on_create + set_on_update
col deleted_at => timestamp null;        # no auto-set
col birthday   => date null;

Enum

enum(@values)

col role => enum(qw( admin moderator user guest ));

UUID

uuid

col id => uuid;   # auto retrieve_on_insert

JSON

json, jsonb

col metadata => jsonb null;

With -inflate_json, json/jsonb columns are automatically serialized.

Array (PostgreSQL)

array($type)

col tags => array(text), null;

Vector / AI (pgvector)

vector($dims), halfvec($dims), sparsevec($dims)

col embedding => vector(1536);

Full-text search (PostgreSQL)

tsvector, tsquery

Network types (PostgreSQL)

inet, cidr, macaddr, macaddr8

Geometric types (PostgreSQL)

point, line, lseg, box, path, polygon, circle

Range types (PostgreSQL)

int4range, int8range, numrange, tsrange, tstzrange, daterange

Other

money, xml, hstore, bit($size), varbit($size)

COLUMN MODIFIERS

All modifiers return flat key-value lists and pass through @_.

null

Marks the column as nullable.

col bio => text null;

auto_inc

Marks the column as auto-increment.

col id => integer auto_inc;

fk

Marks the column as a foreign key.

col author_id => integer fk;

unsigned

Marks the column as unsigned (MySQL).

col count => integer unsigned;

default($value)

Sets the default value.

col active => boolean default(1);
col created => timestamp default(\"now()");

on_create

Explicitly set set_on_create. Normally not needed -- NOT NULL timestamp columns get this automatically.

on_update

Set set_on_update -- the column value is refreshed on every row update.

col updated_at => timestamp on_update;

TABLE AND CONSTRAINT FUNCTIONS

table

table 'my_table';

Sets the table name for this result class.

primary_key

primary_key 'id';
primary_key 'artist_id', 'cd_id';

Sets the primary key column(s).

unique

unique \@cols;
unique $name => \@cols;

Adds a unique constraint.

RELATIONSHIP FUNCTIONS

belongs_to author => 'MyApp::Schema::Result::Author', 'author_id';
has_one    isbn   => 'MyApp::Schema::Result::ISBN', 'book_id';
has_many   books  => 'MyApp::Schema::Result::Book', 'author_id';
might_have bio    => 'MyApp::Schema::Result::Bio', 'author_id';
many_to_many roles => 'actor_roles', 'role';

rel_one

Like belongs_to but forces join_type => 'left'.

rel_many

Alias for has_many.

CASCADE HELPERS

ddl_cascade

Returns on_delete => 'CASCADE', on_update => 'CASCADE' for use in relationship attribute hashes.

dbic_cascade

Returns cascade_delete => 1, cascade_copy => 1.

VIEW SUPPORT

view

view 'my_view', 'SELECT * FROM artists WHERE active = 1';

Declares a view-based result source.

TIMESTAMP HELPERS

Shortcut functions for the most common timestamp column patterns.

col_created

col_created;               # creates 'created_at' column
col_created 'born_at';     # custom column name

Equivalent to col created_at => timestamp.

col_updated

col_updated;               # creates 'updated_at' column
col_updated 'modified_at'; # custom column name

Equivalent to col updated_at => timestamp on_update.

cols_updated_created

cols_updated_created;      # creates both created_at + updated_at

Creates both timestamp columns in one call. The most common pattern -- just add this one line and you're done.

INDEX SUPPORT

idx

idx name_idx => ['name'];
idx composite_idx => ['last_name', 'first_name'], type => 'unique';
idx tags_idx => ['tags'], using => 'gin';
idx draft_only => ['key'],
    type => 'unique',
    pg   => { where => 'version IS NULL' };

Declares an index. Cake installs two hooks on the Result class so that idx works transparently in both deployment pipelines:

  • sqlt_deploy_hookDEPRECATED hook for legacy deployment. The options key passes producer-specific options through.

  • pg_indexes — used by DBIO::PostgreSQL::DDL when the schema loads the PostgreSQL component. The pg key carries PostgreSQL-specific options (where, using, with, expression) and is passed through to the native PG DDL emitter.

If the class already defines pg_indexes by hand, those definitions are preserved and Cake-declared indexes are merged on top.

PostgreSQL partial indexes

idx agent_published => ['key', 'version'],
    type => 'unique',
    pg   => { where => 'version IS NOT NULL' };
idx agent_draft => ['key'],
    type => 'unique',
    pg   => { where => 'version IS NULL' };

SEE ALSO

DBIO::Core, DBIO::Candy, DBIO::ResultSource, DBIx::Class::ResultDDL (inspiration for Cake's syntax)

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.