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

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

            
cleanup
Yuki Kimoto authored on 2011-01-25
284
# DEPRECATED!
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
285
sub register_tag_processor {
286
    my $self = shift;
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
287
    warn "register_tag_processor is DEPRECATED! use register_tag instead";
cleanup
Yuki Kimoto authored on 2011-01-25
288
    # Merge tag
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
289
    my $tag_processors = ref $_[0] eq 'HASH' ? $_[0] : {@_};
290
    $self->tag_processors({%{$self->tag_processors}, %{$tag_processors}});
291
    return $self;
292
}
293

            
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
294
1;
295

            
296
=head1 NAME
297

            
298
DBIx::Custom::QueryBuilder - Query builder
299

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

            
307
=head1 METHODS
308

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

            
312
=head2 C<build_query>
313
    
314
    my $query = $builder->build_query($source);
315

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

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