Aniki
view release on metacpan or search on metacpan
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
- Small & Simple
You can read codes easily.
- Object mapping
Inflates rows to [Aniki::Result::Collection](https://metacpan.org/pod/Aniki::Result::Collection) object.
And inflates row to [Aniki::Row](https://metacpan.org/pod/Aniki::Row) object.
You can change result class, also we can change row class.
Aniki dispatches result/row class by table. (e.g. `foo` table to `MyDB::Row::Foo`)
- Raw SQL support
Supports to execute raw `SELECT` SQL and fetch rows of result.
Of course, Aniki can inflate to result/row also.
- Query builder
Aniki includes query builder powered by [SQL::Maker](https://metacpan.org/pod/SQL::Maker).
[SQL::Maker](https://metacpan.org/pod/SQL::Maker) is fast and secure SQL builder.
- Fork safe & Transaction support
Aniki includes [DBI](https://metacpan.org/pod/DBI) handler powered by [DBIx::Handler](https://metacpan.org/pod/DBIx::Handler).
- Error handling
Easy to handle execution errors by `handle_error` method.
You can override it.
- Extendable
You can extend Aniki by [Mouse::Role](https://metacpan.org/pod/Mouse::Role).
Aniki provides some default plugins as [Mouse::Role](https://metacpan.org/pod/Mouse::Role).
## 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
- schema : ClassName
- handler : ClassName
- filter : ClassName
- row : ClassName
- result : ClassName
- query\_builder : ClassName
### `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](https://metacpan.org/pod/SQL::Maker)'s strict mode.
This method returns true value default.
So you need to disable [SQL::Maker](https://metacpan.org/pod/SQL::Maker)'s strict mode, override it and return false value.
SEE ALSO: [The JSON SQL Injection Vulnerability](http://blog.kazuhooku.com/2014/07/the-json-sql-injection-vulnerability.html)
### `preload_all_row_classes`
Preload all row classes.
### `preload_all_result_classes`
Preload all result classes.
### `guess_result_class($table_name) : ClassName`
( run in 0.737 second using v1.01-cache-2.11-cpan-a5162978ef8 )