<commit_before>package EnsEMBL::ORM::Rose::Object;

### NAME: EnsEMBL::Rose::ORM::Object
### Should be used only as a base class, and for a Rose-based object only

### DESCRIPTION:
### This module's children provide access to non-genomic databases, using the Rose::DB::Object suite

use strict;
use warnings;

use EnsEMBL::ORM::Rose::DbConnection;
use EnsEMBL::ORM::Rose::Manager;
use EnsEMBL::ORM::Rose::MetaData;
use EnsEMBL::Web::Exceptions;

use Rose::DB::Object::Helpers qw(as_tree forget_related has_loaded_related clone_and_reset);  ## Some extra methods that can be called on any child class object

use base qw(Rose::DB::Object);

use constant {
  ROSE_DB_NAME  => undef,         ## Name of the database connection as registered with Rose::DB (Override in child class)
  DEBUG_SQL     => undef,         ## Warns out all the mysql queries if flag is set '1'
};

__PACKAGE__->meta->error_mode('return');    ## When debugging, change from 'return' to 'carp'/'cluck'/'confess'/'croak' to produce the desired Carp behaviour
__PACKAGE__->meta->column_type_class(       ## Add extra column type(s)
  'datastructure' => 'EnsEMBL::ORM::Rose::DataStructure',
  'datamap'       => 'EnsEMBL::ORM::Rose::DataMap',
);

sub save {
  ## Tries to save the object, but does not exit perl
  ## If any error occours, object->error can return the string values of the error
  ## @return Object if saved successfully, undef otherwise
  ## @overrides
  my $self = shift;
  $Rose::DB::Object::Debug = $self->DEBUG_SQL;
  eval {
    $self->SUPER::save(@_);
  };
}

sub meta_class {
  return 'EnsEMBL::ORM::Rose::MetaData';
}

sub include_in_lookup {
  ## Flag to control wether or not to include this object in manager's get_lookup method's return value
  ## @param Class name of the related rose object
  return 1;
}

sub primary_key {
  ## Returns the name of the primary key (no composite keys)
  ## @return String
  return shift->meta->primary_key_column_names->[0];
}

sub init_db {
  ## Method called by Rose to creat connection to database
  ## Override ROSE_DB_NAME constant instead of this method
  EnsEMBL::ORM::Rose::DbConnection->new_or_cached(shift->ROSE_DB_NAME);
}

sub get_title {
  ## Returns the name of the object as defined as title_column in meta
  ## @return String
  my $self    = shift;
  my $column  = $self->meta->title_column || $self->primary_key;

  return $column ? $self->column_value($column) : '';
}

sub get_primary_key_value {
  ## Gets the value of the primary key column
  ## @return Value if primary key exists, undef otherwise
  my $self = shift;
  my $key  = $self->primary_key;
  return $key ? $self->column_value($key) : undef;
}

sub column_value {
  ## Gets/sets value for a given column
  ## It is recommended to use this method as it takes care of any column alias or datamap columns
  ## @param Column name OR Rose::DB::Object::Metadata::Column drived object OR datamap column name
  ## @param Value (only if setting the value)
  ## @return Column value when using as a getter
  my $self      = shift;
  my $col_name  = shift;
  my $meta      = $self->meta;

  my $column    = ref $col_name ? $col_name : $meta->column($col_name) || $meta->virtual_column($col_name) or throw exception('ORMException::UnknownColumnException', sprintf(q(No column with name '%s' found for %s), $col_name, ref $self));

  return $self->virtual_column_value($column, @_) if $column->isa('EnsEMBL::ORM::Rose::VirtualColumn');
  return $self->$_(@_) for (@_ ? $column->mutator_method_name : $column->accessor_method_name);
}

sub virtual_column_value {
  ## Gets/sets value of a virtual column
  ## @param Virtual column object or virtual column name
  ## @param Value (only if setting the value)
  ## @return Virtual column value when using as a getter
  my $self      = shift;
  my $col_name  = shift;

  my $column    = ref $col_name ? $col_name : $self->meta->virtual_column($col_name) or throw exception('ORMException::UnknownColumnException', sprintf(q(No virtual column with name '%s' found for %s), $col_name, ref $self));

  my $datamap   = $column->column;
  my $accessor  = $datamap->accessor_method_name;
  my $hash      = $self->$accessor;

  if (@_) {
    my $mutator       = $datamap->mutator_method_name;
    $hash->{$column}  = shift;
    $self->$mutator($hash);
  }

  return $hash->{$column};
}

sub relationship_value {
  ## Gets/sets value for a given relationship name
  ## It is recommended to use this method as it takes care of any relationship alias, and can set relationships if only foreign key values are provided
  ## @param Rose::DB::Object::Metadata::Relationship drived object, or relationship name
  ## @param Value (only if setting the value) - Can be a Rose object or a foreign key value, or a hashref containing method name key and value for singular relationships,
  ##   OR an arrayref of any of the options for multiple relationship
  ## @return Relationship value when using as a getter
  my $self      = shift;
  my $meta      = $self->meta;
  my $rel_name  = shift;
  my $relation  = ref $rel_name ? $rel_name : $meta->relationship($rel_name) or throw exception('ORMException::UnknownRelationException', sprintf(q(No relationship with name '%s' found for %s), $rel_name, ref $self));
  my $method    = $relation->method_name('get_set_on_save');
  if (@_) {
    my $value = ref $_[0] eq 'ARRAY' ? shift : [ shift ];
    if ($relation->is_singular) {
      $value = $value->[0] || undef; # no blank strings or zeros - zero will end up addind a new row to the related table
      unless (ref $value) { # if foreign key value
        my ($foreign_key)   = $relation->column_map;
        my $accessor_method = $meta->column_accessor_method_name($foreign_key);
        my $old_value       = $self->$accessor_method;
        return 1 if !$old_value && !$value || $old_value && $value && $old_value eq $value; # ignore if value not changed - this may prevent an extra SQL query on save
        $method             = $meta->column_mutator_method_name($foreign_key);
        $self->forget_related($relation->name);
      }
    }
    else {
      $value = [ grep {$_} @$value ]; # prevent adding a new row to related table by filtering out null value
    }
    return $self->$method($value);
  }
  else {
    return $self->$method;
  }
}

sub external_relationship_value {
  ## Get/set an external relationships value
  ## @param ExternalRelationship object or name
  ## @param Value to be set (optional) - Foreign rose object or value of the mapped column of the foreign rose object (or arrayref of either for '* to many' relation)
  ## @return Rose object
  my $self     = shift;
  my $meta     = $self->meta;
  my $relation = ref $_[0] ? shift : $meta->external_relationship(shift);
  my $manager  = 'EnsEMBL::ORM::Rose::Manager';
  my $key_name = $self->meta->EXTERNAL_RELATIONS_KEY_NAME;

  my ($r_name, $r_class, $r_is_singular, $r_map)  = map {$relation->$_} qw(name class is_singular column_map);
  my ($column_internal, $column_external)         = %$r_map;

  if (@_) { # Set value
    my $rose_value  = shift || []; # no '0' value
    $rose_value     = [$rose_value] unless ref $rose_value eq 'ARRAY';
    $rose_value     = $r_is_singular ? [shift @$rose_value] : $rose_value;

    # Get related rose object(s) if only foreign key value(s) provided
    if (@$rose_value && $rose_value->[0] && !UNIVERSAL::isa($rose_value->[0], $r_class)) {
      $rose_value = $manager->get_objects(<commit_msg>minor change<commit_after>package EnsEMBL::ORM::Rose::Object;

### NAME: EnsEMBL::Rose::ORM::Object
### Should be used only as a base class, and for a Rose-based object only

### DESCRIPTION:
### This module's children provide access to non-genomic databases, using the Rose::DB::Object suite

use strict;
use warnings;

use EnsEMBL::ORM::Rose::DbConnection;
use EnsEMBL::ORM::Rose::Manager;
use EnsEMBL::ORM::Rose::MetaData;
use EnsEMBL::Web::Exceptions;

use Rose::DB::Object::Helpers qw(as_tree forget_related has_loaded_related clone_and_reset);  ## Some extra methods that can be called on any child class object

use base qw(Rose::DB::Object);

use constant {
  ROSE_DB_NAME  => undef,         ## Name of the database connection as registered with Rose::DB (Override in child class)
  DEBUG_SQL     => undef,         ## Warns out all the mysql queries if flag is set '1'
};

__PACKAGE__->meta->error_mode('return');    ## When debugging, change from 'return' to 'carp'/'cluck'/'confess'/'croak' to produce the desired Carp behaviour
__PACKAGE__->meta->column_type_class(       ## Add extra column type(s)
  'datastructure' => 'EnsEMBL::ORM::Rose::DataStructure',
  'datamap'       => 'EnsEMBL::ORM::Rose::DataMap',
);

sub save {
  ## Tries to save the object, but does not exit perl
  ## If any error occours, object->error can return the string values of the error
  ## @return Object if saved successfully, undef otherwise
  ## @overrides
  my $self = shift;
  $Rose::DB::Object::Debug = $self->DEBUG_SQL;
  eval {
    $self->SUPER::save(@_);
  };
}

sub meta_class {
  return 'EnsEMBL::ORM::Rose::MetaData';
}

sub include_in_lookup {
  ## Flag to control wether or not to include this object in manager's get_lookup method's return value
  ## @param Class name of the related rose object
  return 1;
}

sub primary_key {
  ## Returns the name of the primary key (no composite keys)
  ## @return String
  return shift->meta->primary_key_column_names->[0];
}

sub init_db {
  ## Method called by Rose to creat connection to database
  ## Override ROSE_DB_NAME constant instead of this method
  EnsEMBL::ORM::Rose::DbConnection->new_or_cached(shift->ROSE_DB_NAME);
}

sub get_title {
  ## Returns the name of the object as defined as title_column in meta
  ## @return String
  my $self    = shift;
  my $column  = $self->meta->title_column || $self->primary_key;

  return $column ? $self->column_value($column) : '';
}

sub get_primary_key_value {
  ## Gets the value of the primary key column
  ## @return Value if primary key exists, undef otherwise
  my $self = shift;
  my $key  = $self->primary_key;
  return $key ? $self->column_value($key) : undef;
}

sub column_value {
  ## Gets/sets value for a given column
  ## It is recommended to use this method as it takes care of any column alias or datamap columns
  ## @param Column name OR Rose::DB::Object::Metadata::Column drived object OR datamap column name
  ## @param Value (only if setting the value)
  ## @return Column value when using as a getter
  my $self      = shift;
  my $col_name  = shift;
  my $meta      = $self->meta;

  my $column    = ref $col_name ? $col_name : $meta->column($col_name) || $meta->virtual_column($col_name) or throw exception('ORMException::UnknownColumnException', sprintf(q(No column with name '%s' found for %s), $col_name, ref $self));

  return $self->virtual_column_value($column, @_) if $column->isa('EnsEMBL::ORM::Rose::VirtualColumn');
  return $self->$_(@_) for (@_ ? $column->mutator_method_name : $column->accessor_method_name);
}

sub virtual_column_value {
  ## Gets/sets value of a virtual column
  ## @param Virtual column object or virtual column name
  ## @param Value (only if setting the value)
  ## @return Virtual column value when using as a getter
  my $self      = shift;
  my $col_name  = shift;

  my $column    = ref $col_name ? $col_name : $self->meta->virtual_column($col_name) or throw exception('ORMException::UnknownColumnException', sprintf(q(No virtual column with name '%s' found for %s), $col_name, ref $self));

  my $datamap   = $column->column;
  my $accessor  = $datamap->accessor_method_name;
  my $hash      = $self->$accessor;

  if (@_) {
    my $mutator       = $datamap->mutator_method_name;
    $hash->{$column}  = shift;
    $self->$mutator($hash);
  }

  return $hash->{$column};
}

sub relationship_value {
  ## Gets/sets value for a given relationship name
  ## It is recommended to use this method as it takes care of any relationship alias, and can set relationships if only foreign key values are provided
  ## @param Rose::DB::Object::Metadata::Relationship drived object, or relationship name
  ## @param Value (only if setting the value) - Can be a Rose object or a foreign key value, or a hashref containing method name key and value for singular relationships,
  ##   OR an arrayref of any of the options for multiple relationship
  ## @return Relationship value when using as a getter
  my $self      = shift;
  my $meta      = $self->meta;
  my $rel_name  = shift;
  my $relation  = ref $rel_name ? $rel_name : $meta->relationship($rel_name) or throw exception('ORMException::UnknownRelationException', sprintf(q(No relationship with name '%s' found for %s), $rel_name, ref $self));
  my $method    = $relation->method_name('get_set_on_save');
  if (@_) {
    my $value = ref $_[0] eq 'ARRAY' ? shift : [ shift ];
    if ($relation->is_singular) {
      $value = $value->[0] || undef; # no blank strings or zeros - zero will end up addind a new row to the related table
      unless (ref $value) { # if foreign key value
        my ($foreign_key)   = $relation->column_map;
        my $accessor_method = $meta->column_accessor_method_name($foreign_key);
        my $old_value       = $self->$accessor_method;
        return 1 if !$old_value && !$value || $old_value && $value && $old_value eq $value; # ignore if value not changed - this may prevent an extra SQL query on save
        $method             = $meta->column_mutator_method_name($foreign_key);
        $self->forget_related($relation->name);
      }
    }
    else {
      $value = [ grep {$_} @$value ]; # prevent adding a new row to related table by filtering out null value
    }
    return $self->$method($value);
  }
  else {
    return $self->$method;
  }
}

sub external_relationship_value {
  ## Get/set an external relationships value
  ## @param ExternalRelationship object or name
  ## @param Value to be set (optional) - Foreign rose object or value of the mapped column of the foreign rose object (or arrayref of either for '* to many' relation)
  ## @return Rose object
  my $self     = shift;
  my $meta     = $self->meta;
  my $relation = ref $_[0] ? shift : $meta->external_relationship(shift);
  my $manager  = 'EnsEMBL::ORM::Rose::Manager';
  my $key_name = $meta->EXTERNAL_RELATIONS_KEY_NAME;

  my ($r_name, $r_class, $r_is_singular, $r_map)  = map {$relation->$_} qw(name class is_singular column_map);
  my ($column_internal, $column_external)         = %$r_map;

  if (@_) { # Set value
    my $rose_value  = shift || []; # no '0' value
    $rose_value     = [$rose_value] unless ref $rose_value eq 'ARRAY';
    $rose_value     = $r_is_singular ? [shift @$rose_value] : $rose_value;

    # Get related rose object(s) if only foreign key value(s) provided
    if (@$rose_value && $rose_value->[0] && !UNIVERSAL::isa($rose_value->[0], $r_class)) {
      $rose_value = $manager->get_objects(
{'fraction_non_alphanumeric': 0.12593239701632955, 'fraction_numerical': 0.0013439956992137626, 'mean_word_length': 3.9392631928310653, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 122, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4369278', 'n_tokens_mistral': 4745, 'n_tokens_neox': 4604, 'n_words': 1556}