NAME

DBIO::Candy - Sugar syntax for defining DBIO result classes

VERSION

version 0.900004

SYNOPSIS

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

table 'artists';

primary_column id => {
    data_type => 'integer',
    is_auto_increment => 1,
};

column name => {
    data_type => 'varchar',
    size => 100,
};

column bio => {
    data_type => 'text',
    is_nullable => 1,
};

column created_at => {
    data_type => 'timestamp',
    set_on_create => 1,
};

column updated_at => {
    data_type => 'timestamp',
    set_on_create => 1,
    set_on_update => 1,
};

unique_constraint [qw(name)];
has_many cds => 'MyApp::Schema::Result::CD', 'artist_id';

1;

PostgreSQL-specific example:

package MyApp::Schema::Result::User;
use DBIO::Candy -components => ['InflateColumn::DateTime', 'InflateColumn::Serializer'];

table 'users';

primary_column id => {
    data_type => 'uuid',
    retrieve_on_insert => 1,
};

column name => {
    data_type => 'varchar',
    size => 100,
};

column role => {
    data_type => 'enum',
    extra => { list => [qw( admin moderator user guest )] },
    is_nullable => 1,
};

column metadata => {
    data_type => 'jsonb',
    default_value => '{}',
    serializer_class => 'JSON',
};

column embedding => {
    data_type => 'vector',
    size => 1536,
};

column tags => {
    data_type => 'text[]',
    is_nullable => 1,
};

column created_at => {
    data_type => 'timestamp',
    set_on_create => 1,
};

column updated_at => {
    data_type => 'timestamp',
    set_on_create => 1,
    set_on_update => 1,
};

column deleted_at => {
    data_type => 'timestamp',
    is_nullable => 1,
};

1;

See t/candy_indices.t for a runnable example.

DESCRIPTION

DBIO::Candy sits between vanilla DBIO::Core and DBIO::Cake. It keeps the familiar method-based API, but imports shorter helper names so result classes read more cleanly.

By default it:

  • turns on strict and warnings

  • sets your parent class to DBIO::Core

  • exports package methods used to define results as simple subroutines

  • aliases some method names for clarity

  • cleans the namespace after export via namespace::clean

METHODS

base

sub base { $_[1] || 'MyApp::Schema::Result' }

Class-method hook, called with the -base import value. Returns the parent class(es) to add to the result class; the default returns that value or DBIO::Core. Override in a subclass to change the default (see "SETTING DEFAULT IMPORT OPTIONS").

perl_version

Hook called with the -perl5 import value (already converted to a number from a v-string). A true return enables use feature ":5.$n" in the result class. The default returns its argument.

autotable

Hook called with the -autotable import value. A true return makes Candy set the table name from the class name on the first sugar call, using "gen_table". The default returns its argument.

experimental

Hook called with the -experimental import value. A true return must be an arrayref of feature names, which are passed to experimental. The default returns its argument.

gen_table

my $table = $candy->gen_table($class, $version);

Derives a table name from a result class name: takes the part after ::Result:: (croaking on any other naming scheme), strips :: and decamelizes. $version 'singular' returns that; 1 additionally pluralizes through Lingua::EN::Inflect. See "AUTOTABLE VERSIONS".

gen_custom_imports

my ($methods, $aliases) = $candy->gen_custom_imports($result_class);

Walks the linearised @ISA of the result class and collects the extra methods and aliases every class in it registered through DBIO::Candy::Exports. Returns an arrayref of method names and a hashref of alias to method.

parse_arguments

my $args = $candy->parse_arguments(\@import_args);

Splits the import list into the known options (-base, -autotable, -perl5, -experimental, -components, each taking the following value) and everything else. Returns { base, autotable, perl_version, components, experimental, rest => [...] }; one-character -autotable and -perl5 values (v-strings) are converted with ord.

gen_primary_column

gen_unique_column

gen_has_column

gen_indices

gen_proxy

gen_rename_proxy

Generator hooks for Sub::Exporter: each returns a generator that builds the exported sugar sub for one result class ("primary_column", "unique_column", "has_column", "indices", the plain method proxies of "IMPORTED SUBROUTINES", and the renamed ones of "IMPORTED ALIASES"). Every generated sub first applies the autotable name (once), then calls the corresponding class method on the result class.

installer

Returns the Sub::Exporter installer: the default installer, followed by namespace::clean on every installed sugar sub, so none of them remains a method of the result class.

set_base

$candy->set_base($result_class, $base);

Loads the class(es) "base" returns for $base and appends them to the result class's @ISA, skipping any already present (idempotent, so a reload does not duplicate them).

gen_INIT

Returns the INIT collector run on every import: turns on strict and warnings, enables the requested :5.N feature bundle and experimental features (dying unless the latter is an arrayref), and sets the result class's MRO to c3.

IMPORT OPTIONS

Candy is a good fit when you want lighter syntax but still prefer explicit column hashrefs over Cake's DDL-style declarations.

-base

use DBIO::Candy -base => 'MyApp::Schema::Result';

Set the parent class. Defaults to DBIO::Core.

-autotable

use DBIO::Candy -autotable => v1;

Automatically generate the table name from the class name. Version v1 pluralizes (Cat becomes cats), 'singular' does not.

-components

use DBIO::Candy -components => ['InflateColumn::DateTime'];

Load components at import time so they can register their own sugar via DBIO::Candy::Exports.

-perl5

use DBIO::Candy -perl5 => v10;

Enable Perl feature flags (equivalent to use feature ':5.10').

-experimental

use DBIO::Candy -experimental => ['signatures'];

Enable experimental features.

IMPORTED SUBROUTINES

The following are exported with the same name and arguments as their __PACKAGE__->method equivalents:

belongs_to
has_many
has_one
inflate_column
many_to_many
might_have
remove_column
remove_columns
resultset_attributes
resultset_class
sequence
source_name
table

IMPORTED ALIASES

Shorter or clearer names for common methods:

column            => 'add_columns'
primary_key       => 'set_primary_key'
unique_constraint => 'add_unique_constraint'
relationship      => 'add_relationship'

TRANSFORMER FUNCTIONS

has_column

has_column foo => (
  data_type => 'varchar',
  size => 25,
);

Like add_columns but takes a flat list of key/value pairs (Moose-style) and wraps them into a hashref.

primary_column

primary_column id => {
  data_type => 'int',
  is_auto_increment => 1,
};

Defines a column and adds it to the primary key in a single call.

unique_column

unique_column name => {
  data_type => 'varchar',
  size => 30,
};

Defines a column and adds a unique constraint on it in a single call.

indices

indices(
  name_idx       => 'name',
  name_email_idx => ['name', 'email'],
);

Declares one or more secondary indexes on the table. Field lists may be a single column name or an arrayref of column names. Equivalent to the DBICx::Indexing component on DBIx::Class. Each index is stored as a canonical declaration on the result source ("index_declarations" in DBIO::ResultSource), which the native driver deploy path reads.

SETTING DEFAULT IMPORT OPTIONS

Create a subclass to avoid repeating import options:

package MyApp::Schema::Candy;
use base 'DBIO::Candy';

sub base { $_[1] || 'MyApp::Schema::Result' }
sub perl_version { 12 }
sub autotable { 1 }
sub experimental { ['signatures'] }

Then in your result classes:

use MyApp::Schema::Candy;

AUTOTABLE VERSIONS

v1

Extracts the part after ::Result::, removes ::, decamelizes, and pluralizes:

MyApp::Schema::Result::Cat           -> cats
MyApp::Schema::Result::LonelyPerson  -> lonely_people

'singular'

Same as v1 but without pluralization:

MyApp::Schema::Result::Cat           -> cat
MyApp::Schema::Result::LonelyPerson  -> lonely_person

TIMESTAMP HELPERS

These are proxy methods for DBIO::Timestamp (loaded automatically):

col_created

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

col_updated

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

cols_updated_created

cols_updated_created;      # creates both at once

The most common pattern -- one line for both timestamp columns.

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.