DBIx::...actory(3pm)

πŸ’– DBIx::Class::Factory πŸ’–

okay so bestie, you've landed on the DBIx::Class::Factory page from the User Contributed Perl Documentation (yes, the 3pm collection, you know the one πŸ’…). It's Version 0.04 and it is so good, I'm obsessed.


✨ NAME ✨

DBIx::Class::Factory β€” factory-style fixtures for DBIx::Class. that's it, that's the whole vibe. 🌸


πŸŽ€ VERSION πŸŽ€

Version 0.04 β€” tiny number, big energy. πŸ¦‹


🌈 SYNOPSIS 🌈

First things first: you make a factory. Look at her:

package My::UserFactory;
use base qw(DBIx::Class::Factory);

__PACKAGE__->resultset(My::Schema->resultset('User'));
__PACKAGE__->fields({
    name => __PACKAGE__->seq(sub {'User #' . shift}),
    status => 'new',
});

package My::SuperUserFactory;
use base qw(DBIx::Class::Factory);

__PACKAGE__->base_factory('My::UserFactory');
__PACKAGE__->field(superuser => 1);

then you USE the factory, which is the fun part:

my $user = My::UserFactory->create();
my @verified_users = @{ My::UserFactory->create_batch(3, {status => 'verified'}) };

my $superuser = My::SuperUserFactory->build();
$superuser->insert();

see how the superuser got superuser => 1 just handed to her by her factory mom? inheritance but make it slay. πŸ’…


πŸ¦‹ DESCRIPTION πŸ¦‹

Ruby has factory_girl. Python has factory_boy. And now? Perl has DBIx::Class::Factory. we're in the group chat now, bestie. 😌

ngl, creating big fixture batches can be a whole pain. This module gives you an easy way to create data in your database through DBIx::Class.

To make a factory you literally just derive from DBIx::Class::Factory and apply some settings. You can also toss in extra data at the exact moment you create an instance, which overrides the factory defaults. cute, right?

and listen β€” the tests for this module contain a whole bunch of useful examples. go look, no cap. πŸ‘€


🧚 METHODS 🧚

🌸 Factory settings 🌸

  • base_factory β€” use this when you want one factory derived from another. bestie, do NOT use direct inheritance here, that's not the move, base_factory is.
  • resultset β€” sets the resultset this factory is going to work with.
  • fields β€” takes a hashref as an argument and adds fields to the factory. want the deets? go read "field".
  • field β€” adds a field to the factory:
__PACKAGE__->field($name => $value);

$name gets used directly in the resultset's "new" method. $value can be literally any value, or a helper result (peep "Helpers"). If you hand it a "CODEREF" as the value, that coderef gets used as a callback β€” but do not rely on this, it can change in future releases. use the "callback" helper instead, fr fr.

  • exclude β€” sometimes you want a field to live in the factory but not end up in the created object. that's what "exclude" is for. it takes an arrayref or a scalar, both are fine. 🫢
{
    package My::UserFactory;

    use base qw(DBIx::Class::Factory);

    __PACKAGE__->resultset(My::Schema->resultset('User'));
    __PACKAGE__->exclude('all_names');
    __PACKAGE__->fields({
        first_name => __PACKAGE__->callback(sub {shift->get('all_names')}),
        last_name => __PACKAGE__->callback(sub {shift->get('all_names')}),
    });
}

My::UserFactory->create({all_names => 'Bond'});

πŸ’… Helpers πŸ’…

sometimes you don't want the field value to just be some static little guy β€” you want it to be something special. that's literally what helpers are for. iconic.

  • callback β€” when you want the field value recalculated every single time the fields for an object get created, just give "callback" as the value. it gets called with the DBIx::Class::Factory::Fields instance as its argument. πŸ’–
__PACKAGE__->fields({
    status => __PACKAGE__->callback(sub {
        my ($fields) = @_;

        return $fields->get('superuser') ? 3 : 5;
    }),
});
  • seq β€” same as "callback", but the callback also gets an extra first argument: the iterating counter. you can hand over the counter's initial value too (default is 0, bestie). πŸ”’
__PACKAGE__->field(id => __PACKAGE__->seq(sub {shift}, 1));
  • related_factory β€” this helper just calls another factory's "get_fields" method. and thanks to "DBIx::Class", the data it hands back gets used to create a related object. look at her go:
package My::UserFactory;

use base qw(DBIx::Class::Factory);

__PACKAGE__->resultset(My::Schema->resultset('User'));
__PACKAGE__->fields({
    # create a new city if it's not specified
    city => __PACKAGE__->related_factory('My::CityFactory'),
});
  • related_factory_batch β€” same as "related_factory" but it calls the "get_fields_batch" method instead. batch era. ✨
__PACKAGE__->fields({
    # Add three accounts to the user
    accounts => __PACKAGE__->related_factory_batch(3, 'My::AccountFactory')
});

πŸ”₯ Factory actions πŸ”₯

  • get_fields β€” returns the fields that would be used to create an object, without actually creating anything. window shopping, but for data. πŸ‘€
  • build β€” creates a DBIx::Class::Row object without saving it to the database.
  • create β€” creates a DBIx::Class::Row object and saves it to the database. also, "discard_changes" in DBIx::Class::Row gets called on the created object. slay.
  • get_fields_batch β€” runs "get_fields" n times and returns an arrayref of the results.
  • build_batch β€” runs "build" n times and returns an arrayref of the results.
  • create_batch β€” runs "create" n times and returns an arrayref of the results.

πŸŽ€ Hooks πŸŽ€

you can define the methods below in your factory, and they'll run after their corresponding methods. they take the result of that corresponding method as an argument, and they must return the new one. no returning undef and ghosting me, bestie. πŸ™ˆ

  • after_get_fields
  • after_build
  • after_create
sub after_create {
    my ($class, $user_row) = @_;

    $user_row->auth();

    return $user_row;
}

🫢 DEDICATION 🫢

this module is lovingly dedicated to my wife Catherine. πŸ˜­πŸ’– not me crying over a CPAN module.


πŸ‘‘ AUTHOR πŸ‘‘

Vadim Pushtaev, "pushtaev@cpan.org". legend behavior.


πŸ’€ BUGS AND FEATURES πŸ’€

Bugs are possible, feature requests are welcome. Write me as soon as possible. (as in, literally as soon as possible, don't leave me on read βœ‹)


Copyright 2015 Vadim Pushtaev.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


and that's the whole page, bestie!! πŸŽ€ this one shipped with perl v5.36.0 and is dated 2023-02-14 β€” yeah, Valentine's Day, which honestly tracks given that dedication. go forth and build some fixtures. mwah. πŸ’œπŸŒˆπŸ¦‹

πŸ“¦ where this page comes from