Restructured KQ importing design

Change-Id: I74f0247462a8f64f937437b11a7800631f770657
diff --git a/lib/Krawfish/Koral/Query.pm b/lib/Krawfish/Koral/Query.pm
index 57bf876..a15ee67 100644
--- a/lib/Krawfish/Koral/Query.pm
+++ b/lib/Krawfish/Koral/Query.pm
@@ -61,7 +61,7 @@
 # Constructor
 sub new {
   my $class = shift;
-  my $self = bless {
+  bless {
     anywhere => 0,
     optional => 0,
     null => 0,
@@ -70,12 +70,6 @@
     extended_left => 0,
    extended_right => 0
   }, $class;
-
-  if ($_[0]) {
-    return $self->from_koral(shift);
-  };
-
-  $self;
 };
 
 
@@ -341,38 +335,6 @@
 # Query Application methods #
 #############################
 
-# Deserialization of KoralQuery
-# TODO: export this method from Importer
-sub from_koral {
-  my ($class, $kq) = @_;
-  my $importer = Krawfish::Koral::Query::Importer->new;
-
-  my $type = $kq->{'@type'};
-  if ($type eq 'koral:group') {
-    my $op = $kq->{operation};
-    if ($op eq 'operation:sequence') {
-      return $importer->seq($kq);
-    }
-
-    elsif ($op eq 'operation:class') {
-      return $importer->class($kq);
-    }
-    else {
-      warn 'Operation ' . $op . ' no supported';
-    };
-  }
-
-  elsif ($type eq 'koral:token') {
-    return $importer->token($kq);
-  }
-  else {
-    warn $type . ' unknown';
-  };
-
-  return;
-};
-
-
 # Serialize
 sub to_koral_query {
   my $self = shift;
@@ -408,20 +370,8 @@
 
 
 # Create KoralQuery builder
-#sub importer {
-#  return Krawfish::Koral::Query::Importer->new;
-#};
-
-
-# Serialization helper
-sub boundary {
-  my $self = shift;
-  my %hash = (
-    '@type' => 'koral:boundary'
-  );
-  $hash{min} = $self->{min} if defined $self->{min};
-  $hash{max} = $self->{max} if defined $self->{max};
-  return \%hash;
+sub importer {
+  return Krawfish::Koral::Query::Importer->new;
 };
 
 
diff --git a/lib/Krawfish/Koral/Query/Boundary.pm b/lib/Krawfish/Koral/Query/Boundary.pm
new file mode 100644
index 0000000..2f12b2a
--- /dev/null
+++ b/lib/Krawfish/Koral/Query/Boundary.pm
@@ -0,0 +1,36 @@
+package Krawfish::Koral::Query::Boundary;
+use Role::Tiny;
+use strict;
+use warnings;
+
+# Serialization helper
+sub boundary {
+  my $self = shift;
+  my %hash = (
+    '@type' => 'koral:boundary'
+  );
+  $hash{min} = $self->{min} if defined $self->{min};
+  $hash{max} = $self->{max} if defined $self->{max};
+  return \%hash;
+};
+
+
+sub min {
+  if (defined $_[1]) {
+    $_[0]->{min} = $_[1];
+    return $_[0];
+  };
+  $_[0]->{min};
+};
+
+
+sub max {
+  if (defined $_[1]) {
+    $_[0]->{max} = $_[1];
+    return $_[0];
+  };
+  $_[0]->{max};
+};
+
+
+1;
diff --git a/lib/Krawfish/Koral/Query/Class.pm b/lib/Krawfish/Koral/Query/Class.pm
index 3aae2dd..1a86a24 100644
--- a/lib/Krawfish/Koral/Query/Class.pm
+++ b/lib/Krawfish/Koral/Query/Class.pm
@@ -204,7 +204,7 @@
   my $nr = $kq->{'classOut'} or warn 'No class defined';
 
   # Import operand
-  my $op = $importer->all($kq->{operands}->[0]);
+  my $op = $importer->from_koral($kq->{operands}->[0]);
 
   return $class->new($op, $nr);
 };
diff --git a/lib/Krawfish/Koral/Query/Constraint.pm b/lib/Krawfish/Koral/Query/Constraint.pm
index ce3c04c..9c272a0 100644
--- a/lib/Krawfish/Koral/Query/Constraint.pm
+++ b/lib/Krawfish/Koral/Query/Constraint.pm
@@ -347,6 +347,10 @@
   ...
 };
 
+sub from_koral {
+  ...
+};
+
 
 # Stringification
 sub to_string {
diff --git a/lib/Krawfish/Koral/Query/Exclusion.pm b/lib/Krawfish/Koral/Query/Exclusion.pm
index d4ae164..5da12b8 100644
--- a/lib/Krawfish/Koral/Query/Exclusion.pm
+++ b/lib/Krawfish/Koral/Query/Exclusion.pm
@@ -44,6 +44,10 @@
   return $koral;
 };
 
+sub from_koral {
+  ...
+};
+
 
 #########################################
 # Query Planning methods and attributes #
diff --git a/lib/Krawfish/Koral/Query/Extension.pm b/lib/Krawfish/Koral/Query/Extension.pm
index 77e5630..ec45cff 100644
--- a/lib/Krawfish/Koral/Query/Extension.pm
+++ b/lib/Krawfish/Koral/Query/Extension.pm
@@ -85,6 +85,10 @@
   ...
 };
 
+sub from_koral {
+  ...
+};
+
 sub uses_classes {
   ...
 };
diff --git a/lib/Krawfish/Koral/Query/Filter.pm b/lib/Krawfish/Koral/Query/Filter.pm
index e9927b2..175f83a 100644
--- a/lib/Krawfish/Koral/Query/Filter.pm
+++ b/lib/Krawfish/Koral/Query/Filter.pm
@@ -173,6 +173,11 @@
 };
 
 
+sub from_koral {
+  ...
+};
+
+
 # Return the minimum numbers of tokens of the span
 sub min_span {
   $_[0]->operand->min_span;
diff --git a/lib/Krawfish/Koral/Query/Importer.pm b/lib/Krawfish/Koral/Query/Importer.pm
index e1eb6ce..8c5cb38 100644
--- a/lib/Krawfish/Koral/Query/Importer.pm
+++ b/lib/Krawfish/Koral/Query/Importer.pm
@@ -6,36 +6,94 @@
 use Krawfish::Koral::Query::Token;
 use Krawfish::Koral::Query::Term;
 use Krawfish::Koral::Query::Class;
+use Krawfish::Koral::Query::Repetition;
 
 sub new {
   my $var;
   bless \$var, shift;
 };
 
-sub all {
-  shift;
-  return Krawfish::Koral::Query->from_koral(shift);
+# Deserialization of KoralQuery
+# TODO: export this method from Importer
+
+
+sub from_koral {
+  my ($self, $kq) = @_;
+
+  my $type = $kq->{'@type'};
+  if ($type eq 'koral:group') {
+    my $op = $kq->{operation};
+    if ($op eq 'operation:sequence') {
+      return $self->seq($kq);
+    }
+
+    elsif ($op eq 'operation:class') {
+      return $self->class($kq);
+    }
+
+    elsif ($op eq 'operation:length') {
+      return $self->length($kq);
+    }
+
+    elsif ($op eq 'operation:repetition') {
+      return $self->repeat($kq);
+    }
+
+    else {
+      warn 'Operation ' . $op . ' no supported';
+    };
+  }
+
+  elsif ($type eq 'koral:token') {
+    return $self->token($kq);
+  }
+  else {
+    warn $type . ' unknown';
+  };
+
+  return;
 };
 
+
+# Import sequence
 sub seq {
   shift;
   return Krawfish::Koral::Query::Sequence->from_koral(shift);
 };
 
+
+# Import token
 sub token {
   shift;
   return Krawfish::Koral::Query::Token->from_koral(shift);
-}
+};
 
+
+# Import term
 sub term {
   shift;
   return Krawfish::Koral::Query::Term->from_koral(shift);
 };
 
 
+# Import class
 sub class {
   shift;
   return Krawfish::Koral::Query::Class->from_koral(shift);
-}
+};
+
+
+# Import length
+sub length {
+  shift;
+  return Krawfish::Koral::Query::Length->from_koral(shift);
+};
+
+
+# Import repetition
+sub repeat {
+  shift;
+  return Krawfish::Koral::Query::Repetition->from_koral(shift);
+};
 
 1;
diff --git a/lib/Krawfish/Koral/Query/InCorpus.pm b/lib/Krawfish/Koral/Query/InCorpus.pm
index 0bc6c0b..79e2bea 100644
--- a/lib/Krawfish/Koral/Query/InCorpus.pm
+++ b/lib/Krawfish/Koral/Query/InCorpus.pm
@@ -97,6 +97,10 @@
 };
 
 
+sub from_koral {
+  ...
+};
+
 # TODO: Identical to class/unique
 
 sub is_anywhere {
diff --git a/lib/Krawfish/Koral/Query/Length.pm b/lib/Krawfish/Koral/Query/Length.pm
index 29a3ce0..dc4bc47 100644
--- a/lib/Krawfish/Koral/Query/Length.pm
+++ b/lib/Krawfish/Koral/Query/Length.pm
@@ -10,6 +10,7 @@
 memoize('max_span');
 
 with 'Krawfish::Koral::Query';
+with 'Krawfish::Koral::Query::Boundary';
 
 # TODO:
 #   Normalize chained length queries
@@ -62,26 +63,6 @@
 };
 
 
-# Minimum length of either tokens or (default) subtokens
-sub min {
-  if (defined $_[1]) {
-    $_[0]->{min} = $_[1];
-    return $_[0];
-  };
-  $_[0]->{min};
-};
-
-
-# Minimum length of either tokens or (default) subtokens
-sub max {
-  if (defined $_[1]) {
-    $_[0]->{max} = $_[1];
-    return $_[0];
-  };
-  $_[0]->{max};
-};
-
-
 # Minimum span of the query in tokens
 sub min_span {
   my $self = shift;
@@ -139,11 +120,6 @@
 sub type { 'length' };
 
 
-sub to_koral_fragment {
-  ...
-};
-
-
 # Normalize query
 sub normalize {
   my $self = shift;
@@ -235,8 +211,38 @@
 };
 
 
+# Serialize to koral fragment
+sub to_koral_fragment {
+  my $self = shift;
+  return {
+    '@type' => 'koral:group',
+    operation => 'operation:length',
+    boundary => $self->boundary,
+    # token    => $self->token_base,
+    operands => [
+      $self->operand->to_koral_fragment
+    ]
+  };
+};
+
+
+# Deserialize from koral fragment
 sub from_koral {
-  ...
+  my ($class, $kq) = @_;
+
+  my $importer = $class->importer;
+
+  my @param = ();
+  my $boundary = $kq->{boundary};
+  if ($boundary) {
+    push @param, $boundary->{min} if $boundary->{min};
+    push @param, $boundary->{max} if $boundary->{max};
+  };
+  push @param, $kq->{token} if $kq->{token};
+
+  return $class->new(
+    $kq->{operands}->[0], @param
+  );
 };
 
 
diff --git a/lib/Krawfish/Koral/Query/Match.pm b/lib/Krawfish/Koral/Query/Match.pm
index 5cddb43..7491b50 100644
--- a/lib/Krawfish/Koral/Query/Match.pm
+++ b/lib/Krawfish/Koral/Query/Match.pm
@@ -6,6 +6,10 @@
 
 with 'Krawfish::Koral::Query';
 
+
+# TODO:
+#   Suport corpus classes!
+
 # This Query does not search segment data, but
 # returns the data it is passed to.
 # It is used to fetch enriched match data.
@@ -37,6 +41,10 @@
   };
 };
 
+sub from_koral {
+  ...
+};
+
 sub type { 'match' };
 
 
diff --git a/lib/Krawfish/Koral/Query/Nowhere.pm b/lib/Krawfish/Koral/Query/Nowhere.pm
index b2c75a5..56ff24e 100644
--- a/lib/Krawfish/Koral/Query/Nowhere.pm
+++ b/lib/Krawfish/Koral/Query/Nowhere.pm
@@ -65,4 +65,8 @@
   ...
 };
 
+sub from_koral {
+  ...
+};
+
 1;
diff --git a/lib/Krawfish/Koral/Query/Or.pm b/lib/Krawfish/Koral/Query/Or.pm
index 14d20b9..a065353 100644
--- a/lib/Krawfish/Koral/Query/Or.pm
+++ b/lib/Krawfish/Koral/Query/Or.pm
@@ -150,5 +150,8 @@
   ...
 };
 
+sub from_koral {
+  ...
+};
 
 1;
diff --git a/lib/Krawfish/Koral/Query/Repetition.pm b/lib/Krawfish/Koral/Query/Repetition.pm
index 3c439a6..2c09a36 100644
--- a/lib/Krawfish/Koral/Query/Repetition.pm
+++ b/lib/Krawfish/Koral/Query/Repetition.pm
@@ -5,6 +5,7 @@
 use warnings;
 
 with 'Krawfish::Koral::Query';
+with 'Krawfish::Koral::Query::Boundary';
 
 our $MAX = 100;
 
@@ -37,24 +38,6 @@
 };
 
 
-sub min {
-  if (defined $_[1]) {
-    $_[0]->{min} = $_[1];
-    return $_[0];
-  };
-  $_[0]->{min};
-};
-
-
-sub max {
-  if (defined $_[1]) {
-    $_[0]->{max} = $_[1];
-    return $_[0];
-  };
-  $_[0]->{max};
-};
-
-
 # Get the minimum span
 sub min_span {
   my $self = shift;
@@ -99,6 +82,28 @@
   };
 };
 
+sub from_koral {
+  my ($class, $kq) = @_;
+  my $boundary = $kq->{boundary};
+
+  my ($min, $max);
+  if ($boundary->{min}) {
+    $min = $boundary->{min};
+  };
+  if ($boundary->{max}) {
+    $max = $boundary->{max};
+  };
+
+  my $importer = $class->importer;
+
+  # Get operand
+  my $op = $importer->from_koral(
+    $kq->{operands}->[0]
+  );
+
+  $class->new($op, $min, $max);
+};
+
 
 #########################################
 # Query Planning methods and attributes #
diff --git a/lib/Krawfish/Koral/Query/Sequence.pm b/lib/Krawfish/Koral/Query/Sequence.pm
index 92934d7..da53e68 100644
--- a/lib/Krawfish/Koral/Query/Sequence.pm
+++ b/lib/Krawfish/Koral/Query/Sequence.pm
@@ -160,6 +160,7 @@
 };
 
 
+# Get from koralquery
 sub from_koral {
   my $class = shift;
   my $kq = shift;
@@ -167,7 +168,7 @@
   my $importer = $class->importer;
 
   return $class->new(
-    map { $importer->all($_) } @{$kq->{operands}}
+    map { $importer->from_koral($_) } @{$kq->{operands}}
   );
 };
 
diff --git a/lib/Krawfish/Koral/Query/TermGroup.pm b/lib/Krawfish/Koral/Query/TermGroup.pm
index 7a65643..6b1fb7d 100644
--- a/lib/Krawfish/Koral/Query/TermGroup.pm
+++ b/lib/Krawfish/Koral/Query/TermGroup.pm
@@ -228,4 +228,8 @@
 };
 
 
+sub from_koral {
+  ...
+};
+
 1;
diff --git a/lib/Krawfish/Koral/Query/Unique.pm b/lib/Krawfish/Koral/Query/Unique.pm
index fcb52da..e7d61ff 100644
--- a/lib/Krawfish/Koral/Query/Unique.pm
+++ b/lib/Krawfish/Koral/Query/Unique.pm
@@ -20,6 +20,10 @@
   ...
 };
 
+sub from_koral {
+  ...
+};
+
 sub type { 'unique' };