X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2FID3FS%2FPath%2FNode.pm;h=6254600e5a87742970a2bb3117063c57238036e9;hb=c8571ddb3cc1f9bce16c91838de17f27242d2f32;hp=87b1b6e8c81e3983dce126167407c17b3be02644;hpb=b2f0890522f6172d809b9f74d18346b77372f3d0;p=id3fs.git diff --git a/lib/ID3FS/Path/Node.pm b/lib/ID3FS/Path/Node.pm index 87b1b6e..6254600 100644 --- a/lib/ID3FS/Path/Node.pm +++ b/lib/ID3FS/Path/Node.pm @@ -1,8 +1,30 @@ +# id3fs - a FUSE-based filesystem for browsing audio metadata +# Copyright (C) 2010 Ian Beckwith +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + package ID3FS::Path::Node; use strict; use warnings; +require Exporter; +use vars qw(@ISA @EXPORT $TYPE_BOOL $TYPE_TAG $TYPE_ARTIST $TYPE_ALBUM $TYPE_FILE); +@ISA=qw(Exporter); +@EXPORT=qw($TYPE_BOOL $TYPE_TAG $TYPE_ARTIST $TYPE_ALBUM $TYPE_FILE); +($TYPE_BOOL, $TYPE_TAG, $TYPE_ARTIST, $TYPE_ALBUM, $TYPE_FILE)=(1..5); + sub new { my $proto=shift; @@ -10,10 +32,20 @@ sub new my $self={}; bless($self,$class); - $self->left(shift); - $self->op(shift); - $self->right(shift); - + my $db=shift; + $self->{type}=shift; + $self->{name}=shift; + $self->{parents_id}=shift; + if($self->{type} != $TYPE_BOOL) + { + my $table=''; + if ($self->{type} == $TYPE_TAG) { $table="tags"; } + elsif($self->{type} == $TYPE_ARTIST) { $table="artists"; } + elsif($self->{type} == $TYPE_ALBUM) { $table="albums"; } + elsif($self->{type} == $TYPE_FILE) { $table="files"; } + $self->{id}=$db->lookup_id($table, $self->{name}, $self->{parents_id}); + return undef unless(defined($self->{id})); + } return $self; } @@ -27,137 +59,118 @@ sub set return $self->{$name}; } -sub left { return shift->set("left", shift); } -sub right { return shift->set("right", shift); } -sub op { return shift->set("op", shift); } +sub left { return shift->set("left", shift); } +sub right { return shift->set("right", shift); } +sub name { return shift->set("name", shift); } +sub type { return shift->set("type", shift); } +sub id { return shift->set("id", shift); } +sub parents_id { return shift->set("parents_id", shift); } -sub print +sub to_sql { - my($self)=@_; - my $op=$self->op(); - my $left=$self->left(); - my $right=$self->right(); - return "" unless($left || $right); - my $str .= $self->print_node($left); - $str .= (" " . $op->{name} . " ") if($op); - $str .= $self->print_node($right); - if($op || ($left && $right)) + my($self, $hasvals, $not, @joins)=@_; + $not=0 unless(defined($not)); + my @outjoins=(); + unless(@joins) { - $str="(" . $str . ")"; + @outjoins = @joins = ("INNER"); } - return $str; -} - -sub print_node -{ - my($self, $node)=@_; - return "" unless(defined($node)); - return $node->print() if(ref($node) eq "ID3FS::Path::Node"); - return $node->{name}; -} + my $str=''; -sub to_sql -{ - my($self, $parent, @injoins)=@_; - my @childjoins=@injoins; - my @outjoins=(); - # init - unless(@injoins) + if($self->type() != $TYPE_BOOL) { - print "\nSTART\n"; - @outjoins = @childjoins = ("INNER"); + $str .= "t" . scalar(@joins) . ".id='" . $self->{id} . "'"; + if($not && !$hasvals) + { + $str = "(" . $str . " AND fxt" . scalar(@joins) . ".files_id IS NULL)"; + } + return ($str, @outjoins); } - print "OUT: ", join(', ', @outjoins), "\n"; - print "CLD: ", join(', ', @childjoins), "\n"; - my (@leftjoins, @rightjoins); - my ($leftstr, $rightstr); - my $op=$self->op(); + my $left=$self->left(); my $right=$self->right(); return ("", @outjoins) unless($left || $right); - ($leftstr, @leftjoins) = $self->node_to_sql($left, $parent, @childjoins); -# $andlevel=$self->max($andlevel, $leftandlevel); + my ($leftstr, @leftjoins) = $left->to_sql($hasvals, $not, @joins) if($left); + push(@joins, @leftjoins); + push(@outjoins, @leftjoins); + my $op=$self->name(); + print "op: $op type: ", $self->type(), " not: $not\n"; if(defined($op)) { - if($op->{name} eq "AND") + # if we are ANDing, add an inner join + # also if we are NOTing, but we are looking for a tag *value* + if($op eq "AND") + { + print "AND\n"; + # hack - if right child is a NOT, we don't need extra join/brackets + # NOT will do the same and we will end up with an extra one + unless($right && $right->name() && $right->name() eq "NOT") + { + push(@joins, "INNER"); + push(@outjoins, "INNER"); + } + } + elsif($op eq "NOT") { - push(@childjoins, "INNER"); - push(@outjoins, "INNER"); + print "NOT (was $not)\n"; + $not=1; + # as above - if right child is a NOT, we don't need extra join/brackets + # NOT will do the same and we will end up with an extra one + unless($right && $right->name() && $right->name() eq "NOT") + { + if($hasvals) + { + push(@joins, "INNER"); + push(@outjoins, "INNER"); + } + else + { + push(@joins, "LEFT"); + push(@outjoins, "LEFT"); + } + } } - elsif($op->{name} eq "NOT") + elsif($op eq "OR") { - push(@childjoins, "LEFT"); - push(@outjoins, "LEFT"); + print "OR\n"; + # if left child is a NOT, we need an extra (inner) join + # unless right child is also a NOT + if(($left && $left->name() && $left->name() eq "NOT") && + !($right && $right->name() && $right->name() eq "NOT")) + { + push(@joins, "INNER"); + push(@outjoins, "INNER"); + } } } - ($rightstr, @rightjoins) = $self->node_to_sql($right, $parent, @leftjoins, @childjoins); - print "LEFT (", scalar(@leftjoins), "): $leftstr\n"; - print "RIGHT (", scalar(@rightjoins), "): $rightstr\n"; - my $str=$leftstr; - $str .= (" " . $op->{name} . " ") if($op); + my ($rightstr, @rightjoins) = $right->to_sql($hasvals, $not, @joins) if($right); + push(@outjoins, @rightjoins); +# print "LEFT (", scalar(@leftjoins), "): $leftstr\n"; +# print "RIGHT (", scalar(@rightjoins), "): $rightstr\n"; + $str=$leftstr; + $str .= " $op " if($op && !$not); $str .= $rightstr; - if($op || ($left && $right)) + if($op && $left && $right) { $str="(" . $str . ")"; } - print "STR: $str\n"; -# return($str, $self->max($leftandlevel, $rightandlevel)); - my @oldout=@outjoins; - @outjoins = (@leftjoins, @outjoins, @rightjoins); - if($op) - { - print "ME (", (defined($op) ? $op->{name} : ""), "): "; - print(scalar(@outjoins), " = " , scalar(@leftjoins), " + ", scalar(@oldout), - " + ", scalar(@rightjoins), "\n"); - } +# print "STR: $str\n"; +# my @all=(@joins, @rightjoins); +# print "JOINS: RETURN ", scalar(@outjoins), " ALL ", scalar(@all), "\n"; return($str, @outjoins); } -sub node_to_sql -{ - my($self, $node, $parent, @joins)=@_; - return ("", ()) unless(defined($node)); - return $node->to_sql($parent, @joins) if(ref($node) eq "ID3FS::Path::Node"); - my $sql; - my $cnt=scalar(@joins)+1; - if(defined($node->{parents_id})) - { - $sql= "(t" . scalar(@joins) . ".parents_id='$node->{parents_id}'"; - $sql .= " AND fxt" . scalar(@joins) . ".tags_id='" . $node->{id} . "')"; - } - else - { - $sql= "(t" . scalar(@joins) .".parents_id=''"; - $sql .= " AND fxt" . scalar(@joins) . ".tags_id='" . $node->{id} . "')"; - } - return ($sql, ()); -} - sub used_tags { my($self)=@_; - my @used=(grep { defined; } ($self->node_used_tags($self->left()), - $self->node_used_tags($self->right()))); - return(@used); -} - -sub node_used_tags -{ - my($self, $node)=@_; - return (undef) unless(defined($node)); - return $node->used_tags() if(ref($node) eq "ID3FS::Path::Node"); - if(defined($node->{parents_id})) + if($self->type() == $TYPE_BOOL) { - return([ $node->{parents_id}, $node->{id} ]); + my @used=(); + push(@used, $self->left()->used_tags()) if($self->left()); + push(@used, $self->right()->used_tags()) if($self->right()); + return(grep { defined; } @used); } - return $node->{id}; -} - - -sub max -{ - my($self, $a, $b)=@_; - return(($a > $b) ? $a : $b); + return $self->id(); } 1;