ActiveRecord-Simple

 view release on metacpan or  search on metacpan

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

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,
    };

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


    return 'id' if $what_key eq 'primary_key';

    #eval { load $class }; ### TODO: check class has been loaded 
    #load $class unless is_loaded $class;
    #mark_as_loaded $class;
    load_module $class;


    my $table_name = _what_is_the_table_name($class);
    
    $table_name =~ s/s$// if $what_key eq 'foreign_key';

    return ($what_key eq 'foreign_key') ? "$table_name\_id" : undef;
}

sub _delete_keys {
    my ($self, $rx) = @_;

    map { delete $self->{$_} if $_ =~ $rx } keys %$self;
}

sub _append_relation {
    my ($class, $rel_name, $rel_hashref) = @_;

    if ($class->can('_get_relations')) {
        my $relations = $class->_get_relations();
        $relations->{$rel_name} = $rel_hashref;
        $class->relations($relations);
    }
    else {
        $class->relations({ $rel_name => $rel_hashref });
    }

    return $rel_hashref;
}

sub _mk_attribute_getter {
    my ($class, $method_name, $return) = @_;

    return if $class->can($method_name);

    eval "package $class; \n sub $method_name { \$return }";
}

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

    my $relations = $class->_get_relations;

    no strict 'refs';
    RELATION_NAME:
    for my $relation_name ( keys %{ $relations }) {
        my $pkg_method_name = $class . '::' . $relation_name;
        next RELATION_NAME if $class->can($pkg_method_name); ### FIXME: orrrr $relation_name???

        my $relation           = $relations->{$relation_name};
        my $full_relation_type = _get_relation_type($class, $relation);
        my $related_class      = _get_related_class($relation);

        ### TODO: check for error if returns undef
        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
                if (!$self->{$instance_name}) {
                    $self->{$instance_name} = $related_class->objects->get($self->{$fk}) // $related_class;
                }

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

                if (!$self->{$instance_name}) {
                    $self->{$instance_name} = $related_class->find("$fk = ?", $self->{$pk})->fetch;
                }

                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;



( run in 1.473 second using v1.01-cache-2.11-cpan-39a47a84364 )