You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcp-panel/lib/NGCP/Panel/Utils/RedisLocationResultSet.pm

228 lines
6.6 KiB

package NGCP::Panel::Utils::RedisLocationResultSet;
use Moose;
use TryCatch;
use NGCP::Panel::Utils::RedisLocationResultSource;
use Data::Dumper;
has _c => (
is => 'ro',
isa => 'NGCP::Panel',
);
has _redis => (
is => 'ro',
isa => 'Redis',
);
has _rows => (
is => 'rw',
isa => 'ArrayRef',
default => sub {[]}
);
has _query_done => (
is => 'rw',
isa => 'Int',
default => 0,
);
has _domain_resellers => (
is => 'rw',
isa => 'HashRef',
lazy => 1,
default => sub {
my $self = shift;
my $h = {};
my $domres_rs = $self->_c->model('DB')->resultset('domain_resellers')->search(undef, {
join => 'domain'
});
while ((my $res = $domres_rs->next)) {
$h->{$res->domain->domain} = $res->reseller_id;
}
return $h;
},
);
sub count {
my ($self) = @_;
my $count = @{ $self->_rows };
return $count;
}
sub first {
my ($self) = @_;
return $self->_rows->[0];
}
sub all {
my ($self) = @_;
return @{ $self->_rows };
}
sub find {
my ($self, $filter) = @_;
my $id;
if (ref $filter eq "") {
$id = $filter;
$filter = { id => $id };
} elsif(ref $filter eq "HASH" && exists $filter->{id}) {
$id = $filter->{id};
} else {
$self->_c->log->error("id filter is mandatory for redis find()");
return;
}
my %entry = $self->_redis->hgetall("location:entry::$id");
$entry{id} = $entry{ruid};
if (exists $filter->{reseller_id} && $filter->{reseller_id} != $self->_domain_resellers->{$entry{domain}}) {
return;
}
return NGCP::Panel::Utils::RedisLocationResultSource->new(_data => \%entry);
}
sub search {
my ($self, $filter, $opt) = @_;
$filter //= {};
my $new_rs = $self->meta->clone_object($self);
unless ($new_rs->_query_done) {
if ($filter->{id}) {
push @{ $new_rs->_rows }, $new_rs->find($filter);
} elsif ($filter->{username} && $filter->{domain}) {
push @{ $new_rs->_rows },
@{ $new_rs->_rows_from_mapkey("location:usrdom::" .
$filter->{username} . ":" . $filter->{domain}, $filter) };
} else {
$new_rs->_scan($filter);
}
$new_rs->_query_done(1);
}
$new_rs->_filter($filter);
if ($opt->{order_by}->{'-desc'}) {
my $f = $opt->{order_by}->{'-desc'};
$f =~ s/^me\.//;
$new_rs->_rows([sort { $b->$f cmp $a->$f } @{ $new_rs->_rows }]);
} elsif ($opt->{order_by}->{'-asc'} || ref $opt->{order_by} eq "") {
my $f = $opt->{order_by}->{'-asc'} // $opt->{order_by};
$f =~ s/^me\.//;
$new_rs->_rows([sort { $a->$f cmp $b->$f } @{ $new_rs->_rows }]);
}
$opt->{rows} //= -1;
$opt->{offset} //= 0;
if (!defined $opt->{page} && $opt->{rows} > -1 || $opt->{offset} > 0) {
$new_rs->_rows([ splice @{ $new_rs->_rows }, $opt->{offset}, $opt->{rows} ]);
}
if (defined $opt->{page} && $opt->{rows} > 0) {
$new_rs->_rows([ splice(@{ $new_rs->_rows }, ($opt->{page} - 1 )*$opt->{rows}, $opt->{rows}) ]);
}
return $new_rs;
}
sub _rows_from_mapkey {
my ($self, $mapkey, $filter) = @_;
my @rows = ();
my $keys = $self->_redis->smembers($mapkey);
foreach my $key (@{ $keys }) {
my %entry = $self->_redis->hgetall($key);
$entry{id} = $entry{ruid};
if (exists $filter->{reseller_id} && $filter->{reseller_id} != $self->_domain_resellers->{$entry{domain}}) {
next;
}
my $res = NGCP::Panel::Utils::RedisLocationResultSource->new(_data => \%entry);
push @rows, $res;
}
return \@rows;
}
sub _filter {
my ($self, $filter) = @_;
my @newrows = ();
my $i = 0;
foreach my $row (@{ $self->_rows }) {
my $match = 0;
my $filter_applied = 0;
my %attr = map { $_->name => 1 } $row->meta->get_all_attributes;
foreach my $f (keys %{ $filter }) {
if ($f eq "-and" && ref $filter->{$f} eq "ARRAY") {
foreach my $col (@{ $filter->{$f} }) {
next unless (ref $col eq "ARRAY");
foreach my $innercol (@{ $col }) {
if (ref $innercol eq "HASH") {
foreach my $colname (keys %{ $innercol }) {
my $searchname = $colname;
$colname =~ s/^me\.//;
next if ($colname =~ /\./); # we don't support joined table columns
$filter_applied = 1;
if (ref $innercol->{$searchname} eq "") {
if (!exists $attr{$colname} || lc($row->$colname) ne lc($innercol->{$searchname})) {
} else {
$match = 1;
last;
}
} elsif (ref $innercol->{$searchname} eq "HASH" && exists $innercol->{$searchname}->{like}) {
my $fil = $innercol->{$searchname}->{like};
$fil =~ s/^\%//;
$fil =~ s/\%$//;
if (!exists $attr{$colname} || $row->$colname !~ /$fil/i) {
} else {
$match = 1;
last;
}
}
}
last if ($match);
}
}
}
last if ($match);
}
}
next if ($filter_applied && !$match);
push @newrows, $row;
}
$self->_rows(\@newrows);
}
sub _scan {
my ($self, $filter) = @_;
$filter //= {};
my $match = ($filter->{username} // "") . ":" . ($filter->{domain} // "");
if ($match eq ":") {
$match = "*";
} elsif ($match =~ /:$/) {
$match .= '*';
}
$self->_rows([]);
my $cursor = 0;
do {
my $res = $self->_redis->scan($cursor, MATCH => "location:usrdom::$match", COUNT => 1000);
$cursor = shift @{ $res };
my $mapkeys = shift @{ $res };
foreach my $mapkey (@{ $mapkeys }) {
push @{ $self->_rows }, @{ $self->_rows_from_mapkey($mapkey, $filter) };
}
} while ($cursor);
return 1;
}
sub result_class {
"dummy";
}
sub result_source {
NGCP::Panel::Utils::RedisLocationResultSource->new;
}
1;