Showing 4 changed files with 163 additions and 24 deletions
+13 -16
lib/DBIx/Custom/QueryBuilder.pm
... ...
@@ -54,7 +54,7 @@ sub _parse {
54 54
     
55 55
     # Source
56 56
     $source ||= '';
57
-    
57
+
58 58
     # Tree
59 59
     my $tree = [];
60 60
     
... ...
@@ -86,18 +86,10 @@ sub _parse {
86 86
             # Get tag name and arguments
87 87
             my ($tag_name, @tag_args) = split /\s+/, $tag;
88 88
             
89
-            # Tag processor not registerd
90
-            croak qq{Tag "$tag" in "$original" is not registerd}
89
+            # Tag processor not registered
90
+            croak qq{Tag "$tag_name" in "$original" is not registered}
91 91
                unless $self->tag_processors->{$tag_name};
92 92
             
93
-            # Check tag arguments
94
-            foreach my $tag_arg (@tag_args) {
95
-            
96
-                # Cannot cantain placehosder '?'
97
-                croak qq{Tag cannot contains "?"}
98
-                  if $tag_arg =~ /\?/;
99
-            }
100
-            
101 93
             # Add tag to parsing tree
102 94
             push @$tree, {type => 'tag', tag_name => $tag_name,
103 95
                           tag_args => [@tag_args]};
... ...
@@ -145,15 +137,14 @@ sub _build_query {
145 137
               unless ref $tag_processor eq 'CODE';
146 138
             
147 139
             # Execute tag processor
148
-            my ($part, $columns) = @{$tag_processor->(@$tag_args)};
140
+            my $r = $tag_processor->(@$tag_args);
149 141
             
150 142
             # Check tag processor return value
151 143
             croak qq{Tag processor "$tag_name" must return [STRING, ARRAY_REFERENCE]}
152
-              if !defined $part || ref $columns ne 'ARRAY';
144
+              unless ref $r eq 'ARRAY' && defined $r->[0] && ref $r->[1] eq 'ARRAY';
153 145
             
154
-            # Check placeholder count
155
-            croak qq{Count of Placeholders must be same as count of columns in "$tag_name"}
156
-              unless $self->_placeholder_count($part) eq @$columns;
146
+            # Part of SQL statement and colum names
147
+            my ($part, $columns) = @$r;
157 148
             
158 149
             # Add columns
159 150
             push @$all_columns, @$columns;
... ...
@@ -162,6 +153,12 @@ sub _build_query {
162 153
             $sql .= $part;
163 154
         }
164 155
     }
156
+
157
+    # Check placeholder count
158
+    my $placeholder_count = $self->_placeholder_count($sql);
159
+    my $column_count      = @$all_columns;
160
+    croak qq{Placeholder count in "$sql" must be same as column count $column_count}
161
+      unless $placeholder_count eq @$all_columns;
165 162
     
166 163
     # Add semicolon
167 164
     $sql .= ';' unless $sql =~ /;$/;
+2 -2
lib/DBIx/Custom/QueryBuilder/TagProcessors.pm
... ...
@@ -9,7 +9,7 @@ sub _basic {
9 9
     my ($name, $column) = @_;
10 10
     
11 11
     # Check arguments
12
-    croak qq{Column must be specified in tag "{$name }"}
12
+    croak qq{Column name must be specified in tag "{$name }"}
13 13
       unless $column;
14 14
     
15 15
     return ["$column $name ?", [$column]];
... ...
@@ -37,7 +37,7 @@ sub in {
37 37
     my ($column, $count) = @_;
38 38
     
39 39
     # Check arguments
40
-    croak qq{Column and count of values must be specified in tag "{in }"}
40
+    croak qq{Column name and count of values must be specified in tag "{in }"}
41 41
       unless $column && $count && $count =~ /^\d+$/;
42 42
 
43 43
     # Part of statement
+6 -6
t/dbix-custom-core.t
... ...
@@ -3,7 +3,7 @@ use strict;
3 3
 use warnings;
4 4
 
5 5
 use DBIx::Custom;
6
-use DBIx::Custom::SQLTemplate;
6
+use DBIx::Custom::QueryBuilder;
7 7
 
8 8
 # Function for test name
9 9
 my $test;
... ...
@@ -13,9 +13,9 @@ sub test {
13 13
 
14 14
 # Variables for test
15 15
 our $SQL_TMPL = {
16
-    0 => DBIx::Custom::SQLTemplate->new->tag_start(0),
17
-    1 => DBIx::Custom::SQLTemplate->new->tag_start(1),
18
-    2 => DBIx::Custom::SQLTemplate->new->tag_start(2)
16
+    0 => DBIx::Custom::QueryBuilder->new->tag_start(0),
17
+    1 => DBIx::Custom::QueryBuilder->new->tag_start(1),
18
+    2 => DBIx::Custom::QueryBuilder->new->tag_start(2)
19 19
 };
20 20
 my $dbi;
21 21
 
... ...
@@ -31,12 +31,12 @@ $dbi = DBIx::Custom->new(
31 31
     default_bind_filter => 'f',
32 32
     default_fetch_filter => 'g',
33 33
     result_class => 'g',
34
-    sql_builder_class => $SQL_TMPL->{0},
34
+    sql_builder => $SQL_TMPL->{0},
35 35
 );
36 36
 is_deeply($dbi,{user => 'a', database => 'a', password => 'b', data_source => 'c', 
37 37
                 filters => {f => 3}, default_bind_filter => 'f',
38 38
                 default_fetch_filter => 'g', result_class => 'g',
39
-                sql_builder_class => $SQL_TMPL->{0}}, $test);
39
+                sql_builder => $SQL_TMPL->{0}}, $test);
40 40
 isa_ok($dbi, 'DBIx::Custom');
41 41
 
42 42
 
+142
t/dbix-custom-querybuilder.t
... ...
@@ -0,0 +1,142 @@
1
+use strict;
2
+use warnings;
3
+
4
+use Test::More 'no_plan';
5
+
6
+use DBIx::Custom::QueryBuilder;
7
+
8
+# Function for test name
9
+my $test;
10
+sub test{
11
+    $test = shift;
12
+}
13
+
14
+# Variable for test
15
+my $datas;
16
+my $builder;
17
+my $query;
18
+my $ret_val;
19
+
20
+test "Various source pattern";
21
+$datas = [
22
+    # Basic tests
23
+    {   name            => 'placeholder basic',
24
+        source            => "a {?  k1} b {=  k2} {<> k3} {>  k4} {<  k5} {>= k6} {<= k7} {like k8}", ,
25
+        sql_expected    => "a ? b k2 = ? k3 <> ? k4 > ? k5 < ? k6 >= ? k7 <= ? k8 like ?;",
26
+        columns_expected   => [qw/k1 k2 k3 k4 k5 k6 k7 k8/]
27
+    },
28
+    {
29
+        name            => 'placeholder in',
30
+        source            => "{in k1 3};",
31
+        sql_expected    => "k1 in (?, ?, ?);",
32
+        columns_expected   => [qw/k1 k1 k1/]
33
+    },
34
+    
35
+    # Table name
36
+    {
37
+        name            => 'placeholder with table name',
38
+        source            => "{= a.k1} {= a.k2}",
39
+        sql_expected    => "a.k1 = ? a.k2 = ?;",
40
+        columns_expected  => [qw/a.k1 a.k2/]
41
+    },
42
+    {   
43
+        name            => 'placeholder in with table name',
44
+        source            => "{in a.k1 2} {in b.k2 2}",
45
+        sql_expected    => "a.k1 in (?, ?) b.k2 in (?, ?);",
46
+        columns_expected  => [qw/a.k1 a.k1 b.k2 b.k2/]
47
+    },
48
+    {
49
+        name            => 'not contain tag',
50
+        source            => "aaa",
51
+        sql_expected    => "aaa;",
52
+        columns_expected  => [],
53
+    }
54
+];
55
+
56
+for (my $i = 0; $i < @$datas; $i++) {
57
+    my $data = $datas->[$i];
58
+    my $builder = DBIx::Custom::QueryBuilder->new;
59
+    my $query = $builder->build_query($data->{source});
60
+    is($query->{sql}, $data->{sql_expected}, "$test : $data->{name} : sql");
61
+    is_deeply($query->{columns}, $data->{columns_expected}, "$test : $data->{name} : columns");
62
+}
63
+
64
+
65
+test 'Original tag processor';
66
+$builder = DBIx::Custom::QueryBuilder->new;
67
+
68
+$ret_val = $builder->register_tag_processor(
69
+    p => sub {
70
+        my @args = @_;
71
+        
72
+        my $expand    = "? $args[0] $args[1]";
73
+        my $columns = [2];
74
+        return [$expand, $columns];
75
+    }
76
+);
77
+
78
+$query = $builder->build_query("{p a b}");
79
+is($query->{sql}, "? a b;", "$test : register_tag_processor sql");
80
+is_deeply($query->{columns}, [2], "$test : register_tag_processor columns");
81
+isa_ok($ret_val, 'DBIx::Custom::QueryBuilder');
82
+
83
+
84
+test "Tag processor error case";
85
+$builder = DBIx::Custom::QueryBuilder->new;
86
+
87
+
88
+eval{$builder->build_query("{a }")};
89
+like($@, qr/\QTag "a" in "{a }" is not registered/, "$test : tag_processor not exist");
90
+
91
+$builder->register_tag_processor({
92
+    q => 'string'
93
+});
94
+
95
+eval{$builder->build_query("{q}", {})};
96
+like($@, qr/Tag processor "q" must be sub reference/, "$test : tag_processor not code ref");
97
+
98
+$builder->register_tag_processor({
99
+   r => sub {} 
100
+});
101
+
102
+eval{$builder->build_query("{r}")};
103
+like($@, qr/\QTag processor "r" must return [STRING, ARRAY_REFERENCE]/, "$test : tag processor return noting");
104
+
105
+$builder->register_tag_processor({
106
+   s => sub { return ["a", ""]} 
107
+});
108
+
109
+eval{$builder->build_query("{s}")};
110
+like($@, qr/\QTag processor "s" must return [STRING, ARRAY_REFERENCE]/, "$test : tag processor return not array columns");
111
+
112
+$builder->register_tag_processor(
113
+    t => sub {return ["a", []]}
114
+);
115
+
116
+
117
+test 'General error case';
118
+$builder = DBIx::Custom::QueryBuilder->new;
119
+$builder->register_tag_processor(
120
+    a => sub {
121
+        return ["? ? ?", ['']];
122
+    }
123
+);
124
+eval{$builder->build_query("{a}")};
125
+like($@, qr/\QPlaceholder count in "? ? ?" must be same as column count 1/, "$test : placeholder count is invalid");
126
+
127
+
128
+test 'Default tag processor Error case';
129
+eval{$builder->build_query("{= }")};
130
+like($@, qr/Column name must be specified in tag "{= }"/, "$test : basic '=' : key not exist");
131
+
132
+eval{$builder->build_query("{in }")};
133
+like($@, qr/Column name and count of values must be specified in tag "{in }"/, "$test : in : key not exist");
134
+
135
+eval{$builder->build_query("{in a}")};
136
+like($@, qr/\QColumn name and count of values must be specified in tag "{in }"/,
137
+     "$test : in : key not exist");
138
+
139
+eval{$builder->build_query("{in a r}")};
140
+like($@, qr/\QColumn name and count of values must be specified in tag "{in }"/,
141
+     "$test : in : key not exist");
142
+