package SL::DBUtils;
 
+use SL::Util qw(trim);
+
 require Exporter;
 our @ISA = qw(Exporter);
 
 our @EXPORT = qw(conv_i conv_date conv_dateq do_query selectrow_query do_statement
-             dump_query quote_db_date
+             dump_query quote_db_date like
              selectfirst_hashref_query selectfirst_array_query
              selectall_hashref_query selectall_array_query
              selectall_as_map
 
 sub conv_date {
   my ($value) = @_;
-  return (defined($value) && "$value" ne "") ? $value : undef;
+  return undef if !defined $value;
+  $value = trim($value);
+  return $value eq "" ? undef : $value;
 }
 
 sub conv_dateq {
   my %hash;
   if ('' eq ref $value_col) {
     while (my $ref = $sth->fetchrow_hashref()) {
-      $hash{$ref->{$key_col}} = $ref->{$value_col};
+      $hash{$ref->{$key_col} // ''} = $ref->{$value_col};
     }
   } else {
     while (my $ref = $sth->fetchrow_hashref()) {
-      $hash{$ref->{$key_col}} = { map { $_ => $ref->{$_} } @{ $value_col } };
+      $hash{$ref->{$key_col} // ''} = { map { $_ => $ref->{$_} } @{ $value_col } };
     }
   }
 
     id     => \&conv_i,
     bool   => \&conv_b,
     date   => \&conv_date,
-    start  => sub { $_[0] . '%' },
-    end    => sub { '%' . $_[0] },
-    substr => sub { '%' . $_[0] . '%' },
+    start  => sub { trim($_[0]) . '%' },
+    end    => sub { '%' . trim($_[0]) },
+    substr => sub { like($_[0]) },
   );
 
   my $_long_token = sub {
   return ($token, @vals);
 }
 
+sub like {
+  my ($string) = @_;
+
+  return "%" . SL::Util::trim($string // '') . "%";
+}
+
 1;
 
 
 Treats STR as a database date, quoting it. If STR equals current_date returns an escaped version which is treated as the current date by Postgres.
 Returns 'NULL' if STR is empty.
 
+=item like STR
+
+Turns C<STR> into an argument suitable for SQL's C<LIKE> and C<ILIKE>
+operators by Trimming the string C<STR> (removes leading and trailing
+whitespaces) and prepending and appending C<%>.
+
 =back
 
 =head2 QUERY FUNCTIONS