The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

Build Status Coverage Status MetaCPAN Release

NAME

Aniki - The ORM as our great brother.

SYNOPSIS

```perl use 5.014002; package MyProj::DB::Schema { use DBIx::Schema::DSL;

create_table 'module' => columns {
    integer 'id', primary_key, auto_increment;
    varchar 'name';
    integer 'author_id';

    add_index 'author_id_idx' => ['author_id'];

    belongs_to 'author';
};

create_table 'author' => columns {
    integer 'id', primary_key, auto_increment;
    varchar 'name', unique;
};

};

package MyProj::DB::Filter { use Aniki::Filter::Declare; use Scalar::Util qw/blessed/; use Time::Moment;

# define inflate/deflate filters in table context.
table author => sub {
    inflate name => sub {
        my $name = shift;
        return uc $name;
    };

    deflate name => sub {
        my $name = shift;
        return lc $name;
    };
};

inflate qr/_at$/ => sub {
    my $datetime = shift;
    $datetime =~ tr/ /T/;
    $datetime .= 'Z';
    return Time::Moment->from_string($datetime);
};

deflate qr/_at$/ => sub {
    my $datetime = shift;
    return $datetime->at_utc->strftime('%F %T') if blessed $datetime and $datetime->isa('Time::Moment');
    return $datetime;
};

};

package MyProj::DB { use Mouse v2.4.5; extends qw/Aniki/;

__PACKAGE__->setup(
    schema => 'MyProj::DB::Schema',
    filter => 'MyProj::DB::Filter',
    row    => 'MyProj::DB::Row',
);

};

package main { my $db = MyProj::DB->new(connect_info => ["dbi:SQLite:dbname=:memory:", "", ""]); $db->execute($_) for split /;/, MyProj::DB::Schema->output;

my $author_id = $db->insert_and_fetch_id(author => { name => 'songmu' });

$db->insert(module => {
    name      => 'DBIx::Schema::DSL',
    author_id => $author_id,
});
$db->insert(module => {
    name      => 'Riji',
    author_id => $author_id,
});

my $module = $db->select(module => {
    name => 'Riji',
}, {
    limit => 1,
})->first;
say '$module->name:         ', $module->name;         ## Riji
say '$module->author->name: ', $module->author->name; ## SONGMU

my $author = $db->select(author => {
    name => 'songmu',
}, {
    limit    => 1,
    prefetch => [qw/modules/],
})->first;

say '$author->name:   ', $author->name;                 ## SONGMU
say 'modules[]->name: ', $_->name for $author->modules; ## DBIx::Schema::DSL, Riji

};

1; ```

DESCRIPTION

Aniki is ORM. Lite, but powerful.

FEATURES

RELATIONSHIP

Aniki supports relationship. Extracts relationship from schema class.

Example:

```perl use 5.014002; package MyProj::DB::Schema { use DBIx::Schema::DSL;

create_table 'module' => columns {
    integer 'id', primary_key, auto_increment;
    varchar 'name';
    integer 'author_id';

    add_index 'author_id_idx' => ['author_id'];

    belongs_to 'author';
};

create_table 'author' => columns {
    integer 'id', primary_key, auto_increment;
    varchar 'name', unique;
};

}; ```

A author has many modules. So you can access author row object to modules.

perl my $author = $db->select(author => { name => 'songmu' })->first; say 'modules[]->name: ', $_->name for $author->modules; ## DBIx::Schema::DSL, Riji

Also module has a author. So you can access module row object to author also.

perl my $module = $db->select(module => { name => 'Riji' })->first; say "Riji's author is ", $module->author->name; ## SONGMU

And you can pre-fetch related rows.

perl my @modules = $db->select(module => {}, { prefetch => [qw/author/] }); say $_->name, "'s author is ", $_->author->name for @modules;

SETUP

Install Aniki from CPAN:

cpanm Aniki

And run install-aniki command.

install-aniki --lib=./lib MyApp::DB

install-aniki creates skeleton modules.

METHODS

CLASS METHODS

setup(%args)

Initialize and customize Aniki class. schema is required. Others are optional.

Arguments

use_prepare_cached

If this method returns true value, Aniki uses preare_cached. This method returns true value default. So you don't need to use preare_cached, override it and return false value.

use_strict_query_builder

If this method returns true value, Aniki enables SQL::Maker's strict mode. This method returns true value default. So you need to disable SQL::Maker's strict mode, override it and return false value.

SEE ALSO: The JSON SQL Injection Vulnerability

preload_all_row_classes

Preload all row classes.

preload_all_result_classes

Preload all result classes.

guess_result_class($table_name) : ClassName

Guesses result class by table name.

guess_row_class($table_name) : ClassName

Guesses row class by table name.

new(%args) : Aniki

Create instance of Aniki.

Arguments

INSTANCE METHODS

select($table_name, \%where, \%opt)

Execute SELECT query by generated SQL, and returns result object.

```perl my $result = $db->select(foo => { id => 1 }, { limit => 1 });

stmt: SELECT FROM foo WHERE id = ? LIMIT 1

bind: [1]

```

Options

There are the options of SELECT query. See also SQL::Maker.

And you can use there options:

select_named($sql, \%bind, \%opt)

select_by_sql($sql, \@bind, \%opt)

Execute SELECT query by specified SQL, and returns result object.

```perl my $result = $db->select_by_sql('SELECT FROM foo WHERE id = ? LIMIT 1', [1]);

stmt: SELECT FROM foo WHERE id = ? LIMIT 1

bind: [1]

```

Options

You can use there options:

insert($table_name, \%values, \%opt)

Execute INSERT INTO query.

```perl $db->insert(foo => { bar => 1 });

stmt: INSERT INTO foo (bar) VALUES (?)

bind: [1]

```

insert_and_fetch_id($table_name, \%values, \%opt)

Execute INSERT INTO query, and returns last_insert_id.

```perl my $id = $db->insert_and_fetch_id(foo => { bar => 1 });

stmt: INSERT INTO foo (bar) VALUES (?)

bind: [1]

```

insert_and_fetch_row($table_name, \%values, \%opt)

Execute INSERT INTO query, and SELECT it, and returns row object.

```perl my $row = $db->insert_and_fetch_row(foo => { bar => 1 });

stmt: INSERT INTO foo (bar) VALUES (?)

bind: [1]

```

insert_and_emulate_row($table_name, \%values, \%opt)

Execute INSERT INTO query, and returns row object created by $row and schema definition.

```perl my $row = $db->insert_and_fetch_row(foo => { bar => 1 });

stmt: INSERT INTO foo (bar) VALUES (?)

bind: [1]

```

This method is faster than insert_and_fetch_row.

WARNING

If you use SQL TRIGGER or dynamic default value, this method don't return the correct value, maybe. In this case, you should use insert_and_fetch_row instead of this method.

insert_on_duplicate($table_name, \%insert, \%update)

Execute INSERT ... ON DUPLICATE KEY UPDATE query for MySQL.

```perl my $row = $db->insert_on_duplicate(foo => { bar => 1 }, { bar => \'VALUE(bar) + 1' });

stmt: INSERT INTO foo (bar) VALUES (?) ON DUPLICATE KEY UPDATE bar = VALUE(bar) + 1

bind: [1]

```

SEE ALSO: INSERT ... ON DUPLICATE KEY UPDATE Syntax

insert_multi($table_name, \@values, \%opts)

Execute INSERT INTO ... (...) VALUES (...), (...), ... query for MySQL. Insert multiple rows at once.

```perl my $row = $db->insert_multi(foo => [{ bar => 1 }, { bar => 2 }, { bar => 3 }]);

stmt: INSERT INTO foo (bar) VALUES (?),(?),(?)

bind: [1, 2, 3]

```

SEE ALSO: INSERT Syntax

update($table_name, \%set, \%where)

Execute UPDATE query, and returns changed rows count.

```perl my $count = $db->update(foo => { bar => 2 }, { id => 1 });

stmt: UPDATE foo SET bar = ? WHERE id = ?

bind: [2, 1]

```

update($row, \%set)

Execute UPDATE query, and returns changed rows count.

```perl my $row = $db->select(foo => { id => 1 }, { limit => 1 })->first; my $count = $db->update($row => { bar => 2 });

stmt: UPDATE foo SET bar = ? WHERE id = ?

bind: [2, 1]

```

delete($table_name, \%where)

Execute DELETE query, and returns changed rows count.

```perl my $count = $db->delete(foo => { id => 1 });

stmt: DELETE FROM foo WHERE id = ?

bind: [1]

```

delete($row)

Execute DELETE query, and returns changed rows count.

```perl my $row = $db->select(foo => { id => 1 }, { limit => 1 })->first; my $count = $db->delete($row);

stmt: DELETE foo WHERE id = ?

bind: [1]

```

ACCESSORS

CONTRIBUTE

I need to support documentation and reviewing my english. This module is developed on Github.

LICENSE

Copyright (C) karupanerura.

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

CONTRIBUTORS

AUTHOR

karupanerura karupa@cpan.org