DBIx-Custom / lib / DBIx / Custom / QueryBuilder.pm /
Newer Older
317 lines | 8.807kb
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!
added tag_parse attribute
Yuki Kimoto authored on 2011-06-28
22
    $self->{_tag_parse} = 1 unless defined $self->{_tag_parse};
23
    if ($self->{_tag_parse} && $source =~ /\{/ && $source =~ /\}/) {
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
24
        $query = $self->_parse_tag($source);
25
        my $tag_count = delete $query->{tag_count};
fixed DEPRECATED message bug
Yuki Kimoto authored on 2011-06-10
26
        warn qq/Tag system such as {? name} is DEPRECATED! / .
27
             qq/use parameter system such as :name instead/
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
28
          if $tag_count;
29
        my $query2 = $self->_parse_parameter($query->sql);
30
        $query->sql($query2->sql);
31
        for (my $i =0; $i < @{$query->columns}; $i++) {
32
            my $column = $query->columns->[$i];
33
            if ($column eq 'RESERVED_PARAMETER') {
34
                my $column2 = shift @{$query2->columns};
35
                croak ":name syntax is wrong"
36
                  unless defined $column2;
37
                $query->columns->[$i] = $column2;
38
            }
39
        }
40
    }
cleanup
yuki-kimoto authored on 2010-10-17
41
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
42
    # Parse parameter
added tag_parse attribute
Yuki Kimoto authored on 2011-06-28
43
    else { $query = $self->_parse_parameter($source) }
cleanup
yuki-kimoto authored on 2010-10-17
44
    
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
45
    my $sql = $query->sql;
46
    $sql .= ';' unless $source =~ /;$/;
47
    $query->sql($sql);
48

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

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

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

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

            
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
90
# DEPRECATED!
cleanup
Yuki Kimoto authored on 2011-06-13
91
has tags => sub { {} };
- update_param_tag is DEPREC...
Yuki Kimoto authored on 2011-06-07
92

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

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

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

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

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

            
295
=head1 NAME
296

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

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

            
306
=head1 METHODS
307

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

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

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

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