📄 aggregates.pm
字号:
# vim:ts=4 sw=4
# ----------------------------------------------------------------------------------------------------
# Name : ETL::Pequel3::Type::Aggregates.pm
# Created : 8 May 2006
# Author : Mario Gaffiero (gaffie)
#
# Copyright 1999-2007 Mario Gaffiero.
#
# This file is part of Pequel(TM).
#
# Pequel is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# Pequel is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Pequel; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# ----------------------------------------------------------------------------------------------------
# Modification History
# When Version Who What
# ----------------------------------------------------------------------------------------------------
package ETL::Pequel3::Type::Aggregates;
require 5.005_62;
use strict;
use warnings;
# ----------------------------------------------------------------------------------------------------
{
package ETL::Pequel3::Type::Aggregates::Abstract;
use base qw(Class::STL::Element);
use Class::STL::ClassMembers
qw(
name
err
properties
pequel_types
hash
configuration
use_list
output_field
requires_input_field
pequel_ref
xref
description
),
Class::STL::ClassMembers::DataMember->new(name => 'print_info', default => 1),
Class::STL::ClassMembers::DataMember->new(name => 'xs_type', default => 'NMTOKEN'),
Class::STL::ClassMembers::DataMember->new(name => 'valid_types', default => 'string'),
Class::STL::ClassMembers::DataMember->new(name => 'require_input_field', default => 1);
use Class::STL::ClassMembers::Constructor;
use Class::CodeStyler;
sub new_extra
{
my $self = shift;
$self->err(ETL::Pequel3::Error->new());
$self->configuration($self->pequel_ref()->config()) if (defined($self->pequel_ref()));
use ETL::Pequel3::Type::Properties;
$self->properties(ETL::Pequel3::Type::Properties->new());
use ETL::Pequel3::Type::PequelTypes;
$self->pequel_types(ETL::Pequel3::Type::PequelTypes::Catalogue->new());
$self->err()->user_error(10900, "Aggregate '@{[
$self->name() ]}' -- required attribute 'output_field' is undefined!")
if (!defined($self->output_field()));
$self->err()->user_error(10900, "Aggregate '@{[
$self->name()
]}' -- required attribute 'input_field' is undefined for output field '@{[
$self->output_field()->name()
]}'!")
if ($self->require_input_field() && !defined($self->output_field()->input_field()));
$self->hash(defined($self->configuration()) && $self->configuration()->hash() == 1 ? '{$_HKEY}' : '');
#TODO $self->hash($self->configuration()->hash() == 1 ? '{$@{[ $self->properties()->hkey_vname() ]}}' : '');
use ETL::Pequel3::Type::Dates;
use ETL::Pequel3::Type::FieldSet;
$self->use_list(ETL::Pequel3::Type::FieldSet::OutputFields->new());
$self->data($self->name());
use ETL::Pequel3::CrossRef;
$self->xref(ETL::Pequel3::CrossRef->new(
target_obj => $self,
target_name => $self->name(),
pequel_ref => $self->pequel_ref(),
@_,
));
return $self;
}
sub code_init
{
my $self = shift;
my $c = shift || ETL::CodeStyler::Program::Perl->new();
return $c;
}
sub code_reset
{
my $self = shift;
my $c = shift || Class::CodeStyler::Program::Perl->new();
return $c;
}
sub code_output_final
{
my $self = shift;
my $c = shift || Class::CodeStyler::Program::Perl->new();
return $c;
}
sub code_output
{
my $self = shift;
my $c = shift || Class::CodeStyler::Program::Perl->new();
return $c;
}
sub prinfo
{
my $self = shift;
return $self->print_info() ? "# ~@{[ $self->name() ]}(@{[ $self->output_field()->name() ]})" : '';
}
sub xml_schema
{
my $self = shift;
my $xsd = shift;
my $xml_node = shift || $xsd->schema_root();
return if ($xsd->exists('element', $self->name(), $xml_node));
$xsd->comment($xml_node, "Aggregate Type: @{[ $self->name() ]}");
my $element = $xsd->xs_element($xml_node, 'name' => $self->name());
if ($xsd->configuration()->xmlschema_annotation() && defined($self->description())
&& $self->description() ne '')
{
my $doc = $xsd->xs_documentation($xsd->xs_annotation($element), 'xml:lang' => 'en');
$xsd->text($doc, $self->description());
}
my $valid_types = $xsd->xs_element($xsd->xs_all($xsd->xs_complexType($element)),
'name', 'valid_types'
);
my $choice = $xsd->xs_choice($xsd->xs_complexType($valid_types));
foreach (split(/[|]/, $self->valid_types())) {
$xsd->xs_element($choice, 'name' => $_);
}
}
}
# ----------------------------------------------------------------------------------------------------
{
package ETL::Pequel3::Type::Aggregates::Sum;
use base qw(ETL::Pequel3::Type::Aggregates::Abstract);
use Class::STL::ClassMembers
Class::STL::ClassMembers::DataMember->new(name => 'name', default => 'sum'),
Class::STL::ClassMembers::DataMember->new(name => 'description', default => 'Accumulate the total for all values in the group.'),
Class::STL::ClassMembers::DataMember->new(name => 'valid_types', default => 'amount|numeric|date');
use Class::STL::ClassMembers::Constructor;
sub code_output
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
my $if = $self->output_field()->input_field()->getvar();
$c->code("@{[ $self->output_field()->getvar() ]} += $if");
$c->over();
$c->code("unless");
$c->open_block("(");
$c->code("!defined($if)");
$c->code("|| $if eq ''");
$c->close_block();
$c->code(";@{[ $self->prinfo() ]}"); #??? if ($self->properties()->no_nulls() == 1);
$c->back();
return $c;
}
}
# ----------------------------------------------------------------------------------------------------
{
package ETL::Pequel3::Type::Aggregates::SumDistinct;
use base qw(ETL::Pequel3::Type::Aggregates::Abstract);
use Class::STL::ClassMembers
Class::STL::ClassMembers::DataMember->new(name => 'name', default => 'sum_distinct'),
Class::STL::ClassMembers::DataMember->new(name => 'description', default => 'Accumulate the total for unique values for field-name in the group.'),
Class::STL::ClassMembers::DataMember->new(name => 'valid_types', default => 'amount|numeric|date');
use Class::STL::ClassMembers::Constructor;
sub code_init
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
$c->code("my \%SUM_DISTINCT_KEYS_@{[ $self->output_field()->name() ]}; @{[ $self->prinfo() ]}");
return $c;
}
sub code_reset
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
$c->code("\%SUM_DISTINCT_KEYS_@{[ $self->output_field()->name() ]} = (); @{[ $self->prinfo() ]}");
return $c;
}
sub code_output
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
my $of = "@{[ $self->output_field()->name() ]}@{[ $self->hash() ]}";
my $if = $self->output_field()->input_field()->getvar();
$c->code("@{[ $self->output_field()->getvar() ]} += $if");
$c->over();
$c->code("if");
$c->open_block("(");
$c->code("$if ne ''");
$c->code("&& ++\$SUM_DISTINCT_KEYS_$of\{qq{$if}} == 1");
$c->close_block();
$c->code(";@{[ $self->prinfo() ]}");
$c->back();
return $c;
}
}
# ----------------------------------------------------------------------------------------------------
{
package ETL::Pequel3::Type::Aggregates::ValuesUniq;
use base qw(ETL::Pequel3::Type::Aggregates::Abstract);
use Class::STL::ClassMembers
Class::STL::ClassMembers::DataMember->new(name => 'name', default => 'values_uniq'),
Class::STL::ClassMembers::DataMember->new(name => 'description', default => 'Output the list of unique values in the group.');
use Class::STL::ClassMembers::Constructor;
sub code_init
{
my $self = shift;
my $c = shift || ETL::CodeStyler::Program::Perl->new();
$c->code("my \%VALUES_UNIQ_@{[ $self->output_field()->name() ]};@{[ $self->prinfo() ]}");
return $c;
}
sub code_reset
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
$c->code("\%VALUES_UNIQ_@{[ $self->output_field()->name() ]} = ();@{[ $self->prinfo() ]}");
return $c;
}
sub code_output_final
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
my $of = "@{[ $self->output_field()->name() ]}@{[ $self->hash() ]}";
my $delim = $self->properties()->default_list_delimiter();
$c->code("@{[ $self->output_field()->getvar() ]} = ");
$c->over();
$c->code("join");
$c->open_block("(");
$c->code("qq{$delim},");
$c->newline_off();
$c->code("grep(length, sort keys ");
$self->hash() eq ''
? $c->code("\%VALUES_UNIQ_$of")
: $c->code("\%{\$VALUES_UNIQ_$of}"); # hash
$c->newline_on();
$c->code(")"); #grep
$c->close_block();
$c->code(";@{[ $self->prinfo() ]}");
$c->back();
return $c;
}
sub code_output
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
my $of = "@{[ $self->output_field()->name() ]}@{[ $self->hash() ]}";
my $if = $self->output_field()->input_field()->getvar();
my $delim = $self->properties()->default_list_delimiter();
if ($self->output_field()->input_field()->pequel_type()->name() eq 'array')
{
$c->code("map");
$c->open_block("(");
$c->code("\$VALUES_UNIQ_$of\{\$_}++,");
$c->code("split(/\\s*$delim\\s*/, $if)");
$c->close_block();
$c->code(";@{[ $self->prinfo() ]}");
}
else
{
$c->code("\$VALUES_UNIQ_$of\{qq{$if}}++;@{[ $self->prinfo() ]}");
}
return $c;
}
}
# ----------------------------------------------------------------------------------------------------
{
package ETL::Pequel3::Type::Aggregates::ValuesAll;
use base qw(ETL::Pequel3::Type::Aggregates::Abstract);
use Class::STL::ClassMembers
Class::STL::ClassMembers::DataMember->new(name => 'name', default => 'values_all'),
Class::STL::ClassMembers::DataMember->new(name => 'description', default => 'Output the list of all values in the group.');
use Class::STL::ClassMembers::Constructor;
sub code_init
{
my $self = shift;
my $c = shift || ETL::CodeStyler::Program::Perl->new();
$c->code("my @{[ $self->hash() eq '' ? '@' : '%' ]}VALUES_ALL_@{[
$self->output_field()->name() ]};@{[ $self->prinfo() ]}");
return $c;
}
sub code_reset
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
$c->code("@{[ $self->hash() eq '' ? '@' : '%' ]}VALUES_ALL_@{[
$self->output_field()->name() ]} = ();@{[ $self->prinfo() ]}");
return $c;
}
sub code_output_final
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
my $of = "@{[ $self->output_field()->name() ]}@{[ $self->hash() ]}";
my $delim = $self->properties()->default_list_delimiter();
$c->code("@{[ $self->output_field()->getvar() ]} = ");
$c->over();
$c->code("join");
$c->open_block("(");
$c->code("qq{$delim},");
$c->newline_off();
$c->code("grep(length, ");
$self->hash() eq ''
? $c->code("\@VALUES_ALL_$of")
: $c->code("\@{\$VALUES_ALL_$of}"); # hash
$c->newline_on();
$c->code(")"); #grep
$c->close_block();
$c->code(";@{[ $self->prinfo() ]}");
$c->back();
return $c;
}
sub code_output
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
my $of = "@{[ $self->output_field()->name() ]}@{[ $self->hash() ]}";
my $if = $self->output_field()->input_field()->getvar();
my $delim = $self->properties()->default_list_delimiter();
$c->code("push");
$c->open_block("(");
$c->code($self->hash() eq '' ? "\@VALUES_ALL_$of, " : "\@{\$VALUES_ALL_$of}, ");
$self->output_field()->input_field()->pequel_type()->name() eq 'array'
? $c->code("split(/\\s*$delim\\s*/, $if)")
: $c->code("qq{$if}");
$c->close_block();
$c->code(";@{[ $self->prinfo() ]}");
return $c;
}
}
# ----------------------------------------------------------------------------------------------------
{
package ETL::Pequel3::Type::Aggregates::Count;
use base qw(ETL::Pequel3::Type::Aggregates::Abstract);
use Class::STL::ClassMembers
Class::STL::ClassMembers::DataMember->new(name => 'name', default => 'count'),
Class::STL::ClassMembers::DataMember->new(name => 'description', default => 'Output the count of records in the group.');
use Class::STL::ClassMembers::Constructor;
sub code_output
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
my $if = $self->output_field()->input_field()->getvar();
$c->code("@{[ $self->output_field()->getvar() ]}++");
$c->over();
$c->code("if (defined($if));@{[ $self->prinfo() ]}");
$c->back();
return $c;
}
}
# ----------------------------------------------------------------------------------------------------
{
package ETL::Pequel3::Type::Aggregates::Distinct;
use base qw(ETL::Pequel3::Type::Aggregates::Abstract);
use Class::STL::ClassMembers
Class::STL::ClassMembers::DataMember->new(name => 'name', default => 'distinct'),
Class::STL::ClassMembers::DataMember->new(name => 'valid_types', default => 'amount|numeric');
use Class::STL::ClassMembers::Constructor;
sub code_init
{
my $self = shift;
my $c = shift || ETL::CodeStyler::Program::Perl->new();
$c->code("my \%DISTINCT_@{[ $self->output_field()->name() ]};@{[ $self->prinfo() ]}");
return $c;
}
sub code_reset
{
my $self = shift;
my $c = shift || ETL::Pequel3::CodeStyler::Program::Perl->new();
$c->code("\%DISTINCT_@{[ $self->output_field()->name() ]} = ();@{[ $self->prinfo() ]}");
return $c;
}
sub code_output
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -