DBIx-Custom / lib / DBIx / Custom / QueryBuilder.pm /
Newer Older
377 lines | 9.427kb
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
1
package DBIx::Custom::QueryBuilder;
2

            
updatedd pod
Yuki Kimoto authored on 2011-06-12
3
use Object::Simple -base;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
4

            
5
use Carp 'croak';
6
use DBIx::Custom::Query;
cleanup
Yuki Kimoto authored on 2011-04-25
7
use DBIx::Custom::Util '_subname';
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
8

            
fixed Carp trast relationshi...
yuki-kimoto authored on 2010-08-12
9
# Carp trust relationship
10
push @DBIx::Custom::CARP_NOT, __PACKAGE__;
updated document
Yuki Kimoto authored on 2011-01-20
11
push @DBIx::Custom::Where::CARP_NOT, __PACKAGE__;
12

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
13
# Parameter regex
14
our $PARAM_RE = qr/(^|[^\.\w]):([\.\w]+)([^\.\w]|$)/sm;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
15

            
cleanup
yuki-kimoto authored on 2010-10-17
16
sub build_query {
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
17
    my ($self, $source) = @_;
cleanup
yuki-kimoto authored on 2010-10-17
18
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
19
    my $query;
20
    
21
    # Parse tag. tag is DEPRECATED!
22
    if ($source =~ /\{/ && $source =~ /\}/) {
23
        $query = $self->_parse_tag($source);
24
        my $tag_count = delete $query->{tag_count};
fixed DEPRECATED message bug
Yuki Kimoto authored on 2011-06-10
25
        warn qq/Tag system such as {? name} is DEPRECATED! / .
26
             qq/use parameter system such as :name instead/
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
27
          if $tag_count;
28
        my $query2 = $self->_parse_parameter($query->sql);
29
        $query->sql($query2->sql);
30
        for (my $i =0; $i < @{$query->columns}; $i++) {
31
            my $column = $query->columns->[$i];
32
            if ($column eq 'RESERVED_PARAMETER') {
33
                my $column2 = shift @{$query2->columns};
34
                croak ":name syntax is wrong"
35
                  unless defined $column2;
36
                $query->columns->[$i] = $column2;
37
            }
38
        }
39
    }
cleanup
yuki-kimoto authored on 2010-10-17
40
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
41
    # Parse parameter
42
    else {
43
        $query = $self->_parse_parameter($source);
44
    }
cleanup
yuki-kimoto authored on 2010-10-17
45
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
46
    my $sql = $query->sql;
47
    $sql .= ';' unless $source =~ /;$/;
48
    $query->sql($sql);
49

            
50
    # Check placeholder count
51
    croak qq{Placeholder count in "$sql" must be same as column count}
52
        . _subname
53
      unless $self->_placeholder_count($sql) eq @{$query->columns};
54
        
cleanup
yuki-kimoto authored on 2010-10-17
55
    return $query;
56
}
57

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
58
sub _placeholder_count {
59
    my ($self, $sql) = @_;
changed argument of tag proc...
yuki-kimoto authored on 2010-08-03
60
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
61
    # Count
62
    $sql ||= '';
63
    my $count = 0;
64
    my $pos   = -1;
65
    while (($pos = index($sql, '?', $pos + 1)) != -1) {
66
        $count++;
67
    }
68
    return $count;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
69
}
70

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
71
sub _parse_parameter {
72
    my ($self, $source) = @_;
add table tag
Yuki Kimoto authored on 2011-02-09
73
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
74
    # Get and replace parameters
75
    my $sql = $source || '';
76
    my $columns = [];
77
    while ($source =~ /$PARAM_RE/g) {
78
        push @$columns, $2;
cleanup
yuki-kimoto authored on 2010-10-17
79
    }
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
80
    $sql =~ s/$PARAM_RE/$1?$3/g;
cleanup
yuki-kimoto authored on 2010-10-17
81

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
82
    # Create query
add table tag
Yuki Kimoto authored on 2011-02-09
83
    my $query = DBIx::Custom::Query->new(
84
        sql => $sql,
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
85
        columns => $columns
add table tag
Yuki Kimoto authored on 2011-02-09
86
    );
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
87
    
88
    return $query;
89
}
90

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
91
# DEPRECATED!
92
__PACKAGE__->attr('tags' => sub { {} });
93

            
94
# DEPRECATED!
95
sub register_tag {
96
    my $self = shift;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
97
    
added warnings
Yuki Kimoto authored on 2011-06-07
98
    warn "register_tag is DEPRECATED!";
99
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
100
    # Merge tag
101
    my $tags = ref $_[0] eq 'HASH' ? $_[0] : {@_};
102
    $self->tags({%{$self->tags}, %$tags});
103
    
104
    return $self;
105
}
106

            
107
# DEPRECATED!
108
sub _parse_tag {
109
    my ($self, $source) = @_;
110

            
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
111
    # Source
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
112
    $source ||= '';
fixed tests
yuki-kimoto authored on 2010-08-06
113

            
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
114
    # Tree
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
115
    my @tree;
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
116
    
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
117
    # Value
118
    my $value = '';
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
119
    
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
120
    # State
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
121
    my $state = 'text';
122
    
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
123
    # Before charactor
124
    my $before = '';
125

            
126
    # Position
fixed DBIx::Custom::QueryBui...
yuki-kimoto authored on 2010-08-15
127
    my $pos = 0;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
128
    
129
    # Parse
added tests
yuki-kimoto authored on 2010-08-12
130
    my $original = $source;
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
131
    my $tag_count = 0;
fixed DBIx::Custom::QueryBui...
yuki-kimoto authored on 2010-08-15
132
    while (defined(my $c = substr($source, $pos, 1))) {
133
        
134
        # Last
135
        last unless length $c;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
136
        
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
137
        # Parameter
138
        if ($c eq ':' && (substr($source, $pos + 1, 1) || '') =~ /\w/) {
139
            push @tree, {type => 'param'};;
140
        }
141
        
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
142
        # State is text
143
        if ($state eq 'text') {
144
            
145
            # Tag start charactor
146
            if ($c eq '{') {
147
                
148
                # Escaped charactor
149
                if ($before eq "\\") {
150
                    substr($value, -1, 1, '');
151
                    $value .= $c;
152
                }
153
                
154
                # Tag start
155
                else {
156
                    
157
                    # Change state
158
                    $state = 'tag';
159
                    
160
                    # Add text
161
                    push @tree, {type => 'text', value => $value}
162
                      if $value;
163
                    
164
                    # Clear
165
                    $value = '';
166
                }
167
            }
168
            
169
            # Tag end charactor
170
            elsif ($c eq '}') {
171
            
172
                # Escaped charactor
173
                if ($before eq "\\") {
174
                    substr($value, -1, 1, '');
175
                    $value .= $c;
176
                }
177
                
178
                # Unexpected
179
                else {
improved error messages
Yuki Kimoto authored on 2011-04-18
180
                    croak qq{Parsing error. unexpected "\}". }
cleanup
Yuki Kimoto authored on 2011-04-25
181
                        . qq{pos $pos of "$original" } . _subname
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
182
                }
183
            }
184
            
185
            # Normal charactor
186
            else { $value .= $c }
187
        }
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
188
        
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
189
        # State is tags
added tests
yuki-kimoto authored on 2010-08-12
190
        else {
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
191
            
192
            # Tag start charactor
193
            if ($c eq '{') {
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
194
            
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
195
                # Escaped charactor
196
                if ($before eq "\\") {
197
                    substr($value, -1, 1, '');
198
                    $value .= $c;
199
                }
200
                
201
                # Unexpected
202
                else {
improved error messages
Yuki Kimoto authored on 2011-04-18
203
                    croak qq{Parsing error. unexpected "\{". }
cleanup
Yuki Kimoto authored on 2011-04-25
204
                        . qq{pos $pos of "$original" } . _subname
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
205
                }
206
            }
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
207
            
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
208
            # Tag end charactor
209
            elsif ($c eq '}') {
210
                
211
                # Escaped charactor
212
                if ($before eq "\\") {
213
                    substr($value, -1, 1, '');
214
                    $value .= $c;
215
                }
216
                
217
                # Tag end
218
                else {
219
                
220
                    # Change state
221
                    $state = 'text';
222
                    
223
                    # Add tag
224
                    my ($tag_name, @tag_args) = split /\s+/, $value;
225
                    push @tree, {type => 'tag', tag_name => $tag_name, 
226
                                 tag_args => \@tag_args};
227
                    
228
                    # Clear
229
                    $value = '';
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
230
                    
231
                    # Countup
232
                    $tag_count++;
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
233
                }
234
            }
235
            
236
            # Normal charactor
237
            else { $value .= $c }
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
238
        }
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
239
        
240
        # Save before charactor
241
        $before = $c;
242
        
243
        # increment position
244
        $pos++;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
245
    }
246
    
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
247
    # Tag not finished
cleanup
Yuki Kimoto authored on 2011-04-25
248
    croak qq{Tag not finished. "$original" } . _subname
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
249
      if $state eq 'tag';
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
250
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
251
    # Not contains tag
252
    return DBIx::Custom::Query->new(sql => $source, tag_count => $tag_count)
253
      if $tag_count == 0;
254
    
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
255
    # Add rest text
256
    push @tree, {type => 'text', value => $value}
257
      if $value;
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
258
        
259
    # SQL
260
    my $sql = '';
removed DBIx::Custom::Query ...
yuki-kimoto authored on 2010-08-12
261
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
262
    # All Columns
263
    my $all_columns = [];
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
264
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
265
    # Tables
266
    my $tables = [];
267
    
268
    # Build SQL 
269
    foreach my $node (@tree) {
270
        
271
        # Text
272
        if ($node->{type} eq 'text') { $sql .= $node->{value} }
273
        
274
        # Parameter
275
        elsif ($node->{type} eq 'param') {
276
            push @$all_columns, 'RESERVED_PARAMETER';
277
        }
278
        # Tag
279
        else {
280
            
281
            # Tag name
282
            my $tag_name = $node->{tag_name};
283
            
284
            # Tag arguments
285
            my $tag_args = $node->{tag_args};
286
            
287
            # Table
288
            if ($tag_name eq 'table') {
289
                my $table = $tag_args->[0];
290
                push @$tables, $table;
291
                $sql .= $table;
292
                next;
293
            }
294

            
295
            # Get tag
296
            my $tag = $self->tag_processors->{$tag_name}
297
                             || $self->tags->{$tag_name};
298
            
299
            # Tag is not registered
300
            croak qq{Tag "$tag_name" is not registered } . _subname
301
              unless $tag;
302
            
303
            # Tag not sub reference
304
            croak qq{Tag "$tag_name" must be sub reference } . _subname
305
              unless ref $tag eq 'CODE';
306
            
307
            # Execute tag
308
            my $r = $tag->(@$tag_args);
309
            
310
            # Check tag return value
311
            croak qq{Tag "$tag_name" must return [STRING, ARRAY_REFERENCE] }
312
                . _subname
313
              unless ref $r eq 'ARRAY' && defined $r->[0] && ref $r->[1] eq 'ARRAY';
314
            
315
            # Part of SQL statement and colum names
316
            my ($part, $columns) = @$r;
317
            
318
            # Add columns
319
            push @$all_columns, @$columns;
320
            
321
            # Join part tag to SQL
322
            $sql .= $part;
323
        }
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
324
    }
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
325

            
326
    # Query
327
    my $query = DBIx::Custom::Query->new(
328
        sql => $sql,
329
        columns => $all_columns,
330
        tables => $tables,
331
        tag_count => $tag_count
332
    );
333
    
334
    return $query;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
335
}
336

            
cleanup
Yuki Kimoto authored on 2011-01-25
337
# DEPRECATED!
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
338
__PACKAGE__->attr('tag_processors' => sub { {} });
339

            
cleanup
Yuki Kimoto authored on 2011-01-25
340
# DEPRECATED!
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
341
sub register_tag_processor {
342
    my $self = shift;
343
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
344
    warn "register_tag_processor is DEPRECATED! use register_tag instead";
345
    
cleanup
Yuki Kimoto authored on 2011-01-25
346
    # Merge tag
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
347
    my $tag_processors = ref $_[0] eq 'HASH' ? $_[0] : {@_};
348
    $self->tag_processors({%{$self->tag_processors}, %{$tag_processors}});
349
    
350
    return $self;
351
}
352

            
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
353
1;
354

            
355
=head1 NAME
356

            
357
DBIx::Custom::QueryBuilder - Query builder
358

            
359
=head1 SYNOPSIS
360
    
361
    my $builder = DBIx::Custom::QueryBuilder->new;
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
362
    my $query = $builder->build_query(
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
363
        "select from table title = :title and author = :author"
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
364
    );
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
365

            
366
=head1 METHODS
367

            
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
368
L<DBIx::Custom::QueryBuilder> inherits all methods from L<Object::Simple>
369
and implements the following new ones.
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
370

            
371
=head2 C<build_query>
372
    
373
    my $query = $builder->build_query($source);
374

            
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
375
Create a new L<DBIx::Custom::Query> object from SQL source.
update document
yuki-kimoto authored on 2010-08-07
376

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
377
=cut