fix foo/bar/AND/
authorIan Beckwith <ianb@erislabs.net>
Sun, 10 Oct 2010 19:57:23 +0000 (20:57 +0100)
committerIan Beckwith <ianb@erislabs.net>
Sun, 10 Oct 2010 19:57:23 +0000 (20:57 +0100)
lib/ID3FS/DB.pm
lib/ID3FS/Path.pm
lib/ID3FS/Path/Node.pm

index 4ff9bfd..86291cf 100644 (file)
@@ -184,11 +184,14 @@ sub tags
     my @constraints=@{$path->{elements}};
     if(!@constraints) # /
     {
-       # FIXME: add ALL?
        my $sql="SELECT DISTINCT name FROM tags WHERE parents_id='';";
        my $tags=$self->cmd_rows($sql);
        return(map { $_->[0]; } @$tags);
     }
+    my $hasvals=$path->tag_has_values();
+    my $parent=$path->trailing_tag_parent();
+    print "THASVALS: $hasvals\n";
+    print "TPARENT: ", (defined($parent)? $parent : "NO"), "\n";
     my @ids=();
     my $sql=("SELECT tags.name FROM (\n" .
             $self->tags_subselect($path) .
@@ -201,13 +204,13 @@ sub tags
     print "tags(): USED: ", join(", ", @used), "\n";
     print "tags(): USED_WITH_VALS: ", join(", ", map { "[".$_->[0]. ", ".$_->[1]."]";} @used_with_vals), "\n";
     my @orclauses=();
-    if($path->tag_has_values())
+    my @andclauses=();
+    my $id=$path->trailing_tag_id();
+    if($hasvals)
     {
        print "HAS_VALUES\n";
-       my $parent=$path->trailing_tag_id();
-       print "parent: $parent\n";
-       my @values=map { "'".$_->[1]."'"; } grep { $_->[0] == $parent; } @used_with_vals;
-       my $clause="(tags.parents_id='$parent'";
+       my @values=map { "'".$_->[1]."'"; } grep { $_->[0] == $id; } @used_with_vals;
+       my $clause="(tags.parents_id='$id'";
        if(@values)
        {
            $clause .= " AND tags.id NOT IN (" . join(', ', @values) . ")";
@@ -220,16 +223,33 @@ sub tags
        print "HASNT VALUES\n";;
        if(@used)
        {
-           push(@orclauses, "(tags.parents_id='' AND tags.id NOT IN (" . join(', ', @used) . "))");
+           push(@orclauses, "(NOT (tags.parents_id='' AND tags.id IN (" . join(', ', @used) . ")))");
        }
        for my $pair (@used_with_vals)
        {
-           push(@orclauses, "(tags.parents_id='" . $pair->[0] . "' AND tags.id!='" . $pair->[1] . "')");
+           push(@orclauses, "(NOT (tags.parents_id='" . $pair->[0] . "' AND tags.id='" . $pair->[1] . "'))");
        }
     }
+
+    my $parentclause= "(tags.parents_id='";
+    if($hasvals)
+    {
+       $parentclause .= $id;
+    }
+    elsif($parent)
+    {
+       $parentclause .= $parent;
+    }
+    $parentclause .= "')";
+    push(@andclauses, $parentclause);
+
     if(@orclauses)
     {
-       $sql .= "WHERE " . join(' OR ', @orclauses) . "\n";
+       push(@andclauses, join(' OR ', @orclauses));
+    }
+    if(@andclauses)
+    {
+       $sql .= "WHERE " . join(' AND ', @andclauses) . "\n";
     }
     $sql .= "GROUP BY tags.name;";
     print "SQL: $sql\n";
@@ -320,7 +340,6 @@ sub artist_albums
 sub artist_tracks
 {
     my($self, $artist_id, $path)=@_;
-    my @constraints=@{$path->{elements}};
     my $sql=("SELECT files.name FROM (\n" .
             $self->tags_subselect($path) .
             "\t) AS subselect\n" .
@@ -358,7 +377,14 @@ sub tracks
     # FIXME: rework PathElements
     if(ref($constraints[$#constraints]) eq "ID3FS::PathElement::Artist")
     {
-       return $self->artist_tracks($constraints[$#constraints]->{id}, @constraints);
+       my $artist_id=0;
+       my $artist=$constraints[$#constraints];
+       if(defined($artist) && (ref($artist) eq "ID3FS::PathElement::Artist"))
+       {
+           # should always happen
+           $artist_id=$artist->{id};
+       }
+       return $self->artist_tracks($artist_id, $path);
     }
     elsif(ref($constraints[$#constraints]) eq "ID3FS::PathElement::Album")
     {
@@ -408,13 +434,17 @@ sub tags_subselect
 {
     my($self, $path)=@_;
     my $tree=$path->{tagtree};
+    my $hasvals=$path->tag_has_values();
+    my $parent=$path->trailing_tag_parent();
+
     my $tag=undef;
-    if($path->tag_has_values())
+    if($hasvals)
     {
        $tag=$path->trailing_tag_id();
        print "Trailing id: $tag\n";
     }
-    my ($sqlclause, $joinsneeded)=$tree->to_sql($tag);
+    my ($sqlclause, $joinsneeded)=(undef, 1);
+    ($sqlclause, $joinsneeded) = $tree->to_sql($tag) if($tree);
     print "SQL($joinsneeded): $sqlclause\n";
     my $sql="\tSELECT fxt1.files_id FROM tags t1";
     my @crosses=();
@@ -436,7 +466,7 @@ sub tags_subselect
     }
     $sql .= ("\n\t" . join(" ", @crosses)) if(@crosses);
     $sql .= ("\n" . join("\n", @inners)) if(@inners);
-    $sql .= "\n\tWHERE $sqlclause";
+    $sql .= "\n\tWHERE $sqlclause" if($sqlclause);
 #    if($tag)
 #    {
 #      $sql .= " AND t${joinsneeded}.parents_id='$tag'";
index 5c7eacc..370c105 100644 (file)
@@ -300,14 +300,11 @@ sub parse
        }
     }
     # remove trailing boolean
-    if(@{$self->{elements}} &&
-       ref($self->{elements}->[$#{$self->{elements}}]) eq "ID3FS::PathElement::Boolean")
-    {
-       $self->{lastop}=pop @{$self->{elements}};
-    }
+    my @elements=@{$self->{elements}};
+    pop @elements if(@elements && ref($elements[$#elements]) eq "ID3FS::PathElement::Boolean");
     # sort elements by precedence
-    @{$self->{elements}}=$self->sort_elements(@{$self->{elements}});
-    $self->{tagtree}=$self->elements_to_tree([ @{$self->{elements}} ]);
+    @elements=$self->sort_elements(@elements);
+    $self->{tagtree}=$self->elements_to_tree(@elements);
     if($self->{tagtree})
     {
        ($self->{sqlconditions},
@@ -328,17 +325,17 @@ sub state
 
 sub elements_to_tree
 {
-    my($self, $elements)=@_;
-    return undef unless(@$elements);
+    my($self, @elements)=@_;
+    return undef unless(@elements);
     my ($left, $right, $op)=(undef, undef, undef);
-    my $thing=pop @$elements;
+    my $thing=pop @elements;
     if(ref($thing) eq "ID3FS::PathElement::Boolean")
     {
        my $op=$thing;
-       $right=$self->elements_to_tree($elements);
+       $right=$self->elements_to_tree(@elements);
        if($op->{name} ne "NOT")
        {
-           $left=$self->elements_to_tree($elements);
+           $left=$self->elements_to_tree(@elements);
        }
        return ID3FS::Path::Node->new($left, $op, $right);
     }
@@ -408,6 +405,7 @@ sub tag_has_values
 {
     my($self)=@_;
     my $tail=$self->{elements}->[$#{$self->{elements}}];
+    print "TAIL: ", ref($tail), "\n";
     if($tail && ref($tail) eq "ID3FS::PathElement::Tag")
     {
        return($self->{db}->tag_has_values($tail->{id}));
@@ -425,4 +423,16 @@ sub trailing_tag_id
     return undef;
 }
 
+sub trailing_tag_parent
+{
+    my($self)=@_;
+    my $tail=$self->{elements}->[$#{$self->{elements}}];
+    if($tail && ref($tail) eq "ID3FS::PathElement::Tag")
+    {
+       return($tail->{parents_id});
+    }
+    return undef;
+}
+
+
 1;
index f03d040..8adb076 100644 (file)
@@ -113,7 +113,6 @@ sub used_tags
     my($self)=@_;
     my @used=(grep { defined; }  ($self->node_used_tags($self->left()),
                                  $self->node_used_tags($self->right())));
-    print "used_tags: ", join(", ", @used), "\n";
     return(@used);
 }