ActiveRecord-Simple

 view release on metacpan or  search on metacpan

lib/ActiveRecord/Simple.pm  view on Meta::CPAN

package ActiveRecord::Simple;

use 5.010;
use strict;
use warnings;

our $VERSION = '1.11';

use utf8;
use Carp;
use Scalar::Util qw/blessed/;

use ActiveRecord::Simple::QueryManager;
use ActiveRecord::Simple::Utils qw/all_blessed class_to_table_name load_module/;
use ActiveRecord::Simple::Connect;

our $connector;
my $qm = ActiveRecord::Simple::QueryManager->new();


sub new {
    my $class = shift;
    my $params = (scalar @_ > 1) ? {@_} : $_[0];

    # relations
    $class->_init_relations if $class->can('_get_relations');

    return bless $params || {}, $class;
}

sub auto_load {
   my ($class) = @_;

    my $table_name = class_to_table_name($class);

    # 0. check the name
    my $table_info_sth = $class->dbh->table_info('', '%', $table_name, 'TABLE');
    $table_info_sth->fetchrow_hashref or croak "Can't find table '$table_name' in the database";

    # 1. columns list
    my $column_info_sth = $class->dbh->column_info(undef, undef, $table_name, undef);
    my $cols = $column_info_sth->fetchall_arrayref({});

    my @columns = ();
    push @columns, $_->{COLUMN_NAME} for @$cols;

    # 2. Primary key
    my $primary_key_sth = $class->dbh->primary_key_info(undef, undef, $table_name);
    my $primary_key_data = $primary_key_sth->fetchrow_hashref;
    my $primary_key = ($primary_key_data) ? $primary_key_data->{COLUMN_NAME} : undef;

    $class->table_name($table_name) if $table_name;
    $class->primary_key($primary_key) if $primary_key;
    $class->columns(@columns) if @columns;
}

sub connect {
    my ($class, $dsn, $username, $password, $options) = @_;

    eval { require DBIx::Connector };

    $options->{HandleError} = sub {
        my ($error_message, $DBI_st) = @_;

        $error_message or return;
        croak $error_message;

    } if ! exists $options->{HandleError};

    if ($@) {
        $connector = ActiveRecord::Simple::Connect->new($dsn, $username, $password, $options);
        $connector->db_connect;
    }
    else {
        $connector = DBIx::Connector->new($dsn, $username, $password, $options);
    }

    return 1;
}

sub belongs_to {
    my ($class, $rel_name, $rel_class, $params) = @_;

    my $new_relation = {
        class => $rel_class,
        type => 'one',
    };

    my $primary_key = $params->{pk} ||
        $params->{primary_key} ||
        _guess(primary_key => $class);

    my $foreign_key = $params->{fk} ||
        $params->{foreign_key} ||
        _guess(foreign_key => $rel_class);

    $new_relation->{params} = {
        pk => $primary_key,
        fk => $foreign_key,
    };

    $class->_append_relation($rel_name => $new_relation);
    #$class->_mk_relations_accessors;
}

sub has_many {
    my ($class, $rel_name, $rel_class, $params) = @_;

    my $new_relation = {
        class => $rel_class,
        type => 'many',
    };

    $params ||= {};
    my $primary_key = $params->{pk} ||
        $params->{primary_key} ||
        _guess(primary_key => $class);

    my $foreign_key = $params->{fk} ||
        $params->{foreign_key} ||
        _guess(foreign_key => $class);

    $new_relation->{params} = {
        pk => $primary_key,
        fk => $foreign_key,
    };

    $new_relation->{via_table} = $params->{via} if $params->{via};

    $class->_append_relation($rel_name => $new_relation);
    #$class->_mk_relations_accessors;
}

sub has_one {
    my ($class, $rel_name, $rel_class, $params) = @_;

lib/ActiveRecord/Simple.pm  view on Meta::CPAN


    # connect to the database:
    __PACKAGE__->connect($dsn, $opts);


    package Customer;

    use parent 'Model';

    __PACKAGE__->table_name('customer');
    __PACKAGE__->columns(qw/id first_name last_login/);
    __PACKAGE__->primary_key('id');

    __PACKAGE__->has_many(purchases => 'Purchase');


    package Purchase;

    use parent 'Model';

    __PACKAGE__->auto_load(); ### load table_name, columns and primary key from the database automatically

    __PACKAGE__->belongs_to(customer => 'Customer');


    package main;

    # get customer with id = 1:
    my $customer = Customer->objects->find({ id => 1 })->fetch(); 

    # or (the same):
    my $customer = Customer->objects->get(1);

    print $customer->first_name; # print first name
    $customer->last_login(\'NOW()'); # to use built-in database function just send it as a SCALAR ref
    $customer->save(); # save in the database

    # get all purchases of $customer:
    my @purchases = Purchase->objects->find(customer => $customer)->fetch();

    # or (the same):
    my @purchases = $customer->purchases->fetch();

    # order, group and limit:
    my @purchases = $customer->purchases->order_by('paid')->desc->group_by('kind')->limit(10)->fetch();

=head1 CLASS METHODS

L<ActiveRecord::Simple> implements the following class methods.

=head2 new

Object's constructor.

    my $log = Log->new(message => 'hello', level => 'info');

=head2 connect

Connect to the database, uses DBIx::Connector if installed, if it's not - L<ActiveRecord::Simple::Connect>.
    
    __PACKAGE__->connect($dsn, $username, $password, $options);


=head2 dbh

Access to the database handler. Undef if it's not connected.

    __PACKAGE__->dbh->do('SELECT 1');


=head2 table_name

Set table name.

    __PACKAGE__->table_name('log');


=head2 columns

Set columns. Make accessors if make_columns_accessors not 0 (default is 1)

    __PACKAGE__->columns('id', 'time');


=head2 primary_key

Set primary key. Optional parameter.

    __PACKAGE__->primary_key('id');


=head2 secondary_key

Set secondary key.

    __PACKAGE__->secondary_key('time');


=head2 auto_load

Load table_name, columns and primary_key from table_info (automatically from database).

    __PACKAGE__->auto_load();


=head2 has_many

Create a ralation to another table (many-to-many, many-to-one).

    Customer->has_many(purchases => 'Purchase');
    # if you need to set a many-to-many relation, you have to 
    # specify a third table using "via" key:
    Pizza->has_many(toppings => 'Topping', { via => 'pizza_topping' });


=head2 belongs_to

Create a relation to another table (one-to-many, one-to-one). Foreign key is an optional
parameter, default is <table tane>_id.

    Purchase->belongs_to(customer => 'Customer');



( run in 0.438 second using v1.01-cache-2.11-cpan-df04353d9ac )