DBIx-DataModel

 view release on metacpan or  search on metacpan

lib/DBIx/DataModel/Meta/Source.pm  view on Meta::CPAN

package DBIx::DataModel::Meta::Source;
use strict;
use warnings;
use parent "DBIx::DataModel::Meta";
use DBIx::DataModel;
use DBIx::DataModel::Meta::Utils qw/define_class define_readonly_accessors
                                    define_abstract_methods/;
use DBIx::DataModel::Carp;

use Params::Validate qw/validate_with SCALAR ARRAYREF HASHREF OBJECT/;
use Scalar::Util     qw/weaken/;
use List::MoreUtils  qw/any/;

use namespace::clean;

#----------------------------------------------------------------------
# COMPILE-TIME METHODS
#----------------------------------------------------------------------

my %common_arg_spec = (
  schema          => {isa  => "DBIx::DataModel::Meta::Schema"},
  class           => {type => SCALAR},
  default_columns => {type => SCALAR,          default => "*"},
  parents         => {type => OBJECT|ARRAYREF, default => [] },
  primary_key     => {type => SCALAR|ARRAYREF, default => [] },
  aliased_tables  => {type => HASHREF,         default => {} }, # for joins

  # other slot filled later : 'name'
);


define_readonly_accessors(__PACKAGE__, keys %common_arg_spec, 'name');
define_abstract_methods  (__PACKAGE__, qw/db_from where/);

sub _new_meta_source { # called by new() in Meta::Table and Meta::Join
  my $class         = shift;
  my $more_arg_spec = shift;
  my $isa_slot      = shift;

  # validation spec is built from a common part and a specific part
  my %spec = (%common_arg_spec, %$more_arg_spec);

  # validate the parameters
  my $self = validate_with(
    params      => \@_,
    spec        => \%spec,
    allow_extra => 0,
   );

  # force into arrayref if accepts ARRAYREF but given as scalar
  for my $attr (grep {($spec{$_}{type} || 0) & ARRAYREF} keys %spec) {
    next if not $self->{$attr};
    $self->{$attr} = [$self->{$attr}] if not ref $self->{$attr};
  }

  # the name is the short class name (before prepending the schema)
  $self->{name} = $self->{class};

  # prepend schema name in class name, unless it already contains "::"
  $self->{class} =~ s/^/$self->{schema}{class}::/
    unless $self->{class} =~ /::/;

  # avoid circular references
  weaken $self->{schema};

  # instanciate the metaclass
  bless $self, $class;

  # build the list of parent classes
  my @isa = map {$_->{class}} @{$self->{parents}};
  if ($isa_slot) {
    my $parent_class = $self->{schema}{$isa_slot}[0];
    unshift @isa, $parent_class
      unless any {$_->isa($parent_class)} @isa;
  }

  # create the Perl class
  define_class(
    name   => $self->{class},
    isa    => \@isa,
    metadm => $self,
   );

  return $self;
}


#----------------------------------------------------------------------
# RUN-TIME METHODS
#----------------------------------------------------------------------



sub ancestors { # walk through parent metaobjects, similar to C3 inheritance
  my $self = shift;
  my %seen;
  my @pool = $self->parents;
  my @result;
  while (@pool) {
    my $parent = shift @pool;
    if (!$seen{$parent}){
      $seen{$parent} = 1;
      push @result, $parent;
      push @pool, $parent->parents;
    }
  }
  return @result;
}




sub path               {shift->_consolidate_hash('path', @_)}
sub auto_insert_column {shift->_consolidate_hash('auto_insert_columns', @_)}
sub auto_update_column {shift->_consolidate_hash('auto_update_columns', @_)}
sub no_update_column   {shift->_consolidate_hash('no_update_columns', @_)}

sub _consolidate_hash {
  my ($self, $field, $optional_hash_key) = @_;
  my %hash;

  my @meta_sources = ($self, $self->ancestors, $self->{schema});

  foreach my $meta_source (reverse @meta_sources) {



( run in 0.672 second using v1.01-cache-2.11-cpan-39bf76dae61 )