merge PathElement::* into Path::Node
[id3fs.git] / lib / ID3FS / Path / Node.pm
1 package ID3FS::Path::Node;
2
3 use strict;
4 use warnings;
5
6 sub new
7 {
8     my $proto=shift;
9     my $class=ref($proto) || $proto;
10     my $self={};
11     bless($self,$class);
12
13     my $db=shift;
14     $self->{type}=shift;
15     $self->{name}=shift;
16     $self->{parents_id}=shift;
17     if($self->{type} ne "boolean")
18     {
19         my $table=ucfirst($self->{type});
20         $table .= "s" unless($table=~/s$/);
21         $self->{id}=$db->lookup_id($table, $self->{name}, $self->{parents_id});
22         return undef unless(defined($self->{id}));
23     }
24     return $self;
25 }
26
27 sub set
28 {
29     my($self, $name, $val)=@_;
30     if(defined($val))
31     {
32         $self->{$name}=$val;
33     }
34     return $self->{$name};
35 }
36
37 sub left       { return shift->set("left",       shift); }
38 sub right      { return shift->set("right",      shift); }
39 sub name       { return shift->set("name",       shift); }
40 sub type       { return shift->set("type",       shift); }
41 sub id         { return shift->set("id",         shift); }
42 sub parents_id { return shift->set("parents_id", shift); }
43
44 sub print
45 {
46     my($self)=@_;
47     my $op=$self->name();
48     my $left=$self->left();
49     my $right=$self->right();
50     return "" unless($left || $right);
51     my $str .= $self->print_node($left);
52     $str .= (" " . $op . " ") if($op);
53     $str .= $self->print_node($right);
54     if($op || ($left && $right))
55     {
56         $str="(" . $str . ")";
57     }
58     return $str;
59 }
60
61 sub print_node
62 {
63     my($self, $node)=@_;
64     return "" unless(defined($node));
65     return $node->print() if(ref($node) eq "ID3FS::Path::Node");
66     return $node->{name};
67 }
68
69 sub to_sql
70 {
71     my($self, $hasvals, $not, @joins)=@_;
72     $not=0 unless(defined($not));
73     my @outjoins=();
74     # init
75     unless(@joins)
76     {
77         @outjoins = @joins = ("INNER");
78     }
79     my $left=$self->left();
80     my $right=$self->right();
81     return ("", @outjoins) unless($left || $right);
82     my ($leftstr, @leftjoins) = $self->node_to_sql($left, $hasvals, $not, @joins);
83     push(@joins, @leftjoins);
84     push(@outjoins, @leftjoins);
85     my $op=$self->name();
86     if(defined($op) && $self->type() eq "boolean")
87     {
88         # if we are ANDing, add an inner join
89         # also if we are NOTing, but we are looking for a tag *value*
90         if( ($op eq "AND") || ($hasvals && ($op eq "NOT")))
91         {
92             # hack - if right child is a NOT, we don't need extra join/brackets
93             # NOT will do the same and we will end up with an extra one
94             unless($right && $right->name() && $right->name() eq "NOT")
95             {
96                 push(@joins, "INNER");
97                 push(@outjoins, "INNER");
98             }
99         }
100         elsif($op eq "NOT")
101         {
102             $not=1;
103             push(@joins, "LEFT");
104             push(@outjoins, "LEFT");
105 #           print("LEFT: ", $left->print(), "\n") if ($left);
106 #           print("RIGHT: ", $right->print(), "\n") if($right);
107         }
108     }
109     my ($rightstr, @rightjoins) = $self->node_to_sql($right, $hasvals, $not, @joins);
110     push(@outjoins, @rightjoins);
111 #    print "LEFT (", scalar(@leftjoins), "): $leftstr\n";
112 #    print "RIGHT (", scalar(@rightjoins), "): $rightstr\n";
113     my $str=$leftstr;
114     $str .= " $op " if($op && !$not);
115     $str .= $rightstr;
116     if($op || ($left && $right))
117     {
118         $str="(" . $str . ")";
119     }
120 #    print "STR: $str\n";
121     return($str, @outjoins);
122 }
123
124 sub node_to_sql
125 {
126     my($self, $node, $hasvals, $not, @joins)=@_;
127     return ("", ()) unless(defined($node));
128     return $node->to_sql($hasvals, $not, @joins) if($node->type() eq "boolean");
129     my $sql;
130     my $cnt=scalar(@joins)+1;
131     if(defined($node->{parents_id}))
132     {
133         $sql= "(t" . scalar(@joins) . ".parents_id='$node->{parents_id}'";
134         $sql .= " AND t" . scalar(@joins) . ".id='" . $node->{id} . "'";
135     }
136     else
137     {
138         $sql= "(t" . scalar(@joins) .".parents_id=''";
139         $sql .= " AND t" . scalar(@joins) . ".id='" . $node->{id} . "'";
140     }
141     if($not && !$hasvals)
142     {
143         $sql .= " AND fxt" . scalar(@joins) . ".files_id IS NULL";
144     }
145     $sql .= ")";
146     return ($sql, ());
147 }
148
149 sub used_tags
150 {
151     my($self)=@_;
152     if($self->type() eq "boolean")
153     {
154         my @used=();
155         push(@used, $self->left()->used_tags())  if($self->left());
156         push(@used, $self->right()->used_tags()) if($self->right());
157         print "BOOL: ", $self->name(), join(', ', grep { defined; } @used), "\n";
158         return(grep { defined; } @used);
159     }
160     elsif($self->parents_id())
161     {
162         return([ $self->parents_id(), $self->id() ]);
163     }
164     return $self->id();
165 }
166
167 1;