Class-AutoDB
view release on metacpan or search on metacpan
lib/Class/AutoDB/Database.pm view on Meta::CPAN
package Class::AutoDB::Database;
use vars qw(@ISA @AUTO_ATTRIBUTES @OTHER_ATTRIBUTES %SYNONYMS %DEFAULTS);
use strict;
use DBI;
use Class::AutoClass;
use Hash::AutoHash::Args;
use Class::AutoDB::Registry;
use Class::AutoDB::Cursor;
use Text::Abbrev;
@ISA = qw(Class::AutoClass);
# Mixin for Class::AutoDB. Handles database operations
@AUTO_ATTRIBUTES=qw(object_table
_exists);
@OTHER_ATTRIBUTES=qw();
%SYNONYMS=();
%DEFAULTS=(object_table=>'_AutoDB');
Class::AutoClass::declare(__PACKAGE__);
my $GLOBALS=Class::AutoDB::Globals->instance();
# TODO: this is copied from Table.pm. find a single place for this.
my %TYPES=(string =>'longtext',
integer =>'int',
float =>'double',
object =>'bigint unsigned',);
my @TYPES=keys %TYPES;
my %TYPES_ABBREV=abbrev @TYPES;
# TODO: deal with free-form queries
sub find {
my $self=shift;
my $query=$self->parse_query(@_);
my $cursor=new Class::AutoDB::Cursor(-query=>$query,-dbh=>$self->dbh);
$cursor;
}
sub get {
my $self=shift;
my $cursor=$self->find(@_);
$cursor->get;
}
sub count {
my $self=shift;
my $query=$self->parse_query(@_);
my $cursor=new Class::AutoDB::Cursor(-query=>$query,-dbh=>$self->dbh);
$cursor->count;
}
# NG 10-09-15: moved some code around to handle empty query and raw SQL
sub parse_query {
my $self=shift;
my $args=new Hash::AutoHash::Args(@_);
# NG 09-12-19: $autodb needed to remove $value->oid below
my $autodb=$GLOBALS->autodb;
my $dbh=$self->dbh;
my $object_table=$self->object_table;
my @from=($object_table); # always need_AutoDB
# NG 10-09-13: added 'IS NOT NULL' to handle deleted objects
my @where=qq($object_table.object IS NOT NULL);
# NG 10-09-15: added support for raw SQL
my $sql=$args->sql;
delete $args->{sql}; # so 'sql' will not be confused with a search key!
push(@where,"$object_table.oid IN ($sql)") if $sql;
my $limit; # may be set in 'then' below
if (%$args) {
my $name=$args->collection;
delete $args->{collection}; # so 'collection' will not be confused with a search key!
my $query=$args->query? $args->query: $args;
my $collection=$self->registry->collection($name) || $self->throw("Unknown collection $name");
my $keys=$collection->keys;
# NG 09-12-18: rewrote to avoid duplicates when selecting from list
# and to omit base table when keys are all lists
my(@base_where,@list_selects);
while(my($key,$value)=each %$query) { # create SQL condition for each search key
if ($key eq '_limit_') { # reserved keyword
$limit = $value;
next;
}
my $type=$keys->{$key} || $self->throw("Unknown key $key for collection $name");
if (($type eq 'object' || $type eq 'list(object)') && defined $value) {
# NG 09-12-19: $value->oid crashes on nonpersistent things.
# change also needed for cleanup of user-object namespace
# $value=$value->oid;
# $value=Class::AutoDB::Serialize::obj2oid($value)
# NG 09-12-22: handle repeated search terms for list(object)
if ('ARRAY' eq ref $value) {
$value=[map {Class::AutoDB::Serialize::obj2oid($_)} @$value];
} else {
$value=Class::AutoDB::Serialize::obj2oid($value)
}
}
my($db_type,$list_type,$table);
if ($type=~/^list/) {
# legal to have repeated search terms for list
my @values='ARRAY' eq ref $value? @$value: ($value);
($list_type)=$type=~/^list\s*\(\s*(.*)\s*\)/;
$db_type=$TYPES{$list_type};
for my $value (@values) {
$table=$name."_$key"; # list keys are stored in separate tables
my $list_select=qq(SELECT $table.oid FROM $table WHERE );
if (defined $value) {
$value=$dbh->quote($value,$db_type);
$list_select.="$table.$key=$value";
} else {
$list_select.="$table.$key IS NULL";
}
push(@list_selects,$list_select);
( run in 1.224 second using v1.01-cache-2.11-cpan-39bf76dae61 )