Aion-Query
view release on metacpan or search on metacpan
lib/Aion/Query.pm view on Meta::CPAN
my $msg = "$fn: " . (ref $query? np($query): $query);
push @DEBUG, $msg;
print STDERR $msg, "\n" if DEBUG;
}
# sub debug_html {
# join "", map { ("<p class='debug'>", to_html($_), "</p>\n") } @DEBUG;
# }
# sub debug_text {
# return "" if !@DEBUG;
# join "", map { "$_\n\n" } @DEBUG, "";
# }
# sub debug_array {
# return if !@DEBUG;
# $_[0]->{SQL_DEBUG} = \@DEBUG;
# return;
# }
sub LAST_INSERT_ID() {
$base->last_insert_id
}
# ÐÑеобÑазÑÐµÑ Ð² бинаÑнÑÑ ÑÑÑÐ¾ÐºÑ Ð¿ÑинÑÑÑÑ Ð² MYSQL
sub _to_hex_str($) {
my ($s) = @_;
no utf8;
use bytes;
$s =~ s/./sprintf "%02X", ord $&/gaes;
"X'$s'"
}
# ÐÐ´ÐµÑ Ð¿ÐµÑекодиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ñимволов:
# Рбазе иÑполÑзÑеÑÑÑ cp1251, поÑÑÐ¾Ð¼Ñ ÑимволÑ, коÑоÑÑе в Ð½ÐµÑ Ð½Ðµ вÑ
одÑÑ, нÑжно пеÑевеÑÑи в поÑледоваÑелÑноÑÑи.
# Ðид поÑледоваÑелÑноÑÑи: °ЧÐСÐÐ_Ð_254-ÑиÑной ÑиÑÑеме; \x7F
# Ðнак ° вÑбÑан поÑомÑ, ÑÑо он вÑÑе 127, ÑооÑвеÑÑÑвенно ÑÑÑока из Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ
, ÑодеÑжаÑÐ°Ñ ÑакÑÑ Ð¿Ð¾ÑледоваÑелÑноÑÑÑ,
# бÑÐ´ÐµÑ Ñ Ñлагом utf8, ÑÑо необÑ
одимо Ð´Ð»Ñ Ð¾Ð±ÑаÑного пеÑекодиÑованиÑ.
sub _recode_cp1251 {
my ($s) = @_;
return $s unless BQ;
$s =~ s/°|[^\Q$Aion::Format::CIF\E]/"°${\ to_radix(ord $&, 254) }\x7F"/ge;
$s
}
sub quote(;$);
sub quote(;$) {
my $k = @_ == 0? $_: $_[0];
my $ref;
!defined($k)? "NULL":
ref $k eq "ARRAY" && ref $k->[0] eq "ARRAY"?
join(", ", map { join "", "(", join(", ", map quote, @$_), ")" } @$k):
ref $k eq "ARRAY"? join("", join(", ", map quote, @$k)):
ref $k eq "HASH"?
join(", ", map { join "", $_, " = ", quote $k->{$_} } sort keys %$k):
ref $k eq "REF" && ref $$k eq "ARRAY"?
join(" ", List::Util::pairmap { join " ", "WHEN", quote $a, "THEN", quote $b } @$$k):
ref $k eq "SCALAR"? $$k:
Scalar::Util::blessed $k ? $k:
ref $k ne ""? die "Something strange: `$k`":
$k =~ /^-?(?:0|[1-9]\d*)(\.\d+)?\z/a
&& ($ref = ref B::svref_2object(@_ == 0? \$_: \$_[0])
) ne "B::PV"? (
!$1 && $ref eq "B::NV"? "$k.0": $k
):
!utf8::is_utf8($k)? (
$k =~ /[^\t\n -~]/a ? _to_hex_str($k): #$base->quote($k, DBI::SQL_BINARY):
Aion::Format::to_str($k)
):
Aion::Format::to_str(_recode_cp1251($k))
}
sub _set_type {
my ($type, $x) = @_;
if(ref $x eq "ARRAY") {
[map _set_type($type, $_), @$x]
}
elsif(ref $x eq "HASH") {
+{ map ($_ => _set_type($type, $type->{$_})), keys %$x }
}
elsif(ref $type eq "SCALAR") {
\_set_type($type, $$x);
}
elsif($type eq "^") {
int $x
}
elsif($type eq "~") {
"$x"
}
elsif($type eq ".") {
$x+1.e-100
}
else {
die "_set_type($type): type does not exist"
}
}
sub _set_params {
my ($query, $param) = @_;
$query =~ s!:([~\.^])?([a-z_]\w*)!
exists $param->{$2}? do {
my $x = $param->{$2};
defined $1 ? quote _set_type($1, $x): quote $x
}: die "The :$1 parameter was not passed."!ige;
$query
}
# ÐÐµÐ»Ð°ÐµÑ Ð¿Ð¾Ð´ÑÑановки
sub query_prepare (@) {
my ($query, %param) = @_;
$query =~ s!
^(?<sep>[\ \t]*) (?<if>\w+)>> [\ \t]* (?<code>.*)
| ^(?<sep>[\ \t]*) (?<for>\w+)\*>> [\ \t]* (?<code>.*)
| (?<param> : [~\.^]? [a-z_]\w*)
!
exists $+{if}? ($param{$+{if}}? $+{sep} . _set_params($+{code}, \%param): ""):
exists $+{for}? do {
lib/Aion/Query.pm view on Meta::CPAN
if($ignore) {
my $query = "INSERT INTO $tab ($fields) VALUES $values ON CONFLICT DO NOTHING";
query_do($query);
} else {
my $fupdate = join ", ", map "$_ = excluded.$_", @keys;
my $query = "INSERT INTO $tab ($fields) VALUES $values ON CONFLICT DO UPDATE SET $fupdate";
query_do($query);
}
}
else {
my $count = 0;
if($ignore) {
$count += eval { stores $tab, [$_], insert => 1 } for @$rows;
} else {
$count += stores $tab, [$_] for @$rows;
}
$count
}
}
# ÑоÑ
ÑанÑÐµÑ Ð´Ð°Ð½Ð½Ñе (update или insert)
#
# store "tab", word=>123;
#
sub store (@) {
my $tab = shift;
stores $tab, [+{@_}];
}
# СвеÑÑ
моÑÐ½Ð°Ñ ÑÑнкÑиÑ: возвÑаÑÐ°ÐµÑ pk, а еÑли его Ð½ÐµÑ - ÑоздаÑÑ Ð¸Ð»Ð¸ обновлÑÐµÑ Ð·Ð°Ð¿Ð¸ÑÑ Ð¸ вÑÑ Ñавно возвÑаÑаеÑ
sub touch(@) {
my $sub;
$sub = pop @_ if ref $_[$#_] eq "CODE";
my $pk = query_id @_;
return $pk if defined $pk;
store @_, $sub? $sub->(): ();
query_id @_
}
# возвÑаÑÐ°ÐµÑ Ð¿ÐµÑеменнÑÑ, на коÑоÑой нÑжно ÑÑÑановиÑÑ commit, инаÑе пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¾ÑкаÑ
sub START_TRANSACTION () {
package Aion::Query::Transaction {
sub commit {
my ($self) = @_;
$Aion::Query::base->commit;
$self->{commit} = 1;
return $self;
}
sub DESTROY {
my ($self) = @_;
$Aion::Query::base->rollback unless $self->{commit};
}
}
$Aion::Query::base->begin_work;
bless {}, 'Aion::Query::Transaction';
}
1;
__END__
=encoding utf-8
=head1 NAME
Aion::Query - a functional interface for accessing SQL databases (MySQL, MariaDB, Postgres and SQLite)
=head1 VERSION
0.0.6
=head1 SYNOPSIS
File .config.pm:
package config;
config_module Aion::Query => {
DRV => "SQLite",
BASE => "test-base.sqlite",
BQ => 0,
};
1;
use Aion::Query;
query "CREATE TABLE author (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE
)";
insert "author", name => "Pushkin A.S." # -> 1
touch "author", name => "Pushkin A." # -> 2
touch "author", name => "Pushkin A.S." # -> 1
touch "author", name => "Pushkin A." # -> 2
query_scalar "SELECT count(*) FROM author" # -> 2
my @rows = query "SELECT *
FROM author
WHERE 1
if_name>> AND name like :name
",
if_name => Aion::Query::BQ == 0,
name => "P%",
;
\@rows # --> [{id => 1, name => "Pushkin A.S."}, {id => 2, name => "Pushkin A."}]
$Aion::Query::DEBUG[1] # => query: INSERT INTO author (name) VALUES ('Pushkin A.S.')
( run in 1.459 second using v1.01-cache-2.11-cpan-39bf76dae61 )