Config-XrmDatabase

 view release on metacpan or  search on metacpan

lib/Config/XrmDatabase.pm  view on Meta::CPAN

package Config::XrmDatabase;

# ABSTRACT: Pure Perl X Resource Manager Database

use v5.26;
use warnings;

our $VERSION = '0.08';

use Feature::Compat::Try;

use Config::XrmDatabase::Failure ':all';
use Config::XrmDatabase::Util ':all';
use Config::XrmDatabase::Types -all;
use Types::Standard qw( Object Str Optional HashRef );
use Type::Params    qw( compile_named );
use Ref::Util;

use Moo;

use namespace::clean;

use MooX::StrictConstructor;

use experimental qw( signatures postderef declared_refs refaliasing );
use if $] >= 5.034, 'experimental', 'try';

has _db => (
    is       => 'rwp',
    init_arg => undef,
    default  => sub { {} },
);

has _query_return_value => (
    is       => 'ro',
    isa      => QueryReturnValue,
    init_arg => 'query_return_value',
    coerce   => 1,
    default  => 'value',
);

has _query_on_failure => (
    is       => 'ro',
    isa      => OnQueryFailure,
    init_arg => 'query_on_failure',
    coerce   => 1,
    default  => 'undef',
);

# fake attribute so we can use MooX::StrictConstructor
has _insert => (
    is        => 'ro',
    isa       => HashRef,
    init_arg  => 'insert',
    predicate => 1,
    clearer   => 1,
);




















lib/Config/XrmDatabase.pm  view on Meta::CPAN

























no namespace::clean;
use constant {
    QUERY_RETURN_VALUE     => 'value',
    QUERY_RETURN_REFERENCE => 'reference',
    QUERY_RETURN_ALL       => 'all',
    QUERY_ON_FAILURE_THROW => 'throw',
    QUERY_ON_FAILURE_UNDEF => 'undef',
};
use namespace::clean;

sub query ( $self, $class, $name, %iopt ) {

    state $check = compile_named(
        { head => [ Str, Str ] },
        return_value => Optional [QueryReturnValue],
        on_failure   => Optional [OnQueryFailure],
    );

    ( $class, $name, my \%opt ) = $check->( $class, $name, %iopt );

    $opt{on_failure}   //= $self->_query_on_failure;
    $opt{return_value} //= $self->_query_return_value;

    ( $class, $name ) = map { parse_fq_resource_name( $_ ) } $class, $name;

    components_failure->throw( 'class and name must have the same number of components' )
      if @$class != @$name;

    my $return_all = $opt{return_value} eq QUERY_RETURN_ALL;

    my $match  = [];
    my @qargs  = ( $class, $name, $return_all, $match );
    my $retval = $self->_query( $self->_db, 0, \@qargs );

    if ( !defined $retval ) {
        return $opt{on_failure}->( $name, $class )
          if Ref::Util::is_coderef( $opt{on_failure} );

        query_failure->throw(
            "unable to match name: '@{[ name_arr_to_str($name) ]} '; class : '@{[ name_arr_to_str($class) ]}'" )
          if $opt{on_failure} eq QUERY_ON_FAILURE_THROW;

        return undef;
    }

    return $opt{return_value} eq QUERY_RETURN_VALUE ? $$retval : $retval;
}

sub _query ( $self, $db, $idx, $args ) {

    my ( \$class, \$name, \$return_all, \$match ) = map { \$_ } $args->@*;

    my $_query = __SUB__;

    # things are simple if we're looking for the last component; it must
    # match exactly.  this might be able to be inlined in the exact match
    # checks below to avoid a recursive call, but this is clearer.
    if ( $idx + 1 == @$name ) {
        for my $component ( $name->[$idx], $class->[$idx] ) {
            if (   exists $db->{$component}
                && exists $db->{$component}{ +VALUE } )
            {
                push $match->@*, $component;
                my $entry = $db->{$component};
                ++$entry->{ +MATCH_COUNT };
                my $value = $entry->{ +VALUE };
                return $return_all
                  ? {
                    value       => $value,
                    match_count => $entry->{ +MATCH_COUNT },
                    key         => $match,
                  }
                  : \$value;
            }
        }
        return undef;
    }

    # otherwise need to possibly check lower level components

    # exactly named components
    for my $component ( $name->[$idx], $class->[$idx] ) {
        if ( my $subdb = $db->{$component} ) {
            push $match->@*, $component;
            my $res = $self->$_query( $subdb, $idx + 1, $args );
            return $res if defined $res;
            pop $match->@*;
        }
    }

    # single wildcard
    if ( my $subdb = $db->{ +SINGLE } ) {
        push $match->@*, SINGLE;
        my $res = $self->$_query( $subdb, $idx + 1, $args );
        return $res if defined $res;
        pop $match->@*;
    }



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