[Rt-commit] rt branch 5.0/cf-numeric-comparison created. rt-5.0.2-66-gadb5ec517e
BPS Git Server
git at git.bestpractical.com
Tue Feb 15 20:51:14 UTC 2022
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt".
The branch, 5.0/cf-numeric-comparison has been created
at adb5ec517ed648275f733d0e4cb74866d5149046 (commit)
- Log -----------------------------------------------------------------
commit adb5ec517ed648275f733d0e4cb74866d5149046
Author: sunnavy <sunnavy at bestpractical.com>
Date: Tue Feb 15 03:57:43 2022 +0800
Test searching/sorting cf values numerically
diff --git a/t/ticket/search_by_cf_numeric.t b/t/ticket/search_by_cf_numeric.t
new file mode 100644
index 0000000000..edc73767a7
--- /dev/null
+++ b/t/ticket/search_by_cf_numeric.t
@@ -0,0 +1,55 @@
+
+use strict;
+use warnings;
+
+use RT::Test nodata => 1, tests => undef;
+
+{
+ no warnings 'redefine';
+ use RT::CustomField;
+ *RT::CustomField::IsNumeric = sub { 1 }
+}
+
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+my $cf = RT::Test->load_or_create_custom_field( Name => 'test_cf', Queue => $queue->id, Type => 'FreeformSingle' );
+my $cfid = $cf->id;
+
+my $cf2 = RT::Test->load_or_create_custom_field( Name => 'test_cf2', Queue => $queue->id, Type => 'FreeformSingle' );
+my $cf2id = $cf2->id;
+
+my @tickets = RT::Test->create_tickets(
+ { Queue => $queue->Name },
+ { Subject => 'Big', "CustomField-$cfid" => 12, "CustomField-$cf2id" => 5 },
+ { Subject => 'Small', "CustomField-$cfid" => 3, "CustomField-$cf2id" => 10 },
+);
+
+my $tickets = RT::Tickets->new( RT->SystemUser );
+$tickets->FromSQL(q{Queue = 'General' AND CF.test_cf > 5 });
+is( $tickets->Count, 1, 'Found 1 ticket' );
+is( $tickets->First->id, $tickets[0]->id, 'Found the big ticket' );
+
+$tickets->FromSQL(q{Queue = 'General' AND CF.test_cf = 12 });
+is( $tickets->Count, 1, 'Found 1 ticket' );
+is( $tickets->First->id, $tickets[0]->id, 'Found the big ticket' );
+
+$tickets->FromSQL(q{Queue = 'General' AND CF.test_cf < 5});
+is( $tickets->Count, 1, 'Found 1 ticket' );
+is( $tickets->First->id, $tickets[1]->id, 'Found the small ticket' );
+
+$tickets->FromSQL(q{Queue = 'General' AND CF.test_cf = 3});
+is( $tickets->Count, 1, 'Found 1 ticket' );
+is( $tickets->First->id, $tickets[1]->id, 'Found the small ticket' );
+
+$tickets->FromSQL(q{Queue = 'General' AND CF.test_cf < CF.test_cf2 });
+is( $tickets->Count, 1, 'Found 1 ticket' );
+is( $tickets->First->id, $tickets[1]->id, 'Found the small ticket' );
+
+$tickets->FromSQL(q{Queue = 'General'});
+is( $tickets->Count, 2, 'Found 2 tickets' );
+$tickets->OrderByCols( { FIELD => 'CustomField.test_cf' } );
+is( $tickets->First->id, $tickets[1]->id, 'Small ticket first' );
+
+$tickets->OrderByCols( { FIELD => 'CustomField.test_cf', ORDER => 'DESC' } );
+is( $tickets->First->id, $tickets[0]->id, 'Big ticket first' );
+
+done_testing;
commit f85a093e63512cdd3a8f19cf3eaf9cfdb036b881
Author: sunnavy <sunnavy at bestpractical.com>
Date: Sat Feb 12 00:32:46 2022 +0800
Support to search/sort cf values numerically
diff --git a/lib/RT/CustomField.pm b/lib/RT/CustomField.pm
index a89ad6a4b9..e98198cf02 100644
--- a/lib/RT/CustomField.pm
+++ b/lib/RT/CustomField.pm
@@ -2385,6 +2385,10 @@ sub CleanupDefaultValues {
}
}
+sub IsNumeric {
+ my $self = shift;
+}
+
=head2 id
Returns the current value of id.
diff --git a/lib/RT/SearchBuilder.pm b/lib/RT/SearchBuilder.pm
index caf1d035b1..2f16439194 100644
--- a/lib/RT/SearchBuilder.pm
+++ b/lib/RT/SearchBuilder.pm
@@ -169,8 +169,15 @@ sub _OrderByCF {
ENTRYAGGREGATOR => 'AND'
);
- return { %$row, ALIAS => $CFvs, FIELD => 'SortOrder' },
- { %$row, ALIAS => $ocfvs, FIELD => 'Content' };
+ return { %$row, ALIAS => $CFvs, FIELD => 'SortOrder' },
+ {
+ %$row,
+ ALIAS => $ocfvs,
+ FIELD => 'Content',
+ blessed $cf && $cf->IsNumeric
+ ? ( FUNCTION => $self->_CastToDecimal('Content') )
+ : ()
+ };
}
sub OrderByCols {
@@ -529,9 +536,20 @@ sub _LimitCustomField {
my $fix_op = sub {
+ my %args = @_;
+
+ if ( $args{'FIELD'} eq 'Content'
+ && blessed $cf
+ && $cf->IsNumeric
+ && ( !$args{QUOTEVALUE} || Scalar::Util::looks_like_number($args{'VALUE'}) ) )
+ {
+ $args{QUOTEVALUE} = 0;
+ $args{FUNCTION} = $self->_CastToDecimal( "$args{ALIAS}.$args{FIELD}" );
+ return %args;
+ }
+
return @_ unless RT->Config->Get('DatabaseType') eq 'Oracle';
- my %args = @_;
return %args unless $args{'FIELD'} eq 'LargeContent';
my $op = $args{'OPERATOR'};
@@ -827,17 +845,18 @@ sub _LimitCustomField {
);
} else {
# Otherwise, go looking at the Content
- $self->Limit(
+ $self->Limit( $fix_op->(
%args,
ALIAS => $ocfvalias,
FIELD => 'Content',
OPERATOR => $op,
VALUE => $value,
CASESENSITIVE => 0,
- );
+ ) );
}
- if (!$value_is_long and $op eq "=") {
+ if ( ( blessed($cf) and $cf->IsNumeric ) or ( !$value_is_long and $op eq "=" ) ) {
+ # Skip LargeContent comparison for numeric values.
# Doesn't matter what LargeContent contains, as it cannot match
# the short value.
} elsif (!$value_is_long and $op =~ /^(!=|<>)$/) {
@@ -1140,6 +1159,23 @@ sub DistinctFieldValues {
return @values;
}
+sub _CastToDecimal {
+ my $self = shift;
+ my $field = shift or return;
+
+ my $db_type = RT->Config->Get('DatabaseType');
+ if ( $db_type eq 'Oracle' ) {
+ return "TO_NUMBER($field)";
+ }
+ elsif ( $db_type eq 'mysql' ) {
+ # mysql's CAST decimal requires precision specification, which we don't know.
+ return "($field+0)";
+ }
+ else {
+ return "CAST($field AS DECIMAL)";
+ }
+}
+
RT::Base->_ImportOverlays();
1;
diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
index 4ffbd6ab61..b957188969 100644
--- a/lib/RT/Tickets.pm
+++ b/lib/RT/Tickets.pm
@@ -1568,7 +1568,14 @@ sub OrderByCols {
ENTRYAGGREGATOR => 'AND'
);
push @res, { %$row, ALIAS => $CFvs, FIELD => 'SortOrder' },
- { %$row, ALIAS => $ocfvs, FIELD => 'Content' };
+ {
+ %$row,
+ ALIAS => $ocfvs,
+ FIELD => 'Content',
+ blessed $cf && $cf->IsNumeric
+ ? ( FUNCTION => $self->_CastToDecimal('Content') )
+ : ()
+ };
}
else {
RT->Logger->warning("Couldn't load user custom field $cf_name");
@@ -3462,28 +3469,39 @@ sub _parser {
$value = "main.$value" if $class eq 'RT::Tickets' && $value =~ /^\w+$/;
if ( $class eq 'RT::ObjectCustomFieldValues' ) {
+ my $cast_to;
+ if ( $meta->[0] eq 'CUSTOMFIELD' ) {
+ my ($object, $field, $cf, $column) = $self->_CustomFieldDecipher( $subkey );
+ if ( $cf && $cf->IsNumeric ) {
+ $cast_to = 'DECIMAL';
+ }
+ }
+
if ( RT->Config->Get('DatabaseType') eq 'Pg' ) {
- my $cast_to;
- if ($subkey) {
+ if ( !$cast_to ) {
+ if ($subkey) {
- # like Requestor.id
- if ( $subkey eq 'id' ) {
- $cast_to = 'INTEGER';
- }
- }
- elsif ( my $meta = $self->RecordClass->_ClassAccessible->{$key} ) {
- if ( $meta->{is_numeric} ) {
- $cast_to = 'INTEGER';
+ # like Requestor.id
+ if ( $subkey eq 'id' ) {
+ $cast_to = 'INTEGER';
+ }
}
- elsif ( $meta->{type} eq 'datetime' ) {
- $cast_to = 'TIMESTAMP';
+ elsif ( my $meta = $self->RecordClass->_ClassAccessible->{$key} ) {
+ if ( $meta->{is_numeric} ) {
+ $cast_to = 'INTEGER';
+ }
+ elsif ( $meta->{type} eq 'datetime' ) {
+ $cast_to = 'TIMESTAMP';
+ }
}
}
-
$value = "CAST($value AS $cast_to)" if $cast_to;
}
elsif ( RT->Config->Get('DatabaseType') eq 'Oracle' ) {
- if ($subkey) {
+ if ( $cast_to && $cast_to eq 'DECIMAL' ) {
+ $value = "TO_NUMBER($value)";
+ }
+ elsif ($subkey) {
# like Requestor.id
if ( $subkey eq 'id' ) {
-----------------------------------------------------------------------
hooks/post-receive
--
rt
More information about the rt-commit
mailing list