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";

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

sub _find_many_to_many { ActiveRecord::Simple::Find->_find_many_to_many(shift, @_) }

sub DESTROY {}


### Private

sub _get_primary_key_value {
    my ($self) = @_;

    croak "Sory, you can call method '_get_primary_key_value' on unblessed scalar."
        unless blessed $self;

    my $pk = $self->_get_primary_key;
    return $self->$pk;
}


sub _get_relation_type {
    my ($class, $relation) = @_;

    my $type = $relation->{type};

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

        my $pk = $relation->{params}{pk};
        my $fk = $relation->{params}{fk};

        my $instance_name = "relation_instance_$relation_name";

        if (grep { $full_relation_type eq $_ } qw/one_to_many one_to_one one_to_only/) {
            *{$pkg_method_name} = sub {
                my ($self, @args) = @_;
                if (@args) {
                    my $object = shift @args;
                    croak "Using unblessed scalar as an object reference"
                        unless blessed $object;

                    $object->save() if ! exists $object->{isin_database} && !$object->{isin_database} == 1;

                    #$self->$fk($object->$pk);
                    $self->{$fk} = $object->{$pk};
                    $self->{$instance_name} = $object;

                    return $self;
                }
                # else

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

                }

                return $self->{$instance_name};
            }
        }
        elsif ($full_relation_type eq 'many_to_one') {
            *{$pkg_method_name} = sub {
                my ($self, @args) = @_;

                if (@args) {
                    unless (all_blessed(\@args)) {
                        return $related_class->find(@args)->left_join($self->_get_table_name);
                    }

                    OBJECT:
                    for my $object (@args) {
                        next OBJECT if !blessed $object;

                        my $pk = $self->_get_primary_key;
                        #$object->$fk($self->$pk)->save;
                        $object->{$fk} = $self->{$pk};
                        $object->save();
                    }

                    return $self;
                }
                # else

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

            }
        }
        elsif ($full_relation_type eq 'many_to_many') {
            *{$pkg_method_name} = sub {
                my ($self, @args) = @_;

                if (@args) {

                    my $related_subclass = _get_related_subclass($relation);

                    unless (all_blessed(\@args)) {
                        return  $related_class->_find_many_to_many({
                            root_class => $class,
                            via_table  => $relation->{via_table},
                            m_class    => $related_subclass,
                            self       => $self,
                            where_statement => \@args,
                        });
                    }


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

                            $fk2 = $related_class_relation->{params}{fk};
                        }

                        my $pk1_name = $self->_get_primary_key;
                        my $pk1 = $self->{$pk1_name};

                        defined $pk1 or croak 'You are trying to create relations between unsaved objects. Save your ' . $class . ' object first';

                        OBJECT:
                        for my $object (@args) {
                            next OBJECT if !blessed $object;

                            my $pk2_name = $object->_get_primary_key;
                            my $pk2 = $object->{$pk2_name};

                            $related_subclass->new($fk1 => $pk1, $fk2 => $pk2)->save;
                        }
                    }
                    else {
                        my ($fk1, $fk2);
                        $fk1 = $fk;

                        $fk2 = class_to_table_name($related_class) . '_id';

                        my $pk1_name = $self->_get_primary_key;
                        my $pk1 = $self->{$pk1_name};

                        my $via_table = $relation->{via_table};

                        OBJECT:
                        for my $object (@args) {
                            next OBJECT if !blessed $object;

                            my $pk2_name = $object->_get_primary_key;
                            my $pk2 = $object->{$pk2_name};

                            my $sql = qq/INSERT INTO "$via_table" ("$fk1", "$fk2") VALUES (?, ?)/;
                            $self->dbh->do($sql, undef, $pk1, $pk2);
                        }
                    }

                    return $self;

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


=head2 update

Update object using hashref

    $user->update({ last_login => \'NOW()' });


=head2 to_hash

Unbless object, get naked hash


=head2 increment

Increment fields
    
    $customer->increment('age')->save;


=head2 decrement

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


	if (!$self) {
		$self = { dbh => undef };
		if ($dsn) {
			$self->{dsn} = $dsn;
			$self->{username} = $username if $username;
			$self->{password} = $password if $password;
			$self->{connection_parameters} = $params if $params;
		}

		bless $self, $class;
	}

	return $self;
}

sub db_connect {
	my ($self) = @_;

	$self->{dbh} = DBI->connect(
		$self->{dsn},

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

use ActiveRecord::Simple::Utils qw/load_module/;


our $MAXIMUM_LIMIT = 100_000_000_000;


sub new {
    my ($self_class, $class, @param) = @_;

    #my $self = $class->new();
    my $self = bless { class => $class } => $self_class;

    my $table_name = ($self->{class}->can('_get_table_name'))  ? $self->{class}->_get_table_name  : undef;
    my $pkey       = ($self->{class}->can('_get_primary_key')) ? $self->{class}->_get_primary_key : undef;

    croak 'can not get table_name for class ' . $self->{class} unless $table_name;
    #croak 'can not get primary_key for class ' . $self->{class} unless $pkey;

    $self->{prep_select_fields} //= [];
    $self->{prep_select_from}   //= [];
    $self->{prep_select_where}  //= [];

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

package ActiveRecord::Simple::QueryManager;

use ActiveRecord::Simple::Find;


sub new { bless {}, shift }

sub all  { ActiveRecord::Simple::Find->new(shift->{caller})->fetch }
sub get  { ActiveRecord::Simple::Find->new(shift->{caller}, @_)->fetch }
sub find { ActiveRecord::Simple::Find->new(shift->{caller}, @_) }

sub sql_fetch_all {
    my ($self, $sql, @bind) = @_;

    my $data = $self->{caller}->dbh->selectall_arrayref($sql, { Slice => {} }, @bind);
    my @list;
    for my $row (@$data) {
        $self->{caller}->_mk_ro_accessors([keys %$row]);
        bless $row, $self->{caller};
        push @list, $row;
    }

    return \@list;
}

sub sql_fetch_row {
    my ($self, $sql, @bind) = @_;

    my $row = $self->{caller}->dbh->selectrow_hashref($sql, undef, @bind);
    $self->{caller}->_mk_ro_accessors([keys %$row]);
    bless $row, $self->{caller};

    return $row;
}

1;

__END__;

=head1 NAME

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

package ActiveRecord::Simple::Utils;

use strict;
use warnings;

require Exporter;

use Module::Load;
use Module::Loaded;

use Scalar::Util qw/blessed/;

our @ISA = qw/Exporter/;
our @EXPORT = qw/class_to_table_name all_blessed load_module/;


sub quote_sql_stmt {
    my ($sql, $driver_name) = @_;

    return unless $sql && $driver_name;

    $driver_name //= 'Pg';
    my $quotes_map = {
        Pg => q/"/,

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


sub is_numeric {
    my ($data_type) = @_;

    return unless $data_type;
    return 1 if is_integer($data_type);

    return grep { $data_type eq $_ } qw/numeric decimal/;
}

sub all_blessed {
    my ($list) = @_;

    for my $item (@$list) {
        return unless defined $item;
        return unless blessed $item;
    }

    return 1;
}

sub load_module {
    my ($module_name) = @_;

    if (!is_loaded $module_name) {
        eval { load $module_name; };

t/08-basic.t  view on Meta::CPAN


use base 'ActiveRecord::Simple';


package MockDBI;

sub selectrow_array { 1 }
sub do { 1 }
sub selectrow_hashref { { DUMMY => 'hash' } }
sub fetchrow_hashref { { DUMMY => 'hash' } }
sub prepare { bless {}, 'MockDBI' }
sub execute { 1 }
sub last_insert_id { 1 }
sub selectall_arrayref { [{ foo => 1  }, { bar => 2 }] }

1;

*ActiveRecord::Simple::dbh = sub {
    return bless { Driver => { Name => 'mysql' } }, 'MockDBI';
};

package main;

use Test::More;

ok my $c = t::class->new({
    foo => 1,
    bar => 2,
});

t/12-connect.t  view on Meta::CPAN


use strict;
use warnings;
use 5.010;

use FindBin '$Bin';
use lib "$Bin/../lib";
use Data::Dumper;

use DBI;
#use Scalar::Util qw/blessed/;


package Customer;

use parent 'ActiveRecord::Simple';


__PACKAGE__->table_name('customers');
__PACKAGE__->primary_key('id');
__PACKAGE__->columns(qw/id first_name second_name age email/);



( run in 0.535 second using v1.01-cache-2.11-cpan-de7293f3b23 )