--- nfo/perl/libs/Data/Storage/Handler/Tangram.pm 2003/03/27 15:31:14 1.30 +++ nfo/perl/libs/Data/Storage/Handler/Tangram.pm 2003/04/19 16:09:48 1.35 @@ -1,8 +1,24 @@ ############################################ # -# $Id: Tangram.pm,v 1.30 2003/03/27 15:31:14 joko Exp $ +# $Id: Tangram.pm,v 1.35 2003/04/19 16:09:48 jonen Exp $ # # $Log: Tangram.pm,v $ +# Revision 1.35 2003/04/19 16:09:48 jonen +# + added operator dispatching (currently for getting ref-type) at 'getListFiltered' +# +# Revision 1.34 2003/04/11 01:18:53 joko +# sendQuery: +# + introduced crud action 'DELETE' +# +# Revision 1.33 2003/04/09 06:07:43 joko +# revamped 'sub sendQuery' +# +# Revision 1.32 2003/04/08 22:52:22 joko +# modified 'querySchema': better behaviour regarding filtering result +# +# Revision 1.31 2003/04/05 21:24:09 joko +# modified 'sub getChildNodes': now contains code from 'querySchema' +# # Revision 1.30 2003/03/27 15:31:14 joko # fixes to modules regarding new namespace(s) below Data::Mungle::* # @@ -131,7 +147,7 @@ use DesignPattern::Object; use Data::Storage::Result::Tangram; use Data::Mungle::Compare::Struct qw( isEmpty ); -use Data::Mungle::Transform::Deep qw( expand ); +use Data::Mungle::Transform::Deep qw( expand deep_copy merge_to ); # get logger instance my $logger = Log::Dispatch::Config->instance; @@ -231,33 +247,64 @@ sub getChildNodes { my $self = shift; - my @nodes; + my $mode = shift; + my $filter = shift; + + $mode ||= 'core'; + $filter ||= 'all'; + + $logger->debug( __PACKAGE__ . "->getChildNodes($mode)" ); - $logger->debug( __PACKAGE__ . "->getChildNodes()" ); + if ($mode eq 'core') { - # create new DBI - Data::Storage - object from already connected DBI::db - handle inside the current COREHANDLE - #my $loc = new Data::Storage::Locator( type => "DBI", dbi => { db => $self->{COREHANDLE}->{db} }); - #my $loc = new Data::Storage::Locator( type => "DBI", COREHANDLE => $self->{COREHANDLE}->{db} ); - - # todo: should we retrieve information from the schema here - # rather than poorly getting table names from underlying dbi? - my $storage = $self->_getSubLayerHandle(); - @nodes = @{$storage->getChildNodes()}; - #$storage->_configureCOREHANDLE(); -#print "getchildnodes\n"; -#print Dumper($self); - #if (my $result = $self->sendCommand( 'SHOW TABLES;' ) ) { + my @nodes; + + # create new DBI - Data::Storage - object from already connected DBI::db - handle inside the current COREHANDLE + #my $loc = new Data::Storage::Locator( type => "DBI", dbi => { db => $self->{COREHANDLE}->{db} }); + #my $loc = new Data::Storage::Locator( type => "DBI", COREHANDLE => $self->{COREHANDLE}->{db} ); + + # todo: should we retrieve information from the schema here + # rather than poorly getting table names from underlying dbi? + my $storage = $self->_getSubLayerHandle(); + @nodes = @{$storage->getChildNodes()}; + #$storage->_configureCOREHANDLE(); + #print "getchildnodes\n"; + #print Dumper($self); + #if (my $result = $self->sendCommand( 'SHOW TABLES;' ) ) { + + # TODO: REVIEW + #$storage->disconnect(); + + $self->{meta}->{childnodes} = \@nodes; + + return \@nodes; - # TODO: REVIEW - #$storage->disconnect(); + } elsif ($mode eq 'root') { + + # FIXME: this will return *all* known classes to 'Class::Tangram', + # which might not be what you expect since more than one instance + # of Tangram may be in memory and Class::Tangram seems to + # offer no methods to determine this or filter its result(s) according + # to a specific database. + my @object_names = Class::Tangram::known_classes(); + my @concret_names; + my $o_cnt; + foreach (sort @object_names) { + push @concret_names, $_ if (!Class::Tangram::class_is_abstract($_)); + $o_cnt++; + } + + if ($filter eq 'all') { + return \@object_names; + } elsif ($filter eq 'concrete') { + return \@concret_names; + } - $self->{meta}->{childnodes} = \@nodes; + } - return \@nodes; } - sub testIntegrity { my $self = shift; @@ -462,8 +509,14 @@ # objects => $objects, # ); - # HACK: build eval-string (sorry) to get filtered list - please give advice here - push @tfilters, '$remote->{' . $filter->{key} . '}' . " $filter->{op} '$filter->{val}'"; + # TODO: is_op? + # dispatch un-common operators if exists + if($filter->{op} eq "ref") { + push @tfilters, 'ref($remote->{' . $filter->{key} . '})' . " eq '$filter->{val}'"; + } else { + # HACK: build eval-string (sorry) to get filtered list - please give advice here + push @tfilters, '$remote->{' . $filter->{key} . '}' . " $filter->{op} '$filter->{val}'"; + } } @@ -516,57 +569,157 @@ sub sendQuery { my $self = shift; my $query = shift; - #my $sql = "SELECT cs FROM $self->{metainfo}->{$descent}->{node} WHERE $self->{metainfo}->{$descent}->{IdentProvider}->{arg}='$self->{entry}->{source}->{ident}';"; - #my $result = $self->{metainfo}->{$descent}->{storage}->sendCommand($sql); #print Dumper($query); - # HACK: special case: querying by id does not translate into a common tangram query - # just load the object by given id(ent) - if ($query->{criterias}->[0]->{key} eq 'id' && $query->{criterias}->[0]->{op} eq 'eq') { - #print "LOAD!!!", "\n"; - #exit; - #return Set::Object->new( $self->{COREHANDLE}->load($query->{criterias}->[0]->{val}) ); - my $ident = $query->{criterias}->[0]->{val}; -#print "load obj", "\n"; - #return $self->createSet() if $ident == 5; - $self->{_COREHANDLE}->unload($ident); - my $object = $self->{_COREHANDLE}->load($ident); -#print "get id", "\n"; - my $oid = $self->{_COREHANDLE}->id($object); -#print Dumper($object); -#print "oid: $oid", "\n"; - return $self->createSet($object); - #return $self->createSet( $self->{COREHANDLE}->load('300090018') ); - } - - my $list = $self->getListFiltered($query->{node}, $query->{criterias}); - #return $self->createSet($object); - #return $self->createSet($list); - return $self->createSet(@$list); - - #die("This should not be reached for now - redirect to \$self->getListFiltered() here!"); + # type = ITEM|LIST|TRANSPARENT + my $type = ''; + # mode = OID|SPECIAL + my $mode = ''; + my $ident = ''; + my $crud = ''; + + + # dispatch type and mode + + # defaults - 1 + if ($query->{options}) { + $crud = $query->{options}->{crud}; + $crud ||= $query->{options}->{action}; + } + + # defaults - 2 + $type ||= 'TRANSPARENT'; + $crud ||= 'RETRIEVE'; + + if ($query->{options}->{OID}) { + $type = 'ITEM'; + $mode = 'OID'; + $ident = $query->{options}->{OID}; + + } elsif (my $guid = $query->{options}->{GUID}) { + $type = 'TRANSPARENT'; + $query->{criterias} = [ { key => 'guid', op => 'eq', val => $guid } ]; + + # if operator is different (dispatcher for 'getListFiltered') + } elsif (my $op = $query->{options}->{op}) { + $type = 'TRANSPARENT'; + $query->{criterias} = [ { key => $query->{options}->{meta_label}, op => $op, val => $query->{options}->{meta_value} } ]; + + } + + # HACK: special case: querying by id does not translate into a common tangram query + # just load the object by given identifier (OID) named 'id' - this is required by Data::Transfer::Sync! + if ($query->{criterias} && ($query->{criterias}->[0]->{key} eq 'id' && $query->{criterias}->[0]->{op} eq 'eq')) { + $type = 'ITEM'; + $mode = 'SPECIAL.SYNC'; + $ident = $query->{criterias}->[0]->{val}; + } + + + # execute query + my $result; + if ($type eq 'ITEM' && $ident) { + if ($mode eq 'OID') { + # TODO: review this case! + $result = $self->getObject($ident, $query->{options}); + + } elsif ($mode eq 'SPECIAL.SYNC') { + + # V1 - failed + #return Set::Object->new( $self->{COREHANDLE}->load($query->{criterias}->[0]->{val}) ); + + # hmm.... + #return $self->createSet() if $ident == 5; + + # Unload single object before doing any further operations to + # expect a "fresh" object from orm when performing the next calls. + $self->{_COREHANDLE}->unload($ident); + + # Load object from orm. + my $object = $self->{_COREHANDLE}->load($ident); + + # determine object identifier (OID) + my $oid = $self->{_COREHANDLE}->id($object); + + # encapsulate into result/response container and return this one + $result = $self->createSet($object); + + # debugging + #$result = $self->createSet( $self->{COREHANDLE}->load('300090018') ); + + } + + + } elsif ($type eq 'TRANSPARENT') { + if ($crud eq 'RETRIEVE') { + + my $list = $self->getListFiltered($query->{node}, $query->{criterias}); + #return $self->createSet($object); + #return $self->createSet($list); + return $self->createSet(@$list); + + #die("This should not be reached for now - redirect to \$self->getListFiltered() here!"); + + # try a generic tangram query here + # TODO: try to place an oql on top of that (search.cpan.org!) + my @crits; + foreach (@{$query->{criterias}}) { + my $op = ''; + $op = '=' if lc $_->{op} eq 'eq'; + push @crits, "$_->{key}$op'$_->{val}'"; + } + my $subnodes = {}; + map { $subnodes->{$_}++ } @{$query->{subnodes}}; + # HACK: this is hardcoded ;( expand possibilities! + #my $crit = join(' AND ', @crits); + #my $sql = hash2Sql($query->{node}, $subnodes, 'SELECT', $crit); + #return $self->sendCommand($sql); + #my $h = $self->{COREHANDLE}->remote($query->{node}); + #my $res = $self->{COREHANDLE}->select($h, $h->{); + $result = $self->createCursor($query->{node}); + + } elsif ($crud eq 'UPDATE') { + + # Patch current query to be a loader (e.g. change action, remove payload) ... + my $childquery = deep_copy($query); + $childquery->{options}->{crud} = 'RETRIEVE'; + delete $childquery->{payload}; + + # ... to use it to fetch a fresh object using ourselves (sendQuery). + my $cursor = $self->sendQuery($childquery); + my $status = $cursor->getStatus(); + my $object = $cursor->getNextEntry(); + + # Merge values and apply value modifiers. + my $options = { utf8 => 1, php => 1 }; + merge_to($object, $query->{payload}, $options); + + # Execute update operation at orm. + $self->update($object); + + } elsif ($crud eq 'DELETE') { + + # Patch current query to be a loader (e.g. change action) ... + my $childquery = deep_copy($query); + $childquery->{options}->{crud} = 'RETRIEVE'; + + # ... to use it to fetch a fresh object using ourselves (sendQuery). + my $cursor = $self->sendQuery($childquery); + my $status = $cursor->getStatus(); + my $object = $cursor->getNextEntry(); + + $self->erase($object); + + } + + } + + return $result; - # try a generic tangram query here - # TODO: try to place an oql on top of that (search.cpan.org!) - my @crits; - foreach (@{$query->{criterias}}) { - my $op = ''; - $op = '=' if lc $_->{op} eq 'eq'; - push @crits, "$_->{key}$op'$_->{val}'"; - } - my $subnodes = {}; - map { $subnodes->{$_}++ } @{$query->{subnodes}}; - # HACK: this is hardcoded ;( expand possibilities! - #my $crit = join(' AND ', @crits); - #my $sql = hash2Sql($query->{node}, $subnodes, 'SELECT', $crit); - #return $self->sendCommand($sql); - #my $h = $self->{COREHANDLE}->remote($query->{node}); - #my $res = $self->{COREHANDLE}->select($h, $h->{); - return $self->createCursor($query->{node}); } sub eraseAll { @@ -602,7 +755,7 @@ return $object if $object; } -sub getObjectByGuid { +sub getObjectByGuid_old { my $self = shift; my $guid = shift; my $options = shift; @@ -632,7 +785,7 @@ } -sub getObjectAsHash { +sub getObjectAsHash_old { my $self = shift; my $oid = shift; my $options = shift;