| 3 | 
 #  $Id$ | 
 #  $Id$ | 
| 4 | 
 # | 
 # | 
| 5 | 
 #  $Log$ | 
 #  $Log$ | 
| 6 | 
  | 
 #  Revision 1.44  2003/12/04 01:01:50  joko | 
| 7 | 
  | 
 #  + sendQuery now returns result even on crud=UPDATE | 
| 8 | 
  | 
 # | 
| 9 | 
  | 
 #  Revision 1.43  2003/07/02 11:07:12  jonen | 
| 10 | 
  | 
 #  re-activate filtering of results *after* results are fetched from tangram | 
| 11 | 
  | 
 #    (needed for e.g. UserManagment) | 
| 12 | 
  | 
 # | 
| 13 | 
  | 
 #  Revision 1.42  2003/07/01 23:24:17  joko | 
| 14 | 
  | 
 #  now using package before using function | 
| 15 | 
  | 
 # | 
| 16 | 
  | 
 #  Revision 1.41  2003/06/29 02:03:45  joko | 
| 17 | 
  | 
 #  fix:? initialize schema on startup | 
| 18 | 
  | 
 # | 
| 19 | 
  | 
 #  Revision 1.40  2003/06/25 22:57:54  joko | 
| 20 | 
  | 
 #  major rework of "sub sendQuery / sub getListFiltered": now should be capable of "sorting" | 
| 21 | 
  | 
 # | 
| 22 | 
  | 
 #  Revision 1.39  2003/06/06 11:40:40  jonen | 
| 23 | 
  | 
 #  fixed bug at 'getFilteredList' | 
| 24 | 
  | 
 # | 
| 25 | 
  | 
 #  Revision 1.38  2003/05/13 16:38:38  joko | 
| 26 | 
  | 
 #  problems with "tied" on 5.6.1/win32 | 
| 27 | 
  | 
 # | 
| 28 | 
  | 
 #  Revision 1.37  2003/05/10 17:37:39  jonen | 
| 29 | 
  | 
 #  corrected last commit | 
| 30 | 
  | 
 # | 
| 31 | 
  | 
 #  Revision 1.36  2003/05/10 17:31:18  jonen | 
| 32 | 
  | 
 #  + added new functions related to 'create' item | 
| 33 | 
  | 
 #   - createNode() | 
| 34 | 
  | 
 #     # creates non-persistent 'deep dummy filled' object | 
| 35 | 
  | 
 #   - insertChildNode() | 
| 36 | 
  | 
 #     # inserts child node at given parent (child node haven't to exists, | 
| 37 | 
  | 
 #         createNode will be injected transparently) | 
| 38 | 
  | 
 # | 
| 39 | 
  | 
 #  Revision 1.35  2003/04/19 16:09:48  jonen | 
| 40 | 
  | 
 #  + added operator dispatching (currently for getting ref-type) at 'getListFiltered' | 
| 41 | 
  | 
 # | 
| 42 | 
  | 
 #  Revision 1.34  2003/04/11 01:18:53  joko | 
| 43 | 
  | 
 #  sendQuery: | 
| 44 | 
  | 
 #  + introduced crud action 'DELETE' | 
| 45 | 
  | 
 # | 
| 46 | 
  | 
 #  Revision 1.33  2003/04/09 06:07:43  joko | 
| 47 | 
  | 
 #  revamped 'sub sendQuery' | 
| 48 | 
  | 
 # | 
| 49 | 
  | 
 #  Revision 1.32  2003/04/08 22:52:22  joko | 
| 50 | 
  | 
 #  modified 'querySchema': better behaviour regarding filtering result | 
| 51 | 
  | 
 # | 
| 52 | 
 #  Revision 1.31  2003/04/05 21:24:09  joko | 
 #  Revision 1.31  2003/04/05 21:24:09  joko | 
| 53 | 
 #  modified 'sub getChildNodes': now contains code from 'querySchema' | 
 #  modified 'sub getChildNodes': now contains code from 'querySchema' | 
| 54 | 
 # | 
 # | 
| 176 | 
  | 
  | 
| 177 | 
 use Data::Dumper; | 
 use Data::Dumper; | 
| 178 | 
 use Tangram; | 
 use Tangram; | 
| 179 | 
  | 
 use Class::Tangram; | 
| 180 | 
  | 
  | 
| 181 | 
 use DesignPattern::Object; | 
 use DesignPattern::Object; | 
| 182 | 
 use Data::Storage::Result::Tangram; | 
 use Data::Storage::Result::Tangram; | 
| 183 | 
 use Data::Mungle::Compare::Struct qw( isEmpty ); | 
 use Data::Mungle::Compare::Struct qw( isEmpty ); | 
| 184 | 
 use Data::Mungle::Transform::Deep qw( expand ); | 
 use Data::Mungle::Transform::Deep qw( expand deep_copy merge_to ); | 
| 185 | 
  | 
  | 
| 186 | 
 # get logger instance | 
 # get logger instance | 
| 187 | 
 my $logger = Log::Dispatch::Config->instance; | 
 my $logger = Log::Dispatch::Config->instance; | 
| 188 | 
  | 
  | 
| 189 | 
  | 
 #$Tangram::TRACE = *STDOUT; | 
| 190 | 
  | 
  | 
| 191 | 
 # this holds the complete instantiated schema from tangram | 
 # this holds the complete instantiated schema from tangram | 
| 192 | 
 my $schema_tangram; | 
 my $schema_tangram; | 
| 205 | 
   #if (!$schema_tangram) { | 
   #if (!$schema_tangram) { | 
| 206 | 
     #my $obj = getNewPerlObjectByPkgName($self->{locator}->{schema}, { EXPORT_OBJECTS => $self->{locator}->{classnames}, want_transactions => $self->{locator}->{want_transactions} } ); | 
     #my $obj = getNewPerlObjectByPkgName($self->{locator}->{schema}, { EXPORT_OBJECTS => $self->{locator}->{classnames}, want_transactions => $self->{locator}->{want_transactions} } ); | 
| 207 | 
     my $obj = DesignPattern::Object->fromPackage($self->{locator}->{schema}, { 'EXPORT_OBJECTS' => $self->{locator}->{classnames}, 'want_transactions' => $self->{locator}->{want_transactions} } ); | 
     my $obj = DesignPattern::Object->fromPackage($self->{locator}->{schema}, { 'EXPORT_OBJECTS' => $self->{locator}->{classnames}, 'want_transactions' => $self->{locator}->{want_transactions} } ); | 
| 208 | 
     $schema_tangram = $obj->getSchema(); | 
     $schema_tangram = $obj->getSchema() if $obj; | 
| 209 | 
   #} | 
   #} | 
| 210 | 
   if (!$schema_tangram) { | 
   if (!$schema_tangram) { | 
| 211 | 
     $logger->error( __PACKAGE__ . "->_initSchema: No Schema available for $self->{schema}" ); | 
     $logger->error( __PACKAGE__ . "->_initSchema: No Schema available for $self->{locator}->{schema}." ); | 
| 212 | 
     return 0; | 
     return 0; | 
| 213 | 
   } | 
   } | 
| 214 | 
   #$self->_patchSchema(); | 
   #$self->_patchSchema(); | 
| 254 | 
 #      return; | 
 #      return; | 
| 255 | 
 #    } | 
 #    } | 
| 256 | 
  | 
  | 
| 257 | 
     #return unless $self->_initSchema(); | 
     return unless $self->_initSchema(); | 
| 258 | 
     $self->_initSchema(); | 
     #$self->_initSchema(); | 
| 259 | 
  | 
  | 
| 260 | 
     # create the main tangram storage object | 
     # create the main tangram storage object | 
| 261 | 
     #$self->{COREHANDLE} = Tangram::Relational->connect( $schema, $dsn ); | 
     #$self->{COREHANDLE} = Tangram::Relational->connect( $schema, $dsn ); | 
| 283 | 
  | 
  | 
| 284 | 
   my $self = shift; | 
   my $self = shift; | 
| 285 | 
   my $mode = shift; | 
   my $mode = shift; | 
| 286 | 
  | 
   my $filter = shift; | 
| 287 | 
  | 
    | 
| 288 | 
   $mode ||= 'core'; | 
   $mode ||= 'core'; | 
| 289 | 
  | 
   $filter ||= 'all'; | 
| 290 | 
    | 
    | 
| 291 | 
   $logger->debug( __PACKAGE__ . "->getChildNodes($mode)" ); | 
   $logger->debug( __PACKAGE__ . "->getChildNodes($mode)" ); | 
| 292 | 
  | 
  | 
| 328 | 
       push @concret_names, $_  if (!Class::Tangram::class_is_abstract($_)); | 
       push @concret_names, $_  if (!Class::Tangram::class_is_abstract($_)); | 
| 329 | 
       $o_cnt++; | 
       $o_cnt++; | 
| 330 | 
     } | 
     } | 
| 331 | 
    | 
  | 
| 332 | 
     my $result = { | 
     if ($filter eq 'all') { | 
| 333 | 
       all => \@object_names, | 
       return \@object_names; | 
| 334 | 
       concrete => \@concret_names, | 
     } elsif ($filter eq 'concrete') { | 
| 335 | 
     }; | 
       return \@concret_names; | 
| 336 | 
     return $result; | 
     } | 
| 337 | 
    | 
    | 
| 338 | 
   } | 
   } | 
| 339 | 
    | 
    | 
| 517 | 
   # redirect to unfiltered mode | 
   # redirect to unfiltered mode | 
| 518 | 
   #return $self->getListUnfiltered(@_); | 
   #return $self->getListUnfiltered(@_); | 
| 519 | 
  | 
  | 
| 520 | 
   my $nodename = shift; | 
   my $in = {}; | 
| 521 | 
   my $filters = shift; | 
   $in->{nodename} = shift; | 
| 522 | 
  | 
   $in->{filters} = shift; | 
| 523 | 
  | 
   $in->{sorting} = shift; | 
| 524 | 
  | 
    | 
| 525 | 
   my @results; | 
   my @results; | 
| 526 | 
   $logger->debug( __PACKAGE__ . "->getListFiltered( nodename => '" . $nodename . "' )" ); | 
   $logger->debug( __PACKAGE__ . "->getListFiltered( nodename => '" . $in->{nodename} . "' )" ); | 
| 527 | 
  | 
  | 
| 528 | 
  | 
   #print Dumper($filters); | 
| 529 | 
  | 
  | 
| 530 | 
 #print Dumper($filters); | 
   # 1. "Remote Object Handle" - get set of objects from odbms by object name | 
| 531 | 
  | 
   my $remote = $self->{_COREHANDLE}->remote($in->{nodename}); | 
| 532 | 
    | 
    | 
| 533 | 
  | 
   # 2. Transfer $in to $orm_query | 
| 534 | 
  | 
   my $orm_query = {}; | 
| 535 | 
  | 
    | 
| 536 | 
  | 
   # 2.a. Filters | 
| 537 | 
   my @tfilters; | 
   my @tfilters; | 
| 538 | 
  | 
   my $orm_filter = undef; | 
| 539 | 
    | 
    | 
| 540 | 
   foreach my $filter (@$filters) { | 
   foreach my $filter (@{$in->{filters}}) { | 
| 541 | 
    | 
    | 
| 542 | 
     # get filter - TODO: for each filter | 
     # get filter - TODO: for each filter | 
| 543 | 
     #my $filter = $filters->[0]; | 
     #my $filter = $filters->[0]; | 
| 544 | 
    | 
  | 
| 545 | 
     # build filter | 
     # 1. The parts of a filter source entry | 
| 546 | 
     my $lexpr = $filter->{key}; | 
     my $lexpr = $filter->{key}; | 
| 547 | 
     #my $op = $filter->{op}; | 
     #my $op = $filter->{op}; | 
| 548 | 
     my $op = '='; | 
     my $op = '='; | 
| 549 | 
     my $rexpr = $filter->{val}; | 
     my $rexpr = $filter->{val}; | 
| 550 | 
     my $tight = 100; | 
     my $tight = 100; | 
| 551 | 
  | 
  | 
| 552 | 
  | 
     # 2. Build filter target entry | 
| 553 | 
      | 
      | 
| 554 | 
   #  my $tfilter = Tangram::Filter->new( | 
     # Test 1 - didn't work out! | 
| 555 | 
   #    expr => "t1.$lexpr $op '$rexpr'", | 
     #  my $tfilter = Tangram::Filter->new( | 
| 556 | 
   #    tight => $tight, | 
     #    expr => "t1.$lexpr $op '$rexpr'", | 
| 557 | 
   #    objects => $objects, | 
     #    tight => $tight, | 
| 558 | 
   #  ); | 
     #    objects => $objects, | 
| 559 | 
    | 
     #  ); | 
| 560 | 
     # HACK: build eval-string (sorry) to get filtered list - please give advice here | 
  | 
| 561 | 
     push @tfilters, '$remote->{' . $filter->{key} . '}' . " $filter->{op} '$filter->{val}'"; | 
     my $orm_filter_tmp = undef; | 
| 562 | 
  | 
     # was: | 
| 563 | 
  | 
     # TODO: is_op? | 
| 564 | 
  | 
     # dispatch un-common operators if exists | 
| 565 | 
  | 
     if ($filter->{op} eq "ref") { | 
| 566 | 
  | 
       # do nothing, results will be filtered later cause 'tangram-filter' doesn't support 'ref' query | 
| 567 | 
  | 
       #print "Filter->op eq 'ref'.\n"; | 
| 568 | 
  | 
       #push @tfilters, 'ref($remote->{' . $filter->{key} . '})' . " eq '$filter->{val}'"; | 
| 569 | 
  | 
     } else { | 
| 570 | 
  | 
       # HACK: build eval-string (sorry) to get filtered list - please give advice here | 
| 571 | 
  | 
       #push @tfilters, '$remote->{' . $filter->{key} . '}' . " $filter->{op} '$filter->{val}'"; | 
| 572 | 
  | 
       # better: calculate expression right here! | 
| 573 | 
  | 
       #push @tfilters, '$remote->{' . $filter->{key} . '}' . " $filter->{op} '$filter->{val}'"; | 
| 574 | 
  | 
        | 
| 575 | 
  | 
       #print "key: ", $filter->{key}, "\n"; | 
| 576 | 
  | 
        | 
| 577 | 
  | 
       my $left = $remote->{$filter->{key}}; | 
| 578 | 
  | 
       #my $r = Tangram::Expr->new( 'string' => "'" . $filter->{val} . "'" ); | 
| 579 | 
  | 
       my $right = $filter->{val}; | 
| 580 | 
  | 
       my $op = $filter->{op}; | 
| 581 | 
  | 
       $orm_filter_tmp = $left->$op($right); | 
| 582 | 
  | 
     } | 
| 583 | 
  | 
  | 
| 584 | 
  | 
     if (not $orm_filter) { | 
| 585 | 
  | 
       $orm_filter = $orm_filter_tmp; | 
| 586 | 
  | 
     } else { | 
| 587 | 
  | 
       $orm_filter = $orm_filter->and($orm_filter_tmp); | 
| 588 | 
  | 
     } | 
| 589 | 
  | 
  | 
| 590 | 
   } | 
   } | 
| 591 | 
  | 
  | 
| 592 | 
   my $tfilter = join(' & ', @tfilters); | 
   $orm_query->{filter} = $orm_filter; | 
| 593 | 
  | 
  | 
 | 
   # get set of objects from odbms by object name | 
  | 
 | 
   my $remote = $self->{_COREHANDLE}->remote($nodename); | 
  | 
 | 
    | 
  | 
| 594 | 
   # was: | 
   # was: | 
| 595 | 
   #@results = $self->{COREHANDLE}->select($object_set, $tfilter); | 
  | 
| 596 | 
  | 
   # 2.b. sorting [new as of 2003-06-17] | 
| 597 | 
  | 
   if ($in->{sorting}) { | 
| 598 | 
  | 
     my $sorting_rules = []; | 
| 599 | 
  | 
     my $sorting_order = 'ASC'; | 
| 600 | 
  | 
     foreach my $sorting_column (keys %{$in->{sorting}}) { | 
| 601 | 
  | 
       $sorting_order = $in->{sorting}->{$sorting_column} if $in->{sorting}->{$sorting_column}; | 
| 602 | 
  | 
       push @$sorting_rules, Tangram::Expr->new( 'string' => $sorting_column ); | 
| 603 | 
  | 
     } | 
| 604 | 
  | 
     $orm_query->{order} = $sorting_rules; | 
| 605 | 
  | 
     if ($sorting_order eq 'DESC') { | 
| 606 | 
  | 
       $orm_query->{desc} = 1; | 
| 607 | 
  | 
     } | 
| 608 | 
  | 
   } | 
| 609 | 
  | 
  | 
| 610 | 
  | 
  | 
| 611 | 
  | 
   # 3. build and issue query - return result as Tangram::Cursor | 
| 612 | 
  | 
    | 
| 613 | 
  | 
   # coerce hash into array (This is valid in Perl) | 
| 614 | 
  | 
   my @orm_query_args = %$orm_query; | 
| 615 | 
  | 
   # send query (arguments) to orm | 
| 616 | 
  | 
   @results = $self->{_COREHANDLE}->select($remote, @orm_query_args); | 
| 617 | 
  | 
    | 
| 618 | 
  | 
   #my $cursor = $self->{_COREHANDLE}->cursor($remote, @orm_query_args); | 
| 619 | 
  | 
   #return $cursor; | 
| 620 | 
  | 
   #print Dumper(@results); | 
| 621 | 
  | 
  | 
| 622 | 
   # is: | 
   # is: | 
| 623 | 
   # HACK: build eval-string (sorry) to get filtered list - please give advice here | 
   # HACK: build eval-string (sorry) to get filtered list - please give advice here | 
| 624 | 
   my $evalstring = 'return $self->{_COREHANDLE}->select($remote, ' . $tfilter . ');'; | 
     #my $evalstring = 'return $self->{_COREHANDLE}->select($remote, ' . $tfilter . $sorting . ');'; | 
| 625 | 
    | 
     #print "eval: $evalstring", "\n"; | 
| 626 | 
   #print "eval: $evalstring", "\n"; | 
     # get filtered list/set | 
| 627 | 
    | 
     #@results = eval($evalstring); | 
| 628 | 
   # get filtered list/set | 
     #die $@ if $@; | 
| 629 | 
   @results = eval($evalstring); | 
  | 
| 630 | 
   die $@ if $@; | 
   # filter results - NEEDED for e.g. UserManagment !! | 
| 631 | 
  | 
   if ($in->{filters}->[0]->{op} && ($in->{filters}->[0]->{op} eq "ref")) { | 
| 632 | 
  | 
       #print "Filter->op eq 'ref'.\n"; | 
| 633 | 
  | 
       my $att_name = $in->{filters}->[0]->{key}; | 
| 634 | 
  | 
       my $att_val = $in->{filters}->[0]->{val}; | 
| 635 | 
  | 
       my @filtered; | 
| 636 | 
  | 
       foreach(@results) { | 
| 637 | 
  | 
         if(ref($_->{$att_name}) eq $att_val) { | 
| 638 | 
  | 
           push @filtered, $_; | 
| 639 | 
  | 
         } | 
| 640 | 
  | 
       } | 
| 641 | 
  | 
       @results = @filtered; | 
| 642 | 
  | 
   } | 
| 643 | 
  | 
  | 
| 644 | 
  | 
   #print "results: " . Dumper(\@results); | 
| 645 | 
    | 
    | 
| 646 | 
   return \@results; | 
   return \@results; | 
| 647 | 
 } | 
 } | 
| 671 | 
   return $result; | 
   return $result; | 
| 672 | 
 } | 
 } | 
| 673 | 
  | 
  | 
| 674 | 
  | 
 sub createResult { | 
| 675 | 
  | 
   my $self = shift; | 
| 676 | 
  | 
   my $rh = shift; | 
| 677 | 
  | 
   my $result = Data::Storage::Result::Tangram->new( RESULTHANDLE => $rh ); | 
| 678 | 
  | 
   return $result; | 
| 679 | 
  | 
 } | 
| 680 | 
  | 
  | 
| 681 | 
 sub sendQuery { | 
 sub sendQuery { | 
| 682 | 
   my $self = shift; | 
   my $self = shift; | 
| 683 | 
   my $query = 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); | 
  | 
| 684 | 
  | 
  | 
| 685 | 
   #print Dumper($query); | 
   #print Dumper($query); | 
| 686 | 
  | 
  | 
| 687 | 
   # HACK: special case: querying by id does not translate into a common tangram query | 
   # type = ITEM|LIST|TRANSPARENT | 
| 688 | 
   # just load the object by given id(ent) | 
   my $type = ''; | 
| 689 | 
   if ($query->{criterias}->[0]->{key} eq 'id' && $query->{criterias}->[0]->{op} eq 'eq') { | 
   # mode = OID|SPECIAL | 
| 690 | 
     #print "LOAD!!!", "\n"; | 
   my $mode = ''; | 
| 691 | 
     #exit; | 
   my $ident = ''; | 
| 692 | 
     #return Set::Object->new( $self->{COREHANDLE}->load($query->{criterias}->[0]->{val}) ); | 
   my $crud = ''; | 
| 693 | 
     my $ident = $query->{criterias}->[0]->{val}; | 
    | 
| 694 | 
 #print "load obj", "\n"; | 
    | 
| 695 | 
     #return $self->createSet() if $ident == 5; | 
   # dispatch type and mode | 
| 696 | 
     $self->{_COREHANDLE}->unload($ident); | 
    | 
| 697 | 
     my $object = $self->{_COREHANDLE}->load($ident); | 
     # defaults - 1 | 
| 698 | 
 #print "get id", "\n"; | 
     if ($query->{options}) { | 
| 699 | 
     my $oid = $self->{_COREHANDLE}->id($object); | 
       $crud = $query->{options}->{crud}; | 
| 700 | 
 #print Dumper($object); | 
       $crud ||= $query->{options}->{action}; | 
| 701 | 
 #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!"); | 
  | 
| 702 | 
  | 
  | 
| 703 | 
  | 
     # defaults - 2 | 
| 704 | 
  | 
     $type ||= 'TRANSPARENT';  | 
| 705 | 
  | 
     $crud ||= 'RETRIEVE'; | 
| 706 | 
  | 
  | 
| 707 | 
  | 
     if ($query->{options}->{OID}) { | 
| 708 | 
  | 
       $type = 'ITEM'; | 
| 709 | 
  | 
       $mode = 'OID'; | 
| 710 | 
  | 
       $ident = $query->{options}->{OID}; | 
| 711 | 
  | 
      | 
| 712 | 
  | 
     } elsif (my $guid = $query->{options}->{GUID}) { | 
| 713 | 
  | 
       $type = 'TRANSPARENT'; | 
| 714 | 
  | 
       $query->{criterias} = [ { key => 'guid', op => 'eq', val => $guid } ];     | 
| 715 | 
  | 
  | 
| 716 | 
  | 
     # if operator is different (dispatcher for 'getListFiltered') | 
| 717 | 
  | 
     } elsif (my $op = $query->{options}->{op}) { | 
| 718 | 
  | 
       $type = 'TRANSPARENT'; | 
| 719 | 
  | 
       $query->{criterias} = [ { key => $query->{options}->{meta_label}, op => $op, val => $query->{options}->{meta_value} } ];     | 
| 720 | 
  | 
  | 
| 721 | 
  | 
     } | 
| 722 | 
  | 
    | 
| 723 | 
  | 
     # HACK: special case: querying by id does not translate into a common tangram query | 
| 724 | 
  | 
     # just load the object by given identifier (OID) named 'id' - this is required by Data::Transfer::Sync! | 
| 725 | 
  | 
     if ($query->{criterias} && ($query->{criterias}->[0]->{key} eq 'id' && $query->{criterias}->[0]->{op} eq 'eq')) { | 
| 726 | 
  | 
       $type = 'ITEM'; | 
| 727 | 
  | 
       $mode = 'SPECIAL.SYNC'; | 
| 728 | 
  | 
       $ident = $query->{criterias}->[0]->{val}; | 
| 729 | 
  | 
     } | 
| 730 | 
  | 
    | 
| 731 | 
  | 
  | 
| 732 | 
  | 
   # execute query | 
| 733 | 
  | 
   my $result; | 
| 734 | 
  | 
  | 
| 735 | 
  | 
   if ($type eq 'ITEM' && $ident) { | 
| 736 | 
  | 
  | 
| 737 | 
  | 
     if ($mode eq 'OID') {     | 
| 738 | 
  | 
       # TODO: review this case! | 
| 739 | 
  | 
       $result = $self->getObject($ident, $query->{options}); | 
| 740 | 
  | 
      | 
| 741 | 
  | 
     } elsif ($mode eq 'SPECIAL.SYNC') { | 
| 742 | 
  | 
  | 
| 743 | 
  | 
       # V1 - failed | 
| 744 | 
  | 
       #return Set::Object->new( $self->{COREHANDLE}->load($query->{criterias}->[0]->{val}) ); | 
| 745 | 
  | 
    | 
| 746 | 
  | 
       # hmm.... | 
| 747 | 
  | 
       #return $self->createSet() if $ident == 5; | 
| 748 | 
  | 
        | 
| 749 | 
  | 
       # Unload single object before doing any further operations to  | 
| 750 | 
  | 
       # expect a "fresh" object from orm when performing the next calls. | 
| 751 | 
  | 
       $self->{_COREHANDLE}->unload($ident); | 
| 752 | 
  | 
        | 
| 753 | 
  | 
       # Load object from orm. | 
| 754 | 
  | 
       my $object = $self->{_COREHANDLE}->load($ident); | 
| 755 | 
  | 
    | 
| 756 | 
  | 
       # determine object identifier (OID) | 
| 757 | 
  | 
       my $oid = $self->{_COREHANDLE}->id($object); | 
| 758 | 
  | 
        | 
| 759 | 
  | 
       # encapsulate into result/response container and return this one | 
| 760 | 
  | 
       $result = $self->createSet($object); | 
| 761 | 
  | 
        | 
| 762 | 
  | 
       # debugging | 
| 763 | 
  | 
       #$result = $self->createSet( $self->{COREHANDLE}->load('300090018') ); | 
| 764 | 
  | 
  | 
| 765 | 
  | 
     } | 
| 766 | 
  | 
      | 
| 767 | 
  | 
    | 
| 768 | 
  | 
   } elsif ($type eq 'TRANSPARENT') { | 
| 769 | 
  | 
  | 
| 770 | 
  | 
     if ($crud eq 'RETRIEVE') { | 
| 771 | 
  | 
  | 
| 772 | 
  | 
       my $list = $self->getListFiltered($query->{node}, $query->{criterias}, $query->{sorting}); | 
| 773 | 
  | 
       #return $list; | 
| 774 | 
  | 
       return $self->createResult($list); | 
| 775 | 
  | 
        | 
| 776 | 
  | 
       #return $self->createSet($object); | 
| 777 | 
  | 
       #return $self->createSet($list); | 
| 778 | 
  | 
       return $self->createSet(@$list); | 
| 779 | 
  | 
      | 
| 780 | 
  | 
       #die("This should not be reached for now - redirect to \$self->getListFiltered() here!"); | 
| 781 | 
  | 
      | 
| 782 | 
  | 
       # try a generic tangram query here | 
| 783 | 
  | 
       # TODO: try to place an oql on top of that (search.cpan.org!) | 
| 784 | 
  | 
       my @crits; | 
| 785 | 
  | 
       foreach (@{$query->{criterias}}) { | 
| 786 | 
  | 
         my $op = ''; | 
| 787 | 
  | 
         $op = '=' if lc $_->{op} eq 'eq'; | 
| 788 | 
  | 
         push @crits, "$_->{key}$op'$_->{val}'"; | 
| 789 | 
  | 
       } | 
| 790 | 
  | 
       my $subnodes = {}; | 
| 791 | 
  | 
       map { $subnodes->{$_}++ } @{$query->{subnodes}}; | 
| 792 | 
  | 
       # HACK: this is hardcoded ;(    expand possibilities! | 
| 793 | 
  | 
       #my $crit = join(' AND ', @crits); | 
| 794 | 
  | 
       #my $sql = hash2Sql($query->{node}, $subnodes, 'SELECT', $crit); | 
| 795 | 
  | 
       #return $self->sendCommand($sql); | 
| 796 | 
  | 
       #my $h = $self->{COREHANDLE}->remote($query->{node}); | 
| 797 | 
  | 
       #my $res = $self->{COREHANDLE}->select($h, $h->{); | 
| 798 | 
  | 
       $result = $self->createCursor($query->{node}); | 
| 799 | 
  | 
  | 
| 800 | 
  | 
     } elsif ($crud eq 'UPDATE') { | 
| 801 | 
  | 
  | 
| 802 | 
  | 
       # Patch current query to be a loader (e.g. change action, remove payload) ... | 
| 803 | 
  | 
       my $childquery = deep_copy($query); | 
| 804 | 
  | 
       $childquery->{options}->{crud} = 'RETRIEVE'; | 
| 805 | 
  | 
       delete $childquery->{payload}; | 
| 806 | 
  | 
  | 
| 807 | 
  | 
       # ... to use it to fetch a fresh object using ourselves (sendQuery). | 
| 808 | 
  | 
       my $cursor = $self->sendQuery($childquery); | 
| 809 | 
  | 
       my $status = $cursor->getStatus(); | 
| 810 | 
  | 
       my $object = $cursor->getNextEntry(); | 
| 811 | 
  | 
  | 
| 812 | 
  | 
       # Merge values and apply value modifiers. | 
| 813 | 
  | 
       my $options = { utf8 => 1, php => 1 }; | 
| 814 | 
  | 
       merge_to($object, $query->{payload}, $options); | 
| 815 | 
  | 
  | 
| 816 | 
  | 
       #print Dumper($object); | 
| 817 | 
  | 
        | 
| 818 | 
  | 
       # Execute update operation at orm. | 
| 819 | 
  | 
       $self->update($object); | 
| 820 | 
  | 
       $result = $self->createResult([ $object ]); | 
| 821 | 
  | 
      | 
| 822 | 
  | 
     } elsif ($crud eq 'DELETE') { | 
| 823 | 
  | 
  | 
| 824 | 
  | 
       # Patch current query to be a loader (e.g. change action) ... | 
| 825 | 
  | 
       my $childquery = deep_copy($query); | 
| 826 | 
  | 
       $childquery->{options}->{crud} = 'RETRIEVE'; | 
| 827 | 
  | 
  | 
| 828 | 
  | 
       # ... to use it to fetch a fresh object using ourselves (sendQuery). | 
| 829 | 
  | 
       my $cursor = $self->sendQuery($childquery); | 
| 830 | 
  | 
       my $status = $cursor->getStatus(); | 
| 831 | 
  | 
       my $object = $cursor->getNextEntry(); | 
| 832 | 
  | 
  | 
| 833 | 
  | 
       $self->erase($object); | 
| 834 | 
  | 
  | 
| 835 | 
  | 
     } elsif ($crud eq 'CREATE') { | 
| 836 | 
  | 
        | 
| 837 | 
  | 
       my $nodename = $query->{node};       | 
| 838 | 
  | 
       my $newnode = $self->createNode($nodename); | 
| 839 | 
  | 
       my $id = $self->{_COREHANDLE}->insert($newnode); | 
| 840 | 
  | 
    | 
| 841 | 
  | 
       print "Saved new node $nodename with GUID $newnode->{guid}, OID '$id': " . Dumper($newnode) . "\n"; | 
| 842 | 
  | 
        | 
| 843 | 
  | 
       return $newnode; | 
| 844 | 
  | 
  | 
| 845 | 
  | 
     } | 
| 846 | 
  | 
  | 
| 847 | 
  | 
   } | 
| 848 | 
  | 
  | 
| 849 | 
  | 
   return $result; | 
| 850 | 
  | 
  | 
 | 
   # 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}); | 
  | 
| 851 | 
 } | 
 } | 
| 852 | 
  | 
  | 
| 853 | 
 sub eraseAll { | 
 sub eraseAll { | 
| 883 | 
   return $object if $object; | 
   return $object if $object; | 
| 884 | 
 } | 
 } | 
| 885 | 
  | 
  | 
| 886 | 
 sub getObjectByGuid { | 
 sub getObjectByGuid_old { | 
| 887 | 
   my $self = shift; | 
   my $self = shift; | 
| 888 | 
   my $guid = shift; | 
   my $guid = shift; | 
| 889 | 
   my $options = shift; | 
   my $options = shift; | 
| 913 | 
    | 
    | 
| 914 | 
 } | 
 } | 
| 915 | 
  | 
  | 
| 916 | 
 sub getObjectAsHash { | 
 sub getObjectAsHash_old { | 
| 917 | 
   my $self = shift; | 
   my $self = shift; | 
| 918 | 
   my $oid = shift; | 
   my $oid = shift; | 
| 919 | 
   my $options = shift;   | 
   my $options = shift;   | 
| 996 | 
   $self->{dataStorageLayer}->disconnect(); | 
   $self->{dataStorageLayer}->disconnect(); | 
| 997 | 
 } | 
 } | 
| 998 | 
  | 
  | 
| 999 | 
  | 
  | 
| 1000 | 
  | 
 sub createNode { | 
| 1001 | 
  | 
   my $self = shift; | 
| 1002 | 
  | 
   my $classname = shift; | 
| 1003 | 
  | 
  | 
| 1004 | 
  | 
   my $obj = $classname->new(); | 
| 1005 | 
  | 
    | 
| 1006 | 
  | 
   my $attr_options = Class::Tangram::attribute_options($classname); | 
| 1007 | 
  | 
   #print "Attribute Options: " . Dumper($attr_options); | 
| 1008 | 
  | 
  | 
| 1009 | 
  | 
   my $attr_types = Class::Tangram::attribute_types($classname); | 
| 1010 | 
  | 
   #print "Attribute Types: " . Dumper($attr_types); | 
| 1011 | 
  | 
    | 
| 1012 | 
  | 
   foreach(keys %{$attr_types}) { | 
| 1013 | 
  | 
     if($attr_types->{$_} eq 'string') { | 
| 1014 | 
  | 
       $obj->{$_} = ''; | 
| 1015 | 
  | 
     } elsif($attr_types->{$_} eq 'int') { | 
| 1016 | 
  | 
       $obj->{$_} = 0; | 
| 1017 | 
  | 
     } elsif($attr_types->{$_} eq 'real') { | 
| 1018 | 
  | 
       $obj->{$_} = 0; | 
| 1019 | 
  | 
     } elsif($attr_types->{$_} eq 'rawdatetime') { | 
| 1020 | 
  | 
       $obj->{$_} = '0000-00-00 00:00:00'; | 
| 1021 | 
  | 
     } elsif($attr_types->{$_} eq 'ref') { | 
| 1022 | 
  | 
       if($attr_options->{$_}->{class}) { | 
| 1023 | 
  | 
         $obj->{$_} = $self->createNode($attr_options->{$_}->{class}); | 
| 1024 | 
  | 
       } else { | 
| 1025 | 
  | 
         #$obj->{$_} = undef(); | 
| 1026 | 
  | 
       } | 
| 1027 | 
  | 
     } elsif($attr_types->{$_} eq 'iarray') { | 
| 1028 | 
  | 
         $obj->{$_} = [ ]; | 
| 1029 | 
  | 
     } elsif($attr_types->{$_} eq 'hash') { | 
| 1030 | 
  | 
         $obj->{$_} = {  }; | 
| 1031 | 
  | 
     } elsif($attr_types->{$_} eq 'flat_hash') { | 
| 1032 | 
  | 
         $obj->{$_} = { }; | 
| 1033 | 
  | 
     } | 
| 1034 | 
  | 
   } | 
| 1035 | 
  | 
    | 
| 1036 | 
  | 
   #print "New Object: " . Dumper($obj); | 
| 1037 | 
  | 
    | 
| 1038 | 
  | 
   return $obj; | 
| 1039 | 
  | 
 } | 
| 1040 | 
  | 
  | 
| 1041 | 
  | 
  | 
| 1042 | 
  | 
   sub insertChildNode { | 
| 1043 | 
  | 
     my $self = shift; | 
| 1044 | 
  | 
     my $child_entry = shift; | 
| 1045 | 
  | 
     my $query_args = shift; | 
| 1046 | 
  | 
      | 
| 1047 | 
  | 
     my $core = $self->{_COREHANDLE}; | 
| 1048 | 
  | 
     my $nodename = $query_args->{nodename}; | 
| 1049 | 
  | 
      | 
| 1050 | 
  | 
     # get parent object | 
| 1051 | 
  | 
     my $query = { | 
| 1052 | 
  | 
           node => $query_args->{parent}->{nodename}, | 
| 1053 | 
  | 
           options => { GUID => $query_args->{parent}->{guid}, }, | 
| 1054 | 
  | 
           }; | 
| 1055 | 
  | 
     my $cursor = $self->sendQuery($query); | 
| 1056 | 
  | 
     my $parent = $cursor->getNextEntry(); | 
| 1057 | 
  | 
  | 
| 1058 | 
  | 
     # debug | 
| 1059 | 
  | 
     #print "Parent_org: " . Dumper($parent); | 
| 1060 | 
  | 
          | 
| 1061 | 
  | 
     # Create child node object if isn't already done  | 
| 1062 | 
  | 
     # ($child_entry have to be the class name then...) | 
| 1063 | 
  | 
     if(!ref($child_entry)) { | 
| 1064 | 
  | 
       $child_entry = $self->createNode($child_entry); | 
| 1065 | 
  | 
       # it could be insert 'manually' or will be insert 'transparent' if parent will be updated | 
| 1066 | 
  | 
       #$core->insert($child_entry); | 
| 1067 | 
  | 
       #print "Create child object [$nodename]: " . Dumper($child_entry); | 
| 1068 | 
  | 
     } | 
| 1069 | 
  | 
  | 
| 1070 | 
  | 
     # get reference of tied node (seems, only on Linux node's are tied!!) | 
| 1071 | 
  | 
     my $tied_node = tied $parent->{$nodename}; | 
| 1072 | 
  | 
  | 
| 1073 | 
  | 
     # insert/change child entry at parent | 
| 1074 | 
  | 
     #print "reference: " . ref($parent->{$nodename}) . "\n"; | 
| 1075 | 
  | 
     if(ref($parent->{$nodename}) eq 'ARRAY') { | 
| 1076 | 
  | 
       # (seems, only on Linux node's are tied!!) | 
| 1077 | 
  | 
       if($tied_node) { | 
| 1078 | 
  | 
         # all tangram types are tied as 'SCALAR' with special 'FETCH', 'STORE' methods per type, | 
| 1079 | 
  | 
         # so a 'PUSH' is not implemented (which could be then done transparently) | 
| 1080 | 
  | 
         my $array = $tied_node->FETCH; | 
| 1081 | 
  | 
         push @$array, $child_entry; | 
| 1082 | 
  | 
         $tied_node->STORE($array); | 
| 1083 | 
  | 
         # node will be normaly untied at 'STORE' | 
| 1084 | 
  | 
         if(tied $parent->{$nodename}) { print "already tied !!\n"; } | 
| 1085 | 
  | 
         else { undef $tied_node; } | 
| 1086 | 
  | 
       } else { | 
| 1087 | 
  | 
         push @{$parent->{$nodename}}, $child_entry; | 
| 1088 | 
  | 
       } | 
| 1089 | 
  | 
     } | 
| 1090 | 
  | 
     elsif(ref($parent->{$nodename}) eq 'HASH') { | 
| 1091 | 
  | 
       if(my $key = $query_args->{hash_key}) { | 
| 1092 | 
  | 
         # (seems, only on Linux node's are tied!!) | 
| 1093 | 
  | 
         if($tied_node) { | 
| 1094 | 
  | 
           # same problem as with 'ARRAY': | 
| 1095 | 
  | 
           # all tangram types are tied as 'SCALAR' with special 'FETCH', 'STORE' methods per type. | 
| 1096 | 
  | 
           my $hash = $tied_node->FETCH; | 
| 1097 | 
  | 
           $hash->{$key} = $child_entry; | 
| 1098 | 
  | 
           $tied_node->STORE($hash);  | 
| 1099 | 
  | 
           # node will be normaly untied at 'STORE' | 
| 1100 | 
  | 
           if(tied $parent->{$nodename}) { print "already tied !!\n"; } | 
| 1101 | 
  | 
           else { undef $tied_node; } | 
| 1102 | 
  | 
         } else { | 
| 1103 | 
  | 
           $parent->{$nodename}->{$key} = $child_entry; | 
| 1104 | 
  | 
         } | 
| 1105 | 
  | 
       } else { | 
| 1106 | 
  | 
        print "ERROR: No HASH KEY given, so not able to insert hash entry!"; | 
| 1107 | 
  | 
       } | 
| 1108 | 
  | 
     }  | 
| 1109 | 
  | 
     else { | 
| 1110 | 
  | 
       $parent->{$nodename} = $child_entry; | 
| 1111 | 
  | 
     } | 
| 1112 | 
  | 
  | 
| 1113 | 
  | 
     # debug | 
| 1114 | 
  | 
     #print "Parent_new: " . Dumper($parent); | 
| 1115 | 
  | 
      | 
| 1116 | 
  | 
     # save parent | 
| 1117 | 
  | 
     $core->update($parent); | 
| 1118 | 
  | 
      | 
| 1119 | 
  | 
     # debug | 
| 1120 | 
  | 
     #print "Saved Parent: ". Dumper($parent); | 
| 1121 | 
  | 
      | 
| 1122 | 
  | 
     return $child_entry; | 
| 1123 | 
  | 
   } | 
| 1124 | 
  | 
  | 
| 1125 | 
  | 
  | 
| 1126 | 
 1; | 
 1; | 
| 1127 | 
 __END__ | 
 __END__ |