add scan_dq_nodes helper
[dbsrgits/Data-Query.git] / lib / Data / Query / ExprHelpers.pm
index 6020be6..399a8e2 100644 (file)
@@ -5,7 +5,12 @@ use Data::Query::Constants;
 
 use base qw(Exporter);
 
-our @EXPORT = qw(perl_scalar_value perl_operator Literal Identifier compose);
+our @EXPORT = qw(
+  perl_scalar_value perl_operator Literal Identifier compose intersperse
+  scan_dq_nodes
+);
+
+sub intersperse { my $i = shift; my @i = map +($_, $i), @_; pop @i; @i }
 
 sub perl_scalar_value {
   +{
@@ -31,7 +36,7 @@ my %map = (
   Operator => [ qw(operator args) ],
   Select => [ qw(select from) ],
   Where => [ qw(where from) ],
-  Order => [ qw(by reverse from) ],
+  Order => [ qw(by reverse nulls from) ],
   Group => [ qw(by from) ],
   Delete => [ qw(where target) ],
   Update => [ qw(set where target) ],
@@ -71,13 +76,21 @@ foreach my $name (values %Data::Query::Constants::CONST) {
     $dq->{type} and $dq->{type} eq $name
   };
   push @EXPORT, $sub;
-  if ($map{$name}) {
-    my @map = @{$map{$name}};
+  if (my @map = @{$map{$name}||[]}) {
     *$name = sub {
       my $dq = { type => $name };
-      foreach (0..$#_) {
+      foreach (0..$#map) {
         $dq->{$map[$_]} = $_[$_] if defined $_[$_];
       }
+
+      if (my $optional = $_[$#map+1]) {
+        unless(ref $optional eq 'HASH') {
+          require Carp;
+          Carp::croak("Not a hashreference");
+        }
+        @{$dq}{keys %$optional} = values %$optional;
+      }
+
       return $dq;
     };
     push @EXPORT, $name;
@@ -115,5 +128,17 @@ sub compose (&@) {
   $a;
 }
 
+sub scan_dq_nodes {
+  my ($cb_map, @queue) = @_;
+  while (my $node = shift @queue) {
+    if ($node->{type} and my $cb = $cb_map->{$node->{type}}) {
+      $cb->($node);
+    }
+    push @queue,
+      grep ref($_) eq 'HASH',
+        map +(ref($_) eq 'ARRAY' ? @$_ : $_),
+          @{$node}{grep !/\./, keys %$node};
+  }
+}
 
 1;