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

            
removed undocumented DBIx::C...
Yuki Kimoto authored on 2011-08-02
13
has 'dbi';
14

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

            
51
    # Create query
52
    bless {sql => $sql, columns => $columns}, 'DBIx::Custom::Query';
cleanup
yuki-kimoto authored on 2010-10-17
53
}
54

            
cleanup
Yuki Kimoto authored on 2011-10-24
55
# DEPRECATED!
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
56
sub _parse_parameter {
57
    my ($self, $source) = @_;
fixed named placeholder bug ...
Yuki Kimoto authored on 2011-08-01
58
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
59
    # Get and replace parameters
60
    my $sql = $source || '';
61
    my $columns = [];
removed undocumented DBIx::C...
Yuki Kimoto authored on 2011-08-02
62
    my $c = $self->dbi->safety_character;
cleanup
Yuki Kimoto authored on 2011-07-29
63
    # Parameter regex
fixed named placeholder bug ...
Yuki Kimoto authored on 2011-08-01
64
    $sql =~ s/([^:]):(\d+):([^:])/$1\\:$2\\:$3/g;
65
    my $re = qr/(^|.*?[^\\]):([$c\.]+)(?:\{(.*?)\})?(.*)/s;
cleanup
Yuki Kimoto authored on 2011-07-29
66
    while ($sql =~ /$re/g) {
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
67
        push @$columns, $2;
added EXPERIMENTAL parameter...
Yuki Kimoto authored on 2011-07-29
68
        $sql = defined $3 ? "$1$2 $3 ?$4" : "$1?$4";
cleanup
yuki-kimoto authored on 2010-10-17
69
    }
fixed named placeholder bug ...
Yuki Kimoto authored on 2011-08-01
70
    $sql =~ s/\\:/:/g;
cleanup
yuki-kimoto authored on 2010-10-17
71

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
72
    # Create query
add table tag
Yuki Kimoto authored on 2011-02-09
73
    my $query = DBIx::Custom::Query->new(
74
        sql => $sql,
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
75
        columns => $columns
add table tag
Yuki Kimoto authored on 2011-02-09
76
    );
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
77
    
78
    return $query;
79
}
fixed named placeholder bug ...
Yuki Kimoto authored on 2011-08-01
80
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
81
# DEPRECATED!
cleanup
Yuki Kimoto authored on 2011-06-13
82
has tags => sub { {} };
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
83

            
84
# DEPRECATED!
85
sub register_tag {
86
    my $self = shift;
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
87
    
added warnings
Yuki Kimoto authored on 2011-06-07
88
    warn "register_tag is DEPRECATED!";
89
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
90
    # Merge tag
91
    my $tags = ref $_[0] eq 'HASH' ? $_[0] : {@_};
92
    $self->tags({%{$self->tags}, %$tags});
93
    
94
    return $self;
95
}
96

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

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

            
cleanup
Yuki Kimoto authored on 2011-01-25
275
# DEPRECATED!
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
276
sub register_tag_processor {
277
    my $self = shift;
- added EXPERIMENTAL order m...
Yuki Kimoto authored on 2011-06-28
278
    warn "register_tag_processor is DEPRECATED!";
cleanup
Yuki Kimoto authored on 2011-01-25
279
    # Merge tag
renamed DBIx::Custom::TagPro...
Yuki Kimoto authored on 2011-01-24
280
    my $tag_processors = ref $_[0] eq 'HASH' ? $_[0] : {@_};
281
    $self->tag_processors({%{$self->tag_processors}, %{$tag_processors}});
282
    return $self;
283
}
284

            
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
285
1;
286

            
287
=head1 NAME
288

            
289
DBIx::Custom::QueryBuilder - Query builder
290

            
291
=head1 SYNOPSIS
292
    
293
    my $builder = DBIx::Custom::QueryBuilder->new;
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
294
    my $query = $builder->build_query(
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
295
        "select from table title = :title and author = :author"
remove DBIx::Custom::QueryBu...
yuki-kimoto authored on 2010-08-05
296
    );
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
297

            
cleanup
Yuki Kimoto authored on 2011-08-02
298
=head1 ATTRIBUTES
299

            
300
=head2 C<dbi>
301

            
302
    my $dbi = $builder->dbi;
303
    $builder = $builder->dbi($dbi);
304

            
305
L<DBIx::Custom> object.
306

            
renamed default_query_filter...
yuki-kimoto authored on 2010-08-03
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