<commit_before>#!/usr/bin/perl -W

use strict;
use Carp;

use BP::Model;

package BP::Loader::Mapper::NoSQL;

# Needed for metadata model serialization
use JSON;

# Better using something agnostic than JSON::true or JSON::false inside TO_JSON
use boolean 0.32;

use Scalar::Util qw(blessed);

use base qw(BP::Loader::Mapper);

# Constructor parameters:
#	model: a BP::Model instance
#	config: a Config::IniFiles instance
sub new($$) {
	my $proto = shift;
	my $class = ref($proto) || $proto;
	
	my $model = shift;
	my $config = shift;
	
	my $self  = $class->SUPER::new($model,$config);
	bless($self,$class);
	
	# Finding the correspondence between collections and concepts
	# needed for type mapping
	my %colcon = ();
	my %concol = ();
	foreach my $conceptDomain (@{$model->conceptDomains}) {
		next  if($self->{release} && $conceptDomain->isAbstract());
		
		foreach my $concept (@{$conceptDomain->concepts()}) {
			my $collection;
			for(my $lookconcept = $concept , $collection = undef ; !defined($collection) && defined($lookconcept) ; ) {
				if($lookconcept->goesToCollection()) {
					# If it has a destination collection, save the collection
					$collection = $lookconcept->collection();
				} elsif(defined($lookconcept->idConcept())) {
					# If it has an identifying concept, does that concept (or one ancestor idconcept) have a destination collection
					$lookconcept = $lookconcept->idConcept();
				} else {
					$lookconcept = undef;
				}
			}
			
			if(defined($collection)) {
				# Perl hack to have something 'comparable'
				my $colid = $collection+0;
				$colcon{$colid} = []  unless(exists($colcon{$colid}));
				push(@{$colcon{$colid}}, $concept);
				
				# Perl hack to have something 'comparable'
				my $conid = $concept+0;
				$concol{$conid} = $collection;
			}
		}
	}
	
	$self->{_colConcept} = \%colcon;
	$self->{_conceptCol} = \%concol;
	
	return $self;
}

# TO_JSON methods are called by JSON library, which gives the structure to
# be translated into JSON. They are the patches to the different
# BP::Model subclasses, so JSON-ification works without having this
# specific code in the subclasses

sub BP::Model::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	# We need collections by path, not by id
	my %jsonColls = map { $_->path => $_ } values(%{$self->collections()});
	
	# The main features
	my %jsonModel=(
		'project'	=> $self->projectName(),
		'schemaVer'	=> $self->versionString(),
		'annotations'	=> $self->annotations(),
		'collections'	=> \%jsonColls,
		'domains'	=> $self->conceptDomainsHash(),
	);
	
	return \%jsonModel;
}

# ToColumnSet methods are called in order to get a column-set representation
# for the meta-something
sub BP::Model::ToColumnSet() {
	# TO BE FILLED
	my @modelColumns = (
		#BP::Model::Column->new('project',undef,undef,),
		#BP::Model::Column->new('schemaVer',undef,undef,),
		#BP::Model::Column->new('annotations',undef,undef,),
		#BP::Model::Column->new('collections',undef,undef,),
		#BP::Model::Column->new('domains',undef,undef,),
	);
	my $modelColumnSet = BP::Model::ColumnSet->new(undef,undef,@modelColumns);
	
	return $modelColumnSet;
}

# ToConcept methods are called in order to get a concept representation
# either the meta-model or the meta-controlled vocabularies

# This is to compute it only once
{
my $modelConcept = undef;	

sub BP::Model::ToConcept() {
	unless(defined($modelConcept)) {
		my $modelColumnSet = BP::Model::ToColumnSet();
		
		$modelConcept = BP::Model::Concept->new([
			undef, # name
			undef, # fullname
			undef, # basetype
			undef, # concept domain
			undef, # Description Set
			BP::Model::AnnotationSet->new(), # Annotation Set
			$modelColumnSet, # ColumnSet
			undef, # identifying concept
			undef, # related conceptNames
			undef, # parent concept
			'model' # id: The id of this QuasiConcept
		]);
	}
	
	return $modelConcept;
}

}

sub BP::Model::Collection::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	my %jsonCollection = (
		'name'	=> $self->name,
		'path'	=> $self->path,
		'indexes'	=> $self->indexes
	);
	
	return \%jsonCollection;
}

sub BP::Model::Index::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	return {
		'unique'	=> boolean::boolean($self->isUnique),
		'attrs'	=> [map { { 'name' => $_->[0], 'ord' => $_->[1] } } @{$self->indexAttributes}],
	};
}

sub BP::Model::DescriptionSet::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	if(scalar(@{$self})>0) {
		my @arrayRef = @{$self};
		
		foreach my $val (@arrayRef) {
			if(ref($val) eq 'ARRAY') {
				$val = join('',map { (blessed($_) && $_->can('toString'))?$_->toString():$_ } @{$val});
			} elsif(blessed($val) && $val->can('toString')) {
				$val = $val->toString();
			}
		}
		
		return \@arrayRef;
	} else {
		return undef;
	}
}

sub BP::Model::AnnotationSet::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	if(scalar(keys(%{$self->hash}))>0) {
		my %hashRes = %{$self->hash};
		
		foreach my $val (values(%hashRes)) {
			if(ref($val) eq 'ARRAY') {
				$val = join('',map { (blessed($_) && $_->can('toString'))?$_->toString():$_ } @{$val});
			} elsif(blessed($val) && $val->can('toString')) {
				$val = $val->toString();
			}
		}
		
		return \%hashRes;
	} else {
		return undef;
	}
}

sub BP::Model::CV::Term::_jsonId() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	my $cvPrefix = defined($self->parentCV)?$self->parentCV->id:'_null_';
	
	return join(':','t',$cvPrefix,$self->key);
}

sub BP::Model::CV::Term::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	my %hashRes = (
		'_id'	=> $self->_jsonId,
		'term'	=> $self->key,
		'name'	=> $self->name,
	);
	
	my $uriKey = $self->uriKey;
	$hashRes{'term_uri'} = $uriKey  if(defined($uriKey));
	
	my $namespace = $self->namespace;
	$hashRes{'ns'} = $namespace->ns_uri  if(defined($namespace));
	$hashRes{'alt-id'} = [@{$self->keys},@{$self->uriKeys}];
	if($self->isAlias) {
		$hashRes{'alias'} = boolean::true;
		$hashRes{'union-of'} = $self->parents;
	} elsif(defined($self->parents)) {
		$hashRes{'parents'} = $self->parents;
		$hashRes{'ancestors'} = $self->ancestors;
	}
	
	return \%hashRes;
}

sub BP::Model::CV::Abstract::_jsonId() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	return 'cv:'.$self->id;
}

sub BP::Model::CV::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	my %hashRes = (
		'_id'	=> $self->_jsonId,
		'name'	=> $self->name,<commit_msg>Renaming alt-id and union-of to something more Groovy friendly<commit_after>#!/usr/bin/perl -W

use strict;
use Carp;

use BP::Model;

package BP::Loader::Mapper::NoSQL;

# Needed for metadata model serialization
use JSON;

# Better using something agnostic than JSON::true or JSON::false inside TO_JSON
use boolean 0.32;

use Scalar::Util qw(blessed);

use base qw(BP::Loader::Mapper);

# Constructor parameters:
#	model: a BP::Model instance
#	config: a Config::IniFiles instance
sub new($$) {
	my $proto = shift;
	my $class = ref($proto) || $proto;
	
	my $model = shift;
	my $config = shift;
	
	my $self  = $class->SUPER::new($model,$config);
	bless($self,$class);
	
	# Finding the correspondence between collections and concepts
	# needed for type mapping
	my %colcon = ();
	my %concol = ();
	foreach my $conceptDomain (@{$model->conceptDomains}) {
		next  if($self->{release} && $conceptDomain->isAbstract());
		
		foreach my $concept (@{$conceptDomain->concepts()}) {
			my $collection;
			for(my $lookconcept = $concept , $collection = undef ; !defined($collection) && defined($lookconcept) ; ) {
				if($lookconcept->goesToCollection()) {
					# If it has a destination collection, save the collection
					$collection = $lookconcept->collection();
				} elsif(defined($lookconcept->idConcept())) {
					# If it has an identifying concept, does that concept (or one ancestor idconcept) have a destination collection
					$lookconcept = $lookconcept->idConcept();
				} else {
					$lookconcept = undef;
				}
			}
			
			if(defined($collection)) {
				# Perl hack to have something 'comparable'
				my $colid = $collection+0;
				$colcon{$colid} = []  unless(exists($colcon{$colid}));
				push(@{$colcon{$colid}}, $concept);
				
				# Perl hack to have something 'comparable'
				my $conid = $concept+0;
				$concol{$conid} = $collection;
			}
		}
	}
	
	$self->{_colConcept} = \%colcon;
	$self->{_conceptCol} = \%concol;
	
	return $self;
}

# TO_JSON methods are called by JSON library, which gives the structure to
# be translated into JSON. They are the patches to the different
# BP::Model subclasses, so JSON-ification works without having this
# specific code in the subclasses

sub BP::Model::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	# We need collections by path, not by id
	my %jsonColls = map { $_->path => $_ } values(%{$self->collections()});
	
	# The main features
	my %jsonModel=(
		'project'	=> $self->projectName(),
		'schemaVer'	=> $self->versionString(),
		'annotations'	=> $self->annotations(),
		'collections'	=> \%jsonColls,
		'domains'	=> $self->conceptDomainsHash(),
	);
	
	return \%jsonModel;
}

# ToColumnSet methods are called in order to get a column-set representation
# for the meta-something
sub BP::Model::ToColumnSet() {
	# TO BE FILLED
	my @modelColumns = (
		#BP::Model::Column->new('project',undef,undef,),
		#BP::Model::Column->new('schemaVer',undef,undef,),
		#BP::Model::Column->new('annotations',undef,undef,),
		#BP::Model::Column->new('collections',undef,undef,),
		#BP::Model::Column->new('domains',undef,undef,),
	);
	my $modelColumnSet = BP::Model::ColumnSet->new(undef,undef,@modelColumns);
	
	return $modelColumnSet;
}

# ToConcept methods are called in order to get a concept representation
# either the meta-model or the meta-controlled vocabularies

# This is to compute it only once
{
my $modelConcept = undef;	

sub BP::Model::ToConcept() {
	unless(defined($modelConcept)) {
		my $modelColumnSet = BP::Model::ToColumnSet();
		
		$modelConcept = BP::Model::Concept->new([
			undef, # name
			undef, # fullname
			undef, # basetype
			undef, # concept domain
			undef, # Description Set
			BP::Model::AnnotationSet->new(), # Annotation Set
			$modelColumnSet, # ColumnSet
			undef, # identifying concept
			undef, # related conceptNames
			undef, # parent concept
			'model' # id: The id of this QuasiConcept
		]);
	}
	
	return $modelConcept;
}

}

sub BP::Model::Collection::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	my %jsonCollection = (
		'name'	=> $self->name,
		'path'	=> $self->path,
		'indexes'	=> $self->indexes
	);
	
	return \%jsonCollection;
}

sub BP::Model::Index::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	return {
		'unique'	=> boolean::boolean($self->isUnique),
		'attrs'	=> [map { { 'name' => $_->[0], 'ord' => $_->[1] } } @{$self->indexAttributes}],
	};
}

sub BP::Model::DescriptionSet::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	if(scalar(@{$self})>0) {
		my @arrayRef = @{$self};
		
		foreach my $val (@arrayRef) {
			if(ref($val) eq 'ARRAY') {
				$val = join('',map { (blessed($_) && $_->can('toString'))?$_->toString():$_ } @{$val});
			} elsif(blessed($val) && $val->can('toString')) {
				$val = $val->toString();
			}
		}
		
		return \@arrayRef;
	} else {
		return undef;
	}
}

sub BP::Model::AnnotationSet::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	if(scalar(keys(%{$self->hash}))>0) {
		my %hashRes = %{$self->hash};
		
		foreach my $val (values(%hashRes)) {
			if(ref($val) eq 'ARRAY') {
				$val = join('',map { (blessed($_) && $_->can('toString'))?$_->toString():$_ } @{$val});
			} elsif(blessed($val) && $val->can('toString')) {
				$val = $val->toString();
			}
		}
		
		return \%hashRes;
	} else {
		return undef;
	}
}

sub BP::Model::CV::Term::_jsonId() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	my $cvPrefix = defined($self->parentCV)?$self->parentCV->id:'_null_';
	
	return join(':','t',$cvPrefix,$self->key);
}

sub BP::Model::CV::Term::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	my %hashRes = (
		'_id'	=> $self->_jsonId,
		'term'	=> $self->key,
		'name'	=> $self->name,
	);
	
	my $uriKey = $self->uriKey;
	$hashRes{'term_uri'} = $uriKey  if(defined($uriKey));
	
	my $namespace = $self->namespace;
	$hashRes{'ns'} = $namespace->ns_uri  if(defined($namespace));
	$hashRes{'alt_id'} = [@{$self->keys},@{$self->uriKeys}];
	if($self->isAlias) {
		$hashRes{'alias'} = boolean::true;
		$hashRes{'union_of'} = $self->parents;
	} elsif(defined($self->parents)) {
		$hashRes{'parents'} = $self->parents;
		$hashRes{'ancestors'} = $self->ancestors;
	}
	
	return \%hashRes;
}

sub BP::Model::CV::Abstract::_jsonId() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	return 'cv:'.$self->id;
}

sub BP::Model::CV::TO_JSON() {
	my $self = shift;
	
	Carp::croak((caller(0))[3].' is an instance method!')  if(BP::Model::DEBUG && !ref($self));
	
	my %hashRes = (
		'_id'	=> $self->_jsonId,
		'name'	=> $self->name,
{'fraction_non_alphanumeric': 0.20390763765541742, 'fraction_numerical': 0.0038365896980461812, 'mean_word_length': 4.403454894433781, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 167, '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': '3718750', 'n_tokens_mistral': 5553, 'n_tokens_neox': 4970, 'n_words': 1125}