... | ... |
@@ -1,5 +1,9 @@ |
1 |
+0.1608 |
|
2 |
+ update document |
|
3 |
+ renamed DBIx::Custom::QueryBuilder::TagProcessors functions(not backword compatible) |
|
1 | 4 |
0.1607 |
2 |
- renamed build_query to create_query(not backword compatible) |
|
5 |
+ where argument of select() method can specify array(string, paramters) |
|
6 |
+ renamed build_query() to create_query()(not backword compatible) |
|
3 | 7 |
0.1606 |
4 | 8 |
fix testing bug |
5 | 9 |
0.1605 |
... | ... |
@@ -106,7 +106,7 @@ sub insert { |
106 | 106 |
|
107 | 107 |
# Templte for insert |
108 | 108 |
my $source = "insert into $table {insert " |
109 |
- . join(' ', @insert_keys) . '}'; |
|
109 |
+ . join(' ', @insert_keys) . '}'; |
|
110 | 110 |
$source .= " $append" if $append; |
111 | 111 |
|
112 | 112 |
# Execute query |
... | ... |
@@ -254,11 +254,10 @@ sub select { |
254 | 254 |
my $tables = $args{table} || []; |
255 | 255 |
$tables = [$tables] unless ref $tables eq 'ARRAY'; |
256 | 256 |
my $columns = $args{column} || []; |
257 |
- my $where = $args{where} || {}; |
|
257 |
+ my $where = $args{where}; |
|
258 | 258 |
my $relation = $args{relation}; |
259 | 259 |
my $append = $args{append}; |
260 | 260 |
my $filter = $args{filter}; |
261 |
- my $param = $args{param} || {}; |
|
262 | 261 |
|
263 | 262 |
# SQL template for select statement |
264 | 263 |
my $source = 'select '; |
... | ... |
@@ -282,18 +281,26 @@ sub select { |
282 | 281 |
$source =~ s/, $/ /; |
283 | 282 |
|
284 | 283 |
# Where clause |
285 |
- my @where_keys = keys %$where; |
|
286 |
- if (@where_keys) { |
|
287 |
- $source .= 'where '; |
|
288 |
- foreach my $where_key (@where_keys) { |
|
284 |
+ my $param; |
|
285 |
+ if (ref $where eq 'HASH') { |
|
286 |
+ $param = $where; |
|
287 |
+ $source .= 'where ('; |
|
288 |
+ foreach my $where_key (keys %$where) { |
|
289 | 289 |
$source .= "{= $where_key} and "; |
290 | 290 |
} |
291 |
+ $source =~ s/ and $//; |
|
292 |
+ $source .= ') '; |
|
293 |
+ } |
|
294 |
+ elsif (ref $where eq 'ARRAY') { |
|
295 |
+ my$where_str = $where->[0] || ''; |
|
296 |
+ $param = $where->[1]; |
|
297 |
+ |
|
298 |
+ $source .= "where ($where_str) "; |
|
291 | 299 |
} |
292 |
- $source =~ s/ and $//; |
|
293 | 300 |
|
294 | 301 |
# Relation |
295 | 302 |
if ($relation) { |
296 |
- $source .= @where_keys ? "and " : "where "; |
|
303 |
+ $source .= $where ? "and " : "where "; |
|
297 | 304 |
foreach my $rkey (keys %$relation) { |
298 | 305 |
$source .= "$rkey = " . $relation->{$rkey} . " and "; |
299 | 306 |
} |
... | ... |
@@ -304,8 +311,8 @@ sub select { |
304 | 311 |
$source .= " $append" if $append; |
305 | 312 |
|
306 | 313 |
# Execute query |
307 |
- my $result = $self->execute($source, param => $where, |
|
308 |
- filter => $filter); |
|
314 |
+ my $result = $self->execute($source, param => $param, |
|
315 |
+ filter => $filter); |
|
309 | 316 |
|
310 | 317 |
return $result; |
311 | 318 |
} |
... | ... |
@@ -345,7 +352,7 @@ sub create_query { |
345 | 352 |
|
346 | 353 |
# Prepare statement handle |
347 | 354 |
my $sth = eval {$self->dbh->prepare($query->{sql})}; |
348 |
- croak $@ if $@; |
|
355 |
+ croak qq{$@ SQL: "$query->{sql}"} if $@; |
|
349 | 356 |
|
350 | 357 |
# Set statement handle |
351 | 358 |
$query->sth($sth); |
... | ... |
@@ -450,7 +457,7 @@ DBIx::Custom - DBI interface, having hash parameter binding and filtering system |
450 | 457 |
|
451 | 458 |
=cut |
452 | 459 |
|
453 |
-our $VERSION = '0.1606'; |
|
460 |
+our $VERSION = '0.1608'; |
|
454 | 461 |
|
455 | 462 |
=head1 STABILITY |
456 | 463 |
|
... | ... |
@@ -573,9 +580,7 @@ so all people learing database system know it. |
573 | 580 |
If you know SQL statement, |
574 | 581 |
you learn a little thing about L<DBIx::Custom> to do your works. |
575 | 582 |
|
576 |
-=head2 2. Basic usage |
|
577 |
- |
|
578 |
-=head3 connect to the database |
|
583 |
+=head2 1. Connect to the database |
|
579 | 584 |
|
580 | 585 |
C<connect()> method create a new L<DBIx::Custom> |
581 | 586 |
object and connect to the database. |
... | ... |
@@ -584,17 +589,313 @@ object and connect to the database. |
584 | 589 |
my $dbi = DBIx::Custom->connect(data_source => "dbi:mysql:database=books", |
585 | 590 |
user => 'ken', password => '!LFKD%$&'); |
586 | 591 |
|
587 |
-=head3 Suger methods |
|
592 |
+If database is SQLite, use L<DBIx::Custom::SQLite>. you connect database easy way. |
|
593 |
+ |
|
594 |
+ use DBIx::Custom::SQLite; |
|
595 |
+ my $dbi = DBIx::Custom->connect(database => 'books'); |
|
596 |
+ |
|
597 |
+If database is MySQL, use L<DBIx::Costm::MySQL>. |
|
598 |
+ |
|
599 |
+ use DBIx::Custom::MySQL; |
|
600 |
+ my $dbi = DBIx::Custom->connect(database => 'books', |
|
601 |
+ user => 'ken', password => '!LFKD%$&'); |
|
602 |
+ |
|
603 |
+=head2 2. Suger methods |
|
588 | 604 |
|
589 | 605 |
L<DBIx::Custom> has suger methods, such as C<insert()>, C<update()>, |
590 | 606 |
C<delete()> and C<select()>. If you want to do simple works, |
591 | 607 |
You don't have to create SQL statement. |
592 | 608 |
|
593 |
-B<Execute insert statement:> |
|
609 |
+=head3 insert() |
|
610 |
+ |
|
611 |
+ $dbi->insert(table => 'books', |
|
612 |
+ param => {title => 'perl', author => 'Ken'}); |
|
613 |
+ |
|
614 |
+The following SQL is executed. |
|
615 |
+ |
|
616 |
+ insert into (title, author) values (?, ?) |
|
617 |
+ |
|
618 |
+The values of C<title> and C<author> is embedded into placeholders. |
|
619 |
+ |
|
620 |
+C<append> and C<filter> argument can be specified if you need. |
|
621 |
+ |
|
622 |
+=head3 update() |
|
623 |
+ |
|
624 |
+ $dbi->update(table => 'books', |
|
625 |
+ param => {title => 'aaa', author => 'Ken'}, |
|
626 |
+ where => {id => 5}); |
|
627 |
+ |
|
628 |
+The following SQL is executed. |
|
629 |
+ |
|
630 |
+ update books set title = ?, author = ?; |
|
631 |
+ |
|
632 |
+The values of C<title> and C<author> is embedded into placeholders. |
|
633 |
+ |
|
634 |
+If you want to update all rows, use C<update_all()> method instead. |
|
635 |
+ |
|
636 |
+C<append> and C<filter> argument can be specified if you need. |
|
637 |
+ |
|
638 |
+=head3 delete() |
|
639 |
+ |
|
640 |
+ $dbi->delete(table => 'books', |
|
641 |
+ where => {author => 'Ken'}); |
|
642 |
+ |
|
643 |
+The following SQL is executed. |
|
644 |
+ |
|
645 |
+ delete from books where id = ?; |
|
646 |
+ |
|
647 |
+The value of C<id> is embedded into a placehodler. |
|
648 |
+ |
|
649 |
+C<append> and C<filter> argument can be specified if you need. |
|
650 |
+ |
|
651 |
+If you want to delete all rows, use C<delete_all()> method instead. |
|
652 |
+ |
|
653 |
+=head3 select() |
|
654 |
+ |
|
655 |
+Specify only table: |
|
656 |
+ |
|
657 |
+ my $result = $dbi->select(table => 'books'); |
|
658 |
+ |
|
659 |
+The following SQL is executed. |
|
660 |
+ |
|
661 |
+ select * from books; |
|
662 |
+ |
|
663 |
+the result of C<select()> method is L<DBIx::Custom::Result> object. |
|
664 |
+use C<fetch()> method to fetch a row. |
|
665 |
+ |
|
666 |
+ while (my $row = $result->fetch) { |
|
667 |
+ my $title = $row->[0]; |
|
668 |
+ my $author = $row->[1]; |
|
669 |
+ } |
|
670 |
+ |
|
671 |
+L<DBIx::Custom::Result> has various methods to fetch row. |
|
672 |
+See "3. Result of select statement". |
|
673 |
+ |
|
674 |
+Specify C<column> and C<where> arguments: |
|
675 |
+ |
|
676 |
+ my $result = $dbi->select( |
|
677 |
+ table => 'books', |
|
678 |
+ column => [qw/author title/], |
|
679 |
+ where => {author => 'Ken'}); |
|
680 |
+ |
|
681 |
+The following SQL is executed. |
|
682 |
+ |
|
683 |
+ select author, title from books where author = ?; |
|
684 |
+ |
|
685 |
+the value of C<author> is embdded into placeholder. |
|
686 |
+ |
|
687 |
+If C<relation> argument is specifed, you can join tables. |
|
688 |
+ |
|
689 |
+ my $result = $dbi->select( |
|
690 |
+ table => ['books', 'rental'], |
|
691 |
+ column => ['books.name as book_name'] |
|
692 |
+ relation => {'books.id' => 'rental.book_id'} |
|
693 |
+ ); |
|
694 |
+ |
|
695 |
+The following SQL is executed. |
|
696 |
+ |
|
697 |
+ select books.name as book_name from books |
|
698 |
+ where books.id = rental.book_id; |
|
699 |
+ |
|
700 |
+C<append> argument add a string to the end of SQL statement. |
|
701 |
+It is useful to add "order by" or "limit" cluase. |
|
702 |
+ |
|
703 |
+ # Select, more complex |
|
704 |
+ my $result = $dbi->select( |
|
705 |
+ table => 'books', |
|
706 |
+ where => {author => 'Ken'}, |
|
707 |
+ append => 'order by price limit 5', |
|
708 |
+ ); |
|
709 |
+ |
|
710 |
+The following SQL is executed. |
|
711 |
+ |
|
712 |
+ select * books where author = ? order by price limit 5; |
|
713 |
+ |
|
714 |
+C<filter> argument can be specified if you need. |
|
715 |
+ |
|
716 |
+=head2 3. Result of select statement |
|
717 |
+ |
|
718 |
+C<select> method reurn L<DBIx::Custom::Result> object. |
|
719 |
+Using various methods, you can fetch row. |
|
720 |
+ |
|
721 |
+Fetch row into array. |
|
722 |
+ |
|
723 |
+ while (my $row = $result->fetch) { |
|
724 |
+ my $author = $row->[0]; |
|
725 |
+ my $title = $row->[1]; |
|
726 |
+ |
|
727 |
+ } |
|
728 |
+ |
|
729 |
+Fetch only a first row into array. |
|
594 | 730 |
|
731 |
+ my $row = $result->fetch_first; |
|
595 | 732 |
|
733 |
+Fetch multiple rows into array of array. |
|
596 | 734 |
|
735 |
+ while (my $rows = $result->fetch_multi(5)) { |
|
736 |
+ my $first_author = $rows->[0][0]; |
|
737 |
+ my $first_title = $rows->[0][1]; |
|
738 |
+ my $second_author = $rows->[1][0]; |
|
739 |
+ my $second_value = $rows->[1][1]; |
|
740 |
+ |
|
741 |
+ } |
|
742 |
+ |
|
743 |
+Fetch all rows into array of array. |
|
744 |
+ |
|
745 |
+ my $rows = $result->fetch_all; |
|
746 |
+ |
|
747 |
+Fetch row into hash. |
|
748 |
+ |
|
749 |
+ # Fetch a row into hash |
|
750 |
+ while (my $row = $result->fetch_hash) { |
|
751 |
+ my $title = $row->{title}; |
|
752 |
+ my $author = $row->{author}; |
|
753 |
+ |
|
754 |
+ } |
|
755 |
+ |
|
756 |
+Fetch only a first row into hash |
|
757 |
+ |
|
758 |
+ my $row = $result->fetch_hash_first; |
|
759 |
+ |
|
760 |
+Fetch multiple rows into array of hash |
|
761 |
+ |
|
762 |
+ while (my $rows = $result->fetch_hash_multi(5)) { |
|
763 |
+ my $first_title = $rows->[0]{title}; |
|
764 |
+ my $first_author = $rows->[0]{author}; |
|
765 |
+ my $second_title = $rows->[1]{title}; |
|
766 |
+ my $second_author = $rows->[1]{author}; |
|
767 |
+ |
|
768 |
+ } |
|
769 |
+ |
|
770 |
+Fetch all rows into array of hash |
|
771 |
+ |
|
772 |
+ my $rows = $result->fetch_hash_all; |
|
773 |
+ |
|
774 |
+If you want to access row statement handle of L<DBI>, use sth() attribute. |
|
775 |
+ |
|
776 |
+ my $sth = $result->sth; |
|
777 |
+ |
|
778 |
+=head2 4. Hash parameter binding |
|
779 |
+ |
|
780 |
+L<DBIx::Custom> provides hash parameter binding. |
|
781 |
+ |
|
782 |
+At frist, I show normal way of parameter binding. |
|
783 |
+ |
|
784 |
+ use DBI; |
|
785 |
+ my $dbh = DBI->connect(...); |
|
786 |
+ my $sth = $dbh->prepare( |
|
787 |
+ "select * from books where author = ? and title like ?;" |
|
788 |
+ ); |
|
789 |
+ $sth->execute('Ken', '%Perl%'); |
|
790 |
+ |
|
791 |
+This is very good way because database system enable SQL caching, |
|
792 |
+and parameter is quoted automatically. |
|
793 |
+ |
|
794 |
+L<DBIx::Custom>hash parameter binding system improve normal parameter binding to |
|
795 |
+specify hash parameter. |
|
796 |
+ |
|
797 |
+ my $result = $dbi->execute( |
|
798 |
+ "select * from books where {= author} and {like title};" |
|
799 |
+ param => {author => 'Ken', title => '%Perl%'} |
|
800 |
+ ); |
|
801 |
+ |
|
802 |
+This is same as the normal way, execpt that the parameter is hash. |
|
803 |
+{= author} is called C<tag>. tag is expand to placeholder internally. |
|
804 |
+ |
|
805 |
+ select * from books where {= author} and {like title} |
|
806 |
+ -> select * from books where author = ? and title like ?; |
|
807 |
+ |
|
808 |
+See L<DBIx::Custom::QueryBuilder> to know all tags. |
|
809 |
+ |
|
810 |
+=head2 5. Filtering |
|
811 |
+ |
|
812 |
+Usually, Perl string is kept as internal string. |
|
813 |
+If you want to save the string to database, You must encode the string. |
|
814 |
+Filtering system help you to convert a data to another data |
|
815 |
+when you save to the data and get the data form database. |
|
816 |
+ |
|
817 |
+If you want to register filter, use register_filter() method. |
|
818 |
+ |
|
819 |
+ $dbi->register_filter( |
|
820 |
+ to_upper_case => sub { |
|
821 |
+ my $value = shift; |
|
822 |
+ return uc $value; |
|
823 |
+ } |
|
824 |
+ ); |
|
825 |
+ |
|
826 |
+C<encode_utf8> and C<decode_utf8> filter is registerd by default. |
|
827 |
+ |
|
828 |
+You can specify these filters to C<filter> argument of C<execute()> method. |
|
597 | 829 |
|
830 |
+ my $result = $dbi->execute( |
|
831 |
+ "select * from books where {= author} and {like title};" |
|
832 |
+ param => {author => 'Ken', title => '%Perl%'}); |
|
833 |
+ filter => {author => 'to_upper_case, title => 'encode_utf8'} |
|
834 |
+ ); |
|
835 |
+ |
|
836 |
+you can also specify filter in suger methods, such as select(), update(), update_all, |
|
837 |
+delete(), delete_all(), select(). |
|
838 |
+ |
|
839 |
+ $dbi->insert(table => 'books', |
|
840 |
+ param => {title => 'perl', author => 'Ken'}, |
|
841 |
+ filter => {title => 'encode_utf8'}); |
|
842 |
+ |
|
843 |
+ my $result = $dbi->select( |
|
844 |
+ table => 'books', |
|
845 |
+ column => [qw/author title/], |
|
846 |
+ where => {author => 'Ken'}, |
|
847 |
+ append => 'order by id limit 1', |
|
848 |
+ filter => {title => 'encode_utf8'} |
|
849 |
+ ); |
|
850 |
+ |
|
851 |
+Filter work to each parmeter, but you prepare default filter for all parameters. |
|
852 |
+you can use C<default_bind_filter()> attribute. |
|
853 |
+ |
|
854 |
+ $dbi->default_bind_filter('encode_utf8'); |
|
855 |
+ |
|
856 |
+C<filter()> argument overwrites the filter specified by C<default_bind_filter()>. |
|
857 |
+ |
|
858 |
+ $dbi->default_bind_filter('encode_utf8'); |
|
859 |
+ $dbi->insert( |
|
860 |
+ table => 'books', |
|
861 |
+ param => {title => 'perl', author => 'Ken', price => 1000}, |
|
862 |
+ filter => {author => 'to_upper_case', price => undef} |
|
863 |
+ ); |
|
864 |
+ |
|
865 |
+This is same as the following one. |
|
866 |
+ |
|
867 |
+ $dbi->insert( |
|
868 |
+ table => 'books', |
|
869 |
+ param => {title => 'perl', author => 'Ken', price => 1000}, |
|
870 |
+ filter => {title => 'encode_uft8' author => 'to_upper_case'} |
|
871 |
+ ); |
|
872 |
+ |
|
873 |
+You can also specify filter when the row is fetching. This is reverse of bindig filter. |
|
874 |
+ |
|
875 |
+ my $result = $dbi->select(table => 'books'); |
|
876 |
+ $result->filter({title => 'decode_utf8', author => 'to_upper_case'}); |
|
877 |
+ |
|
878 |
+you can specify C<default_fetch_filter()>. |
|
879 |
+ |
|
880 |
+ $dbi->default_fetch_filter('decode_utf8'); |
|
881 |
+ |
|
882 |
+C<DBIx::Custom::Result::filter> overwrites the filter specified |
|
883 |
+by C<default_fetch_filter()> |
|
884 |
+ |
|
885 |
+ $dbi->default_fetch_filter('decode_utf8'); |
|
886 |
+ my $result = $dbi->select( |
|
887 |
+ table => 'books', |
|
888 |
+ columns => ['title', 'author', 'price'] |
|
889 |
+ ); |
|
890 |
+ $result->filter({author => 'to_upper_case', price => undef}); |
|
891 |
+ |
|
892 |
+This is same as the following one. |
|
893 |
+ |
|
894 |
+ my $result = $dbi->select( |
|
895 |
+ table => 'books', |
|
896 |
+ columns => ['title', 'author', 'price'] |
|
897 |
+ ); |
|
898 |
+ $result->filter({title => 'decode_utf8', author => 'to_upper_case'}); |
|
598 | 899 |
|
599 | 900 |
=head1 ATTRIBUTES |
600 | 901 |
|
... | ... |
@@ -11,17 +11,17 @@ use DBIx::Custom::QueryBuilder::TagProcessors; |
11 | 11 |
|
12 | 12 |
__PACKAGE__->dual_attr('tag_processors', default => sub { {} }, inherit => 'hash_copy'); |
13 | 13 |
__PACKAGE__->register_tag_processor( |
14 |
- '?' => \&DBIx::Custom::QueryBuilder::TagProcessors::placeholder, |
|
15 |
- '=' => \&DBIx::Custom::QueryBuilder::TagProcessors::equal, |
|
16 |
- '<>' => \&DBIx::Custom::QueryBuilder::TagProcessors::not_equal, |
|
17 |
- '>' => \&DBIx::Custom::QueryBuilder::TagProcessors::greater_than, |
|
18 |
- '<' => \&DBIx::Custom::QueryBuilder::TagProcessors::lower_than, |
|
19 |
- '>=' => \&DBIx::Custom::QueryBuilder::TagProcessors::greater_than_equal, |
|
20 |
- '<=' => \&DBIx::Custom::QueryBuilder::TagProcessors::lower_than_equal, |
|
21 |
- 'like' => \&DBIx::Custom::QueryBuilder::TagProcessors::like, |
|
22 |
- 'in' => \&DBIx::Custom::QueryBuilder::TagProcessors::in, |
|
23 |
- 'insert' => \&DBIx::Custom::QueryBuilder::TagProcessors::insert, |
|
24 |
- 'update' => \&DBIx::Custom::QueryBuilder::TagProcessors::update |
|
14 |
+ '?' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_placeholder_tag, |
|
15 |
+ '=' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_equal_tag, |
|
16 |
+ '<>' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_not_equal_tag, |
|
17 |
+ '>' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_greater_than_tag, |
|
18 |
+ '<' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_lower_than_tag, |
|
19 |
+ '>=' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_greater_than_equal_tag, |
|
20 |
+ '<=' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_lower_than_equal_tag, |
|
21 |
+ 'like' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_like_tag, |
|
22 |
+ 'in' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_in_tag, |
|
23 |
+ 'insert' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_insert_tag, |
|
24 |
+ 'update' => \&DBIx::Custom::QueryBuilder::TagProcessors::expand_update_tag |
|
25 | 25 |
); |
26 | 26 |
|
27 | 27 |
__PACKAGE__->attr(tag_start => '{'); |
... | ... |
@@ -267,19 +267,69 @@ See also L<DBIx::Custom::QueryBuilder::TagProcessors> to know tag processor. |
267 | 267 |
=head1 Tags |
268 | 268 |
|
269 | 269 |
The following tags is available. |
270 |
- |
|
271 |
- [Tags] [Replaced] |
|
270 |
+ |
|
271 |
+=head2 C<?> |
|
272 |
+ |
|
273 |
+Placeholder tag. |
|
274 |
+ |
|
272 | 275 |
{? NAME} -> ? |
276 |
+ |
|
277 |
+=head2 C<=> |
|
278 |
+ |
|
279 |
+Equal tag. |
|
280 |
+ |
|
273 | 281 |
{= NAME} -> NAME = ? |
282 |
+ |
|
283 |
+=head2 C<E<lt>E<gt>> |
|
284 |
+ |
|
285 |
+Not equal tag. |
|
286 |
+ |
|
274 | 287 |
{<> NAME} -> NAME <> ? |
275 |
- |
|
288 |
+ |
|
289 |
+=head2 C<E<lt>> |
|
290 |
+ |
|
291 |
+Lower than tag |
|
292 |
+ |
|
276 | 293 |
{< NAME} -> NAME < ? |
294 |
+ |
|
295 |
+=head2 C<E<gt>> |
|
296 |
+ |
|
297 |
+Greater than tag |
|
298 |
+ |
|
277 | 299 |
{> NAME} -> NAME > ? |
300 |
+ |
|
301 |
+=head2 C<E<gt>=> |
|
302 |
+ |
|
303 |
+Greater than or equal tag |
|
304 |
+ |
|
278 | 305 |
{>= NAME} -> NAME >= ? |
306 |
+ |
|
307 |
+=head2 C<E<lt>=> |
|
308 |
+ |
|
309 |
+Lower than or equal tag |
|
310 |
+ |
|
279 | 311 |
{<= NAME} -> NAME <= ? |
280 |
- |
|
281 |
- {like NAME} -> NAME like ? |
|
312 |
+ |
|
313 |
+=head2 C<like> |
|
314 |
+ |
|
315 |
+Like tag |
|
316 |
+ |
|
317 |
+ {like NAME} -> NAME like ? |
|
318 |
+ |
|
319 |
+=head2 C<in> |
|
320 |
+ |
|
321 |
+In tag. |
|
322 |
+ |
|
282 | 323 |
{in NAME COUNT} -> NAME in [?, ?, ..] |
283 |
- |
|
324 |
+ |
|
325 |
+=head2 C<insert> |
|
326 |
+ |
|
327 |
+Insert tag. |
|
328 |
+ |
|
284 | 329 |
{insert NAME1 NAME2} -> (NAME1, NAME2) values (?, ?) |
330 |
+ |
|
331 |
+=head2 C<update> |
|
332 |
+ |
|
333 |
+Updata tag. |
|
334 |
+ |
|
285 | 335 |
{update NAME1 NAME2} -> set NAME1 = ?, NAME2 = ? |
... | ... |
@@ -5,7 +5,7 @@ use warnings; |
5 | 5 |
|
6 | 6 |
use Carp 'croak'; |
7 | 7 |
|
8 |
-sub _basic { |
|
8 |
+sub _expand_basic_tag { |
|
9 | 9 |
my ($name, $column) = @_; |
10 | 10 |
|
11 | 11 |
# Check arguments |
... | ... |
@@ -15,15 +15,15 @@ sub _basic { |
15 | 15 |
return ["$column $name ?", [$column]]; |
16 | 16 |
} |
17 | 17 |
|
18 |
-sub equal { _basic('=', @_) } |
|
19 |
-sub not_equal { _basic('<>', @_) } |
|
20 |
-sub greater_than { _basic('>', @_) } |
|
21 |
-sub lower_than { _basic('<', @_) } |
|
22 |
-sub greater_than_equal { _basic('>=', @_) } |
|
23 |
-sub lower_than_equal { _basic('<=', @_) } |
|
24 |
-sub like { _basic('like', @_) } |
|
18 |
+sub expand_equal_tag { _expand_basic_tag('=', @_) } |
|
19 |
+sub expand_not_equal_tag { _expand_basic_tag('<>', @_) } |
|
20 |
+sub expand_greater_than_tag { _expand_basic_tag('>', @_) } |
|
21 |
+sub expand_lower_than_tag { _expand_basic_tag('<', @_) } |
|
22 |
+sub expand_greater_than_equal_tag { _expand_basic_tag('>=', @_) } |
|
23 |
+sub expand_lower_than_equal_tag { _expand_basic_tag('<=', @_) } |
|
24 |
+sub expand_like_tag { _expand_basic_tag('like', @_) } |
|
25 | 25 |
|
26 |
-sub placeholder { |
|
26 |
+sub expand_placeholder_tag { |
|
27 | 27 |
my $column = shift; |
28 | 28 |
|
29 | 29 |
# Check arguments |
... | ... |
@@ -33,7 +33,7 @@ sub placeholder { |
33 | 33 |
return ['?', [$column]]; |
34 | 34 |
} |
35 | 35 |
|
36 |
-sub in { |
|
36 |
+sub expand_in_tag { |
|
37 | 37 |
my ($column, $count) = @_; |
38 | 38 |
|
39 | 39 |
# Check arguments |
... | ... |
@@ -55,7 +55,7 @@ sub in { |
55 | 55 |
return [$s, $columns]; |
56 | 56 |
} |
57 | 57 |
|
58 |
-sub insert { |
|
58 |
+sub expand_insert_tag { |
|
59 | 59 |
my @columns = @_; |
60 | 60 |
|
61 | 61 |
# Part of insert statement |
... | ... |
@@ -71,7 +71,7 @@ sub insert { |
71 | 71 |
return [$s, \@columns]; |
72 | 72 |
} |
73 | 73 |
|
74 |
-sub update { |
|
74 |
+sub expand_update_tag { |
|
75 | 75 |
my @columns = @_; |
76 | 76 |
|
77 | 77 |
# Part of update statement |
... | ... |
@@ -112,48 +112,48 @@ same as the count of column names. |
112 | 112 |
return [$s, $columns]; |
113 | 113 |
} |
114 | 114 |
|
115 |
-=head2 C<placeholder> |
|
115 |
+=head2 C<expand_placeholder_tag> |
|
116 | 116 |
|
117 | 117 |
('NAME') -> ['?', ['NAME']] |
118 | 118 |
|
119 |
-=head2 C<equal> |
|
119 |
+=head2 C<expand_equal_tag> |
|
120 | 120 |
|
121 | 121 |
('NAME') -> ['NAME = ?', ['NAME']] |
122 | 122 |
|
123 |
-=head2 C<not_equal> |
|
123 |
+=head2 C<expand_not_equal_tag> |
|
124 | 124 |
|
125 | 125 |
('NAME') -> ['NAME <> ?', ['NAME']] |
126 | 126 |
|
127 |
-=head2 C<greater_than> |
|
127 |
+=head2 C<expand_greater_than_tag> |
|
128 | 128 |
|
129 | 129 |
('NAME') -> ['NAME > ?', ['NAME']] |
130 | 130 |
|
131 |
-=head2 C<lower_than> |
|
131 |
+=head2 C<expand_lower_than_tag> |
|
132 | 132 |
|
133 | 133 |
('NAME') -> ['NAME < ?', ['NAME']] |
134 | 134 |
|
135 |
-=head2 C<greater_than_equal> |
|
135 |
+=head2 C<expand_greater_than_equal_tag> |
|
136 | 136 |
|
137 | 137 |
('NAME') -> ['NAME >= ?', ['NAME']] |
138 | 138 |
|
139 |
-=head2 C<lower_than_equal> |
|
139 |
+=head2 C<expand_lower_than_equal_tag> |
|
140 | 140 |
|
141 | 141 |
('NAME') -> ['NAME <= ?', ['NAME']] |
142 | 142 |
|
143 |
-=head2 C<like> |
|
143 |
+=head2 C<expand_like_tag> |
|
144 | 144 |
|
145 | 145 |
('NAME') -> ['NAME like ?', ['NAME']] |
146 | 146 |
|
147 |
-=head2 C<in> |
|
147 |
+=head2 C<expand_in_tag> |
|
148 | 148 |
|
149 | 149 |
('NAME', 3) -> ['NAME in (?, ?, ?)', ['NAME', 'NAME', 'NAME']] |
150 | 150 |
|
151 |
-=head2 C<insert> |
|
151 |
+=head2 C<expand_insert_tag> |
|
152 | 152 |
|
153 | 153 |
('NAME1', 'NAME2') |
154 | 154 |
-> ['(NAME1, NAME2) values (?, ?, ?)', ['NAME1', 'NAME2']] |
155 | 155 |
|
156 |
-=head2 C<update> |
|
156 |
+=head2 C<expand_update_tag> |
|
157 | 157 |
|
158 | 158 |
('NAME1', 'NAME2') |
159 | 159 |
-> ['set NAME1 = ?, NAME2 = ?', ['NAME1', 'NAME2']] |
... | ... |
@@ -353,6 +353,9 @@ is_deeply($rows, [{key1 => 1}, {key1 => 3}], "$test : table and columns and wher |
353 | 353 |
$rows = $dbi->select(table => 'table1', where => {key1 => 1})->fetch_hash_all; |
354 | 354 |
is_deeply($rows, [{key1 => 1, key2 => 2}], "$test : table and columns and where key"); |
355 | 355 |
|
356 |
+$rows = $dbi->select(table => 'table1', where => ['{= key1} and {= key2}', {key1 => 1, key2 => 2}])->fetch_hash_all; |
|
357 |
+is_deeply($rows, [{key1 => 1, key2 => 2}], "$test : table and columns and where string"); |
|
358 |
+ |
|
356 | 359 |
$rows = $dbi->select(table => 'table1', column => ['key1'], where => {key1 => 3})->fetch_hash_all; |
357 | 360 |
is_deeply($rows, [{key1 => 3}], "$test : table and columns and where key"); |
358 | 361 |
|
... | ... |
@@ -1,154 +0,0 @@ |
1 |
-use strict; |
|
2 |
-use warnings; |
|
3 |
- |
|
4 |
-use Test::More 'no_plan'; |
|
5 |
- |
|
6 |
-use DBIx::Custom::SQLTemplate; |
|
7 |
- |
|
8 |
-# Function for test name |
|
9 |
-my $test; |
|
10 |
-sub test{ |
|
11 |
- $test = shift; |
|
12 |
-} |
|
13 |
- |
|
14 |
-# Variable for test |
|
15 |
-my $datas; |
|
16 |
-my $sql_tmpl; |
|
17 |
-my $query; |
|
18 |
-my $ret_val; |
|
19 |
- |
|
20 |
-test "Various template pattern"; |
|
21 |
-$datas = [ |
|
22 |
- # Basic tests |
|
23 |
- { name => 'placeholder basic', |
|
24 |
- tmpl => "a {? k1} b {= k2} {<> k3} {> k4} {< k5} {>= k6} {<= k7} {like k8}", , |
|
25 |
- sql_expected => "a ? b k2 = ? k3 <> ? k4 > ? k5 < ? k6 >= ? k7 <= ? k8 like ?;", |
|
26 |
- columns_expected => [qw/k1 k2 k3 k4 k5 k6 k7 k8/] |
|
27 |
- }, |
|
28 |
- { |
|
29 |
- name => 'placeholder in', |
|
30 |
- tmpl => "{in k1 3};", |
|
31 |
- sql_expected => "k1 in (?, ?, ?);", |
|
32 |
- columns_expected => [qw/k1 k1 k1/] |
|
33 |
- }, |
|
34 |
- |
|
35 |
- # Table name |
|
36 |
- { |
|
37 |
- name => 'placeholder with table name', |
|
38 |
- tmpl => "{= a.k1} {= a.k2}", |
|
39 |
- sql_expected => "a.k1 = ? a.k2 = ?;", |
|
40 |
- columns_expected => [qw/a.k1 a.k2/] |
|
41 |
- }, |
|
42 |
- { |
|
43 |
- name => 'placeholder in with table name', |
|
44 |
- tmpl => "{in a.k1 2} {in b.k2 2}", |
|
45 |
- sql_expected => "a.k1 in (?, ?) b.k2 in (?, ?);", |
|
46 |
- columns_expected => [qw/a.k1 a.k1 b.k2 b.k2/] |
|
47 |
- }, |
|
48 |
- { |
|
49 |
- name => 'not contain tag', |
|
50 |
- tmpl => "aaa", |
|
51 |
- sql_expected => "aaa;", |
|
52 |
- columns_expected => [], |
|
53 |
- } |
|
54 |
-]; |
|
55 |
- |
|
56 |
-for (my $i = 0; $i < @$datas; $i++) { |
|
57 |
- my $data = $datas->[$i]; |
|
58 |
- my $sql_tmpl = DBIx::Custom::SQLTemplate->new; |
|
59 |
- my $query = $sql_tmpl->create_query($data->{tmpl}); |
|
60 |
- is($query->{sql}, $data->{sql_expected}, "$test : $data->{name} : sql"); |
|
61 |
- is_deeply($query->{columns}, $data->{columns_expected}, "$test : $data->{name} : columns"); |
|
62 |
-} |
|
63 |
- |
|
64 |
- |
|
65 |
-test 'Original tag processor'; |
|
66 |
-$sql_tmpl = DBIx::Custom::SQLTemplate->new; |
|
67 |
- |
|
68 |
-$ret_val = $sql_tmpl->register_tag_processor( |
|
69 |
- p => sub { |
|
70 |
- my ($tag_name, $args) = @_; |
|
71 |
- |
|
72 |
- my $expand = "$tag_name ? $args->[0] $args->[1]"; |
|
73 |
- my $columns = [2]; |
|
74 |
- return ($expand, $columns); |
|
75 |
- } |
|
76 |
-); |
|
77 |
- |
|
78 |
-$query = $sql_tmpl->create_query("{p a b}"); |
|
79 |
-is($query->{sql}, "p ? a b;", "$test : register_tag_processor sql"); |
|
80 |
-is_deeply($query->{columns}, [2], "$test : register_tag_processor columns"); |
|
81 |
-isa_ok($ret_val, 'DBIx::Custom::SQLTemplate'); |
|
82 |
- |
|
83 |
- |
|
84 |
-test "Tag processor error case"; |
|
85 |
-$sql_tmpl = DBIx::Custom::SQLTemplate->new; |
|
86 |
- |
|
87 |
- |
|
88 |
-eval{$sql_tmpl->create_query("{a }")}; |
|
89 |
-like($@, qr/Tag '{a }' in SQL template is not exist/, "$test : tag_processor not exist"); |
|
90 |
- |
|
91 |
-$sql_tmpl->register_tag_processor({ |
|
92 |
- q => 'string' |
|
93 |
-}); |
|
94 |
- |
|
95 |
-eval{$sql_tmpl->create_query("{q}", {})}; |
|
96 |
-like($@, qr/Tag processor 'q' must be code reference/, "$test : tag_processor not code ref"); |
|
97 |
- |
|
98 |
-$sql_tmpl->register_tag_processor({ |
|
99 |
- r => sub {} |
|
100 |
-}); |
|
101 |
- |
|
102 |
-eval{$sql_tmpl->create_query("{r}")}; |
|
103 |
-like($@, qr/\QTag processor 'r' must return (\E\$expand\Q, \E\$columns\Q)/, "$test : tag processor return noting"); |
|
104 |
- |
|
105 |
-$sql_tmpl->register_tag_processor({ |
|
106 |
- s => sub { return ("a", "")} |
|
107 |
-}); |
|
108 |
- |
|
109 |
-eval{$sql_tmpl->create_query("{s}")}; |
|
110 |
-like($@, qr/\QTag processor 's' must return (\E\$expand\Q, \E\$columns\Q)/, "$test : tag processor return not array columns"); |
|
111 |
- |
|
112 |
-$sql_tmpl->register_tag_processor( |
|
113 |
- t => sub {return ("a", [])} |
|
114 |
-); |
|
115 |
- |
|
116 |
-eval{$sql_tmpl->create_query("{t ???}")}; |
|
117 |
-like($@, qr/Tag '{t }' arguments cannot contain '?'/, "$test : cannot contain '?' in tag argument"); |
|
118 |
- |
|
119 |
- |
|
120 |
-test 'General error case'; |
|
121 |
-$sql_tmpl = DBIx::Custom::SQLTemplate->new; |
|
122 |
-$sql_tmpl->register_tag_processor( |
|
123 |
- a => sub { |
|
124 |
- return ("? ? ?", [[],[]]); |
|
125 |
- } |
|
126 |
-); |
|
127 |
-eval{$sql_tmpl->create_query("{a}")}; |
|
128 |
-like($@, qr/Placeholder count in SQL created by tag processor 'a' must be same as key informations count/, "$test placeholder count is invalid"); |
|
129 |
- |
|
130 |
- |
|
131 |
-test 'Default tag processor Error case'; |
|
132 |
-eval{$sql_tmpl->create_query("{= }")}; |
|
133 |
-like($@, qr/You must be pass key as argument to tag '{= }'/, "$test : basic '=' : key not exist"); |
|
134 |
- |
|
135 |
-eval{$sql_tmpl->create_query("{in }")}; |
|
136 |
-like($@, qr/You must be pass key as first argument of tag '{in }'/, "$test : in : key not exist"); |
|
137 |
- |
|
138 |
-eval{$sql_tmpl->create_query("{in a}")}; |
|
139 |
-like($@, qr/\QYou must be pass value count as second argument of tag '{in }'\E\n\QUsage: {in \E\$key\Q \E\$count\Q}/, |
|
140 |
- "$test : in : key not exist"); |
|
141 |
- |
|
142 |
-eval{$sql_tmpl->create_query("{in a r}")}; |
|
143 |
-like($@, qr/\QYou must be pass value count as second argument of tag '{in }'\E\n\QUsage: {in \E\$key\Q \E\$count\Q}/, |
|
144 |
- "$test : in : key not exist"); |
|
145 |
- |
|
146 |
- |
|
147 |
-test 'Clone'; |
|
148 |
-$sql_tmpl = DBIx::Custom::SQLTemplate->new; |
|
149 |
-$sql_tmpl |
|
150 |
- ->tag_start('[') |
|
151 |
- ->tag_end(']') |
|
152 |
- ->tag_syntax('syntax') |
|
153 |
- ->tag_processors({a => 1, b => 2}); |
|
154 |
- |