# NAME

DBIx::Fast - Object Relational Mapping for the lazy programmer

# SYNOPSIS

    package MyApp::DAO::Users;
    
    use strict;
    use warnings;
    
    use DBIx::Fast;

    table 'users';

    has dbh => (is => 'ro', required => 1);

    field id => (is => 'ro', search => 1, pk => 1);
    field username => (is => 'rw', search => 1, required => 1, column => 'user_name');
    field id_address => (is => 'rw', search => 1, fk => ['MyApp::DAO::Addresses', 'id', 'addresses', 'users']);

    fix;

And elsewhere:

    my $user = MyApp::DAO::Users::Instance->new(username => 'lazybastard', id_address => 5);
    my $dao = MyApp::DAO::Users->new(dbh => DBI->connect(...));
    $dao->insert($user)
    ($user) = @{$dao->search(username => 'lazybastard')};
    $user->username('lazyandproductive');
    $dao->update($user, 'username');
    $user = $user->fetch_again; 
    $dao->delete($user);

# DESCRIPTION

`DBIx::Fast` is the needed bridge between Moo and your database, you create DAO objects in a similar fashion to Moo and those objects auto-create
the corresponding instances under the same package plus ::Instance, importing this module becomes your package into a Moo class and the created
class is also a Moo one.

Many times writing object to relational database mapping you find yourself having to repeat the same information once and once again which becomes
tiring for the developer, Models and DAO are created in a single step in a single file to prevent this, but they remain completely separate classes,
methods are provided to take full advantage of the separation.

The Moo syntax also provides shorter code overall.

This module is preliminar, meaning the syntax is probably not the definitive one, if you are a programmer who wants to spend less effort into
making full blown applications feel free to join the development with suggestions or patches.

If you are needing too fancy autocomplete or templates just to be productive maybe you instead need `DBIx::Fast`.

# DAO DECLARATIONS

While declaring a DBIx::Fast mapping you can use the following subs autoimported into your package namespace.

## table

    table 'transactions';

Specify the table this DAO maps to.

## field

    field id => (is => 'ro', pk => 1, search => 1);
    field amount => (is => 'ro', required => 1, search => 1, column => 'amnt');
    field tax => (is => 'ro');
    field id_user => (is => 'ro', required => 1, search => 1, fk => ['MyApp::DAO::Users', 'id', 'users', 'transactions']);

field is the equivalent to `Moo` `has` sub implementing all its options (useful or not) to represent a column into the table.

It provides the following extra options:

### pk

Defines the primary key if sent a trueish value

### search

Marks this column as searchable for the generated search method.

### column

Allows to change the destination column by default it would be called as the field itself. 

### fk

Takes four arguments: The destination class, the destination field, the method to represent in our model the remote class and optionally the remote instance method to represent our own class.

## fix

Ensures the class is ready to be used and marks the class as ready.

## instance\_sub

    instance_sub uppercase_username => sub {
           my $self = shift;
           return uc($self->username);
    };

and later:

    $user->uppercase_username;

Declares a subroutine to be added to the generated ::Instance Object.

## instance\_has

    instance_has cache => (is => 'lazy');
    instance_sub _build_cache => sub {
           my $redis = Redis->new;
           return $redis;
    };

Makes a Moo attribute available to the ::Instance Object with the same syntax than Moo has.

## dbh

You must declare a dbh method or a Moo attribute returning a DBI connection.

# DAO METHODS

## search

    my @transactions = @{$dao->search(
           # SQL::Abstract::More where syntax using field names instead of columns
           amnt => { '>', 10000 },
           tax  => 21,
    )}

Searchs ::Instance Objects in the table using SQL::Abstract::More where syntax but replacing the column names by field names.

## free\_search

    my @transactions = @{$dao->free_search(
           -join => [
                   'users.id=transactions.id_user users',
           ],
           -where => {
                   'users.surname' => {-like => 'Gar%},
           },
    )};

Searchs ::Instance Objects in the table using all the syntax of SQL::Abstract::More select, columns are the real columns not fields.

\-columns and -from are not allowed to be used. -from should be substituted by -join and -columns is not needed.

## insert

    $dao->insert(MyApp::DAO::Users::Instance->new(username => 'ent'));

Inserts a row in the table, doesn't return the inserted field. You can use UUIDs or other known unique attributes of the table to search for
the inserted object.

## update

    $user->username('X');
    $user->surname('González');
    $dao->update($user, 'username', 'surname');

Takes an instance and a list of the fields that should be updated in db with the instance data for that row, updates them and doesn't have a
meaningful return. Searches the object to update by the primary key.

## delete

    $dao->delete($user);

Vanishes the instance of the database. Searches by the primary key.

# BUGS AND LIMITATIONS

Every DAO/Instance must be associated directly with a table, if you need something extra, the good old and reliable [SQL::Abstract::More](https://metacpan.org/pod/SQL%3A%3AAbstract%3A%3AMore) is 
enough to you.

Errors must be improved to allow users to debug easier faulty code.

API is not stable since this program is so early in its development that I do not know if incorrect assumptions or bad design is hiding here.

No many to many easy wrapper, use free\_search, I could not come up with something that would be better than directly creating your own
queries with free\_search.

# AUTHOR

SERGIOXZ - Sergio Iglesias

# CONTRIBUTORS

SERGIOXZ - Sergio Iglesias

# COPYRIGHT

Copyright © Sergio Iglesias (2025)

# LICENSE

This library is free software and may be distributed under the same terms
as perl itself. See [https://dev.perl.org/licenses/](https://dev.perl.org/licenses/).
