DBIx-Custom / lib / DBIx / Custom / QueryBuilder.pm /
Newer Older
321 lines | 8.951kb
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

            
cleanup
Yuki Kimoto authored on 2011-07-29
13
has 'safety_character';
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
14

            
cleanup
yuki-kimoto authored on 2010-10-17
15
sub build_query {
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
16
    my ($self, $source) = @_;
cleanup
yuki-kimoto authored on 2010-10-17
17
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
18
    my $query;
19
    
20
    # Parse tag. tag is DEPRECATED!
added tag_parse attribute
Yuki Kimoto authored on 2011-06-28
21
    $self->{_tag_parse} = 1 unless defined $self->{_tag_parse};
- removed some EXPERIMENTAL ...
Yuki Kimoto authored on 2011-07-30
22
    if ($self->{_tag_parse} && $source =~ /(\s|^)\{/) {
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
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
added tag_parse attribute
Yuki Kimoto authored on 2011-06-28
42
    else { $query = $self->_parse_parameter($source) }
cleanup
yuki-kimoto authored on 2010-10-17
43
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
44
    my $sql = $query->sql;
45
    $sql .= ';' unless $source =~ /;$/;
46
    $query->sql($sql);
47

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

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

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
69
sub _parse_parameter {
70
    my ($self, $source) = @_;
fixed named placeholder bug ...
Yuki Kimoto authored on 2011-08-01
71
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
72
    # Get and replace parameters
73
    my $sql = $source || '';
74
    my $columns = [];
cleanup
Yuki Kimoto authored on 2011-07-29
75
    my $c = $self->safety_character;
76
    # Parameter regex
fixed named placeholder bug ...
Yuki Kimoto authored on 2011-08-01
77
    $sql =~ s/([^:]):(\d+):([^:])/$1\\:$2\\:$3/g;
78
    my $re = qr/(^|.*?[^\\]):([$c\.]+)(?:\{(.*?)\})?(.*)/s;
cleanup
Yuki Kimoto authored on 2011-07-29
79
    while ($sql =~ /$re/g) {
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
80
        push @$columns, $2;
added EXPERIMENTAL parameter...
Yuki Kimoto authored on 2011-07-29
81
        $sql = defined $3 ? "$1$2 $3 ?$4" : "$1?$4";
cleanup
yuki-kimoto authored on 2010-10-17
82
    }
fixed named placeholder bug ...
Yuki Kimoto authored on 2011-08-01
83
    $sql =~ s/\\:/:/g;
cleanup
yuki-kimoto authored on 2010-10-17
84

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
85
    # Create query
add table tag
Yuki Kimoto authored on 2011-02-09
86
    my $query = DBIx::Custom::Query->new(
87
        sql => $sql,
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
88
        columns => $columns
add table tag
Yuki Kimoto authored on 2011-02-09
89
    );
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
90
    
91
    return $query;
92
}
fixed named placeholder bug ...
Yuki Kimoto authored on 2011-08-01
93
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
94
# DEPRECATED!
cleanup
Yuki Kimoto authored on 2011-06-13
95
has tags => sub { {} };
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
96

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

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

            
cleanup
Yuki Kimoto authored on 2011-01-25
284
# DEPRECATED!
cleanup
Yuki Kimoto authored on 2011-06-13
285
has tag_processors => sub { {} };
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
286

            
cleanup
Yuki Kimoto authored on 2011-01-25
287
# DEPRECATED!
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
288
sub register_tag_processor {
289
    my $self = shift;
- added EXPERIMENTAL order m...
Yuki Kimoto authored on 2011-06-28
290
    warn "register_tag_processor is DEPRECATED!";
cleanup
Yuki Kimoto authored on 2011-01-25
291
    # Merge tag
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
292
    my $tag_processors = ref $_[0] eq 'HASH' ? $_[0] : {@_};
293
    $self->tag_processors({%{$self->tag_processors}, %{$tag_processors}});
294
    return $self;
295
}
296

            
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
297
1;
298

            
299
=head1 NAME
300

            
301
DBIx::Custom::QueryBuilder - Query builder
302

            
303
=head1 SYNOPSIS
304
    
305
    my $builder = DBIx::Custom::QueryBuilder->new;
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
306
    my $query = $builder->build_query(
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
307
        "select from table title = :title and author = :author"
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
308
    );
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
309

            
310
=head1 METHODS
311

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

            
315
=head2 C<build_query>
316
    
317
    my $query = $builder->build_query($source);
318

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

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