mwb613 has asked for the wisdom of the Perl Monks concerning the following question:

Hello, thanks for looking!

I have been looking around CPAN for a module that might save me from starting from scratch. So far I haven't found what I'm looking for hopefully due to a failure to use the proper terminology or focusing on too narrow of a use case.

I have some data in Redis that I'd like to be able to run SQL-style queries on. I'm not looking to invent a SQL wrapper for Redis but I do think it would be useful to have an ability to test values against ad hoc conditionals.

I'd like to be able to pass a subroutine a conditional test and a value to test against it. For example the conditional could be a hash ref like this (say we're testing a zip code):

my $conditional_test = { 'OR' => { 'condition1' => { 'value' => '10022' } 'condition2' => { 'value' => '96813' } 'condition3' => { 'value' => '55401' } } } if(my_condition_test_sub($conditional_test,$redis_handle->get('key'))) +{ #do something }

Possible conditions could be (and, or, not...)

Ideally we could nest these conditions as well which is why I'm looking for a parser that's already built. I did find a grammar parser that looked like it worked for natural language as well as some conditional parsers specific to specialized data (XML, lists) but nothing generalized.

Has anyone come across this particular problem (not Redis queries but checking data against ad hoc value tests) before and found a good solution? It seems like a use case that might warrant a module.

Thanks again for looking.

Replies are listed 'Best First'.
Re: Module for Conditional Parsing
by Anonymous Monk on Mar 30, 2015 at 10:36 UTC
    I'd like to be able to pass a subroutine a conditional test and a value to test against it. For example the conditional could be a hash ...

    Just a thought in case you do go ahead and implement this yourself: Implementing a query language means grammar design + parser + interpreter + tests for everything... why not write the conditionals in Perl?

    my $conditional_test = sub { my $value = shift; return $value==10022 || $value==96813 || $value==55401; }; if( $conditional_test->($redis_handle->get('key')) ) { # do something }

    Plenty of examples of this: sort, File::Find, ... MJD's Higher-Order Perl is an excellent read in this respect.

Re: Module for Conditional Parsing
by choroba (Cardinal) on Mar 30, 2015 at 12:26 UTC
    Please, give us a bigger picture. If the "ad hoc conditionals" will only come from the programmer (i.e. the code), there's no need for a structure, just use an anonymous subroutine:
    my $allowed = sub { grep $_[0] == $_, 10022, 96813, 55401 }; if ($allowed->($redis_handle->get('key')) { # do something }

    But, if users will be creating those conditionals, you need a language + parser (or a GUI to build the conditionals graphically).

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Module for Conditional Parsing
by hdb (Monsignor) on Mar 30, 2015 at 10:45 UTC

    I think you need to elaborate a bit more what you want to achieve. If you want to test a single value against a number of possible allowed values and a number of disallowed values, then writing a subroutine for exactly that purpose would be simpler (providing the lists of allowed and disallowed values). When testing against values, AND is not useful as a variable can only have one value.

    Or if you want something more complex, please provide a more elaborate example. Like testing the values of several keys, more complex tests etc.

      Thanks hdb,

      I provided a little more detail in response to "choroba" below. AND was included for exactly the use case you mentioned, testing multiple keys (in the response below I give an example of a single key being used as a composite so it can be tested against multiple conditionals). I understand the deconstruction of the composite key in itself will require a bit of logic but I have already written a fair amount of code that deals building and breaking apart the composite keys.

        It seems as if your response to choroba got lost...

Re: Module for Conditional Parsing
by marinersk (Priest) on Mar 30, 2015 at 19:19 UTC

    For this purpose, I've always just stored the ad-hoc value relationships as key/value pairs in a hash, and then returned the value for the key:

    #!/usr/bin/perl use strict; my $TRUE = 1; my $FALSE = 0; my $KEY_ADHQRY = 'ADHQRY'; # Hash key for the ad hoc Quer +y my $KEY_ADHVAL = 'ADHVAL'; # Hash key for the ad hoc Valu +e my %Adhinf = (); # Ad hoc information # Get the ad hoc query/response values and populate the hash { print "Enter ad hoc values list in the following format: query->v +alue|query->value|query->value\n"; my $reqahv = <STDIN>; chomp $reqahv; my @adhelt = split /\|/, $reqahv; foreach my $adhelt (@adhelt) { my $wrkelt = $adhelt; $wrkelt =~ s/^\s+//; $wrkelt =~ s/\s+$//; my ($adhqry, $adhval) = split /\s*\-\>\s*/, $wrkelt, 2; my $adhkey = uc $adhqry; $Adhinf{$adhkey}{$KEY_ADHQRY} = $adhqry; $Adhinf{$adhkey}{$KEY_ADHVAL} = $adhval; } } # Test the query/response behavior { my $prcflg = $TRUE; while ($prcflg) { print " Enter query: "; my $reqqry = <STDIN>; chomp $reqqry; if ($reqqry =~ /^\s*$/) { $prcflg = $FALSE; last; } else { my $reqrsp = getAdHocResponse($reqqry); print " Response: $reqrsp\n"; print "\n"; } } } exit; sub getAdHocResponse { my ($reqqry, @arglst) = @_; if (!defined $reqqry) { $reqqry = ''; } my $retval = '{No Response}'; my $reqkey = uc $reqqry; if (defined $Adhinf{$reqkey}) { $retval = $Adhinf{$reqkey}{$KEY_ADHVAL}; } return $retval; }

    And the test results: