App-AutoCRUD

 view release on metacpan or  search on metacpan

lib/App/AutoCRUD/DataSource.pm  view on Meta::CPAN

#======================================================================
# METHODS
#======================================================================

sub config {
  my ($self, @path) = @_;
  return reach $self->config_data, @path;
}


sub descr {
  my ($self) = @_;
  return $self->config('descr');
}

sub prepare_for_request {
  my ($self, $req) = @_;

  # if schema is in single-schema mode, make sure it is connected to
  # the proper database
  my $schema = $self->schema;
  $schema->dbh($self->dbh) unless ref $schema;
}


sub primary_key {
  my ($self, $table) = @_;

  return $self->_meta_table($table)->primary_key;
}


sub colgroups {
  my ($self, $table) = @_;

  # if info already in cache, return it
  my $colgroups = $self->{colgroups}{$table};
  return $colgroups if $colgroups;

  # paths from this table
  my $meta_table = $self->_meta_table($table);
  my %paths      = $meta_table->path;

  # primary_key
  my @pk = $meta_table->primary_key;

  # get column info from database
  my $db_catalog = $self->config(qw/dbh db_catalog/);
  my $db_schema  = $self->config(qw/dbh db_schema/);
  my $sth        = $self->dbh->column_info($db_catalog, $db_schema,
                                           $table, undef);
  my $columns    = $sth->fetchall_hashref('COLUMN_NAME');

  # TMP HACK, Oracle-specific. Q: How to design a good abstraction for this ?
  $columns = $self->_columns_from_Oracle_synonym($db_schema, $table)
    if ! keys %$columns and $self->dbh->{Driver}{Name} eq 'Oracle';

  # mark primary keys
  $columns->{$_}{is_pk} = 1 foreach @pk;

  # attach paths (in alphabetic order) to relevant columns
  foreach my $path (map {$paths{$_}} sort keys %paths) {
    # name of column(s) from which this path starts
    my %path_on             = $path->on;
    my ($col_name, @others) = keys %path_on;

    # for the moment, don't handle assoc on multiple columns (TODO)
    next if @others;

    my $col = $columns->{$col_name} or next;
    my $path_subdata = { name        => $path->name,
                         to_table    => $path->to->db_from,
                         foreign_key => $path_on{$col_name} };
    push @{$col->{paths}}, $path_subdata;
  }

  # grouping: merge with column info from config
  $colgroups = clone $self->config(tables => $table => 'colgroups') || [];
  foreach my $group (@$colgroups) {
    my @columns;
    foreach my $column (@{$group->{columns}}) {
      my $col_name = $column->{name};
      my $db_col = delete $columns->{$col_name} or next;
      push @columns, {%$db_col, %$column};
    }
    $group->{columns} = \@columns;
  }

  # deal with remaining columns (present in database but unlisted in
  # config); sorted with primary keys first, then alphabetically.
  my $sort_pk = sub {   $columns->{$a}{is_pk} ? -1
                      : $columns->{$b}{is_pk} ?  1
                      :                         $a cmp $b};
  if (my @other_cols = sort $sort_pk keys %$columns) {
    # build colgroup
    push @$colgroups, {name    => 'Unclassified columns', 
                       columns => [ @{$columns}{@other_cols} ]};
  }

  # cache result and return
  $self->{colgroups}{$table} = $colgroups;
  return $colgroups;
}




sub _columns_from_Oracle_synonym {
  my ($self, $db_schema, $syn_name) = @_;

  my $dbh = $self->dbh;
  my $sql = "SELECT TABLE_OWNER, TABLE_NAME FROM ALL_SYNONYMS "
          . "WHERE OWNER=? AND SYNONYM_NAME=?";
  my ($owner, $table) = $dbh->selectrow_array($sql, {}, $db_schema, $syn_name)
    or return {};

  my $sth = $dbh->column_info(undef, $owner, $table, undef);
  return $sth->fetchall_hashref('COLUMN_NAME')
}




( run in 1.422 second using v1.01-cache-2.11-cpan-e1769b4cff6 )