Volltext-Suche: Hintergrund-Job nachts aktivieren
[kivitendo-erp.git] / t / controllers / helpers / parse_filter.t
index 9d003c0..bfccf4e 100644 (file)
@@ -1,12 +1,14 @@
 use lib 't';
 
-use Test::More tests => 18;
+use Test::More tests => 41;
 use Test::Deep;
 use Data::Dumper;
 
 use_ok 'Support::TestSetup';
 use_ok 'SL::Controller::Helper::ParseFilter';
 
+use SL::DB::OrderItem;
+
 undef *::any; # Test::Deep exports any (for junctions) and MoreCommon exports any (like in List::Moreutils)
 
 Support::TestSetup::login();
@@ -35,10 +37,10 @@ test {
   name => 'Test',
   whut => 'moof',
 }, {
-  query => [ %{{
+  query => bag(
     name => 'Test',
     whut => 'moof'
-  }} ],
+  ),
 }, 'basic test';
 
 test {
@@ -96,10 +98,10 @@ test {
     },
   },
 }, {
-  'query' => [ %{{
+  'query' => bag(
                'invoice.customer.name'  => 'test',
                'customer.name'          => 'test',
-             }} ],
+            ),
   'with_objects' => bag( 'invoice.customer', 'customer', 'invoice' )
 }, 'object in more than one relationship';
 
@@ -140,7 +142,7 @@ test {
   ]
 }, {
   'sellprice:number' => [ '123,4', '2,34', '0,4' ],
-  'sellprice_number' => [ '123,4', '2,34', '0,4' ],
+  'sellprice_number_' => { '123,4' => 1, '2,34' => 1, '0,4' => 1 },
 }, 'laundering with array', target => 'filter';
 
 my %args = (
@@ -177,6 +179,44 @@ test {
   }
 }, 'deep laundering, check for laundered hash', target => 'launder', launder_to => { };
 
+test {
+  part => {
+   'sellprice:number' => '2',
+   'sellprice:number::' => 'le',
+  }
+}, {
+  part => {
+   'sellprice:number' => '2',
+   'sellprice:number::' => 'le',
+  }
+}, 'laundering of indirect filters does not alter', target => 'filter', launder_to => { };
+
+test {
+  part => {
+   'sellprice:number' => '2',
+   'sellprice:number::' => 'le',
+  }
+}, {
+  part => {
+    'sellprice_number' => '2',
+    'sellprice_number__' => 'le',
+  }
+}, 'laundering of indirect filters', target => 'launder', launder_to => { };
+
+test {
+  part => {
+   'sellprice:number' => '2',
+   'sellprice:number::' => 'le',
+  }
+}, {
+  part => {
+    'sellprice:number' => '2',
+    'sellprice:number::' => 'le',
+    'sellprice_number' => '2',
+    'sellprice_number__' => 'le',
+  }
+}, 'laundering of indirect filters - inplace', target => 'filter';
+
 ### bug: sub objects
 
 test {
@@ -190,3 +230,214 @@ test {
   with_objects => bag('order.customer', 'order'),
 }, 'sub objects have to retain their prefix';
 
+### class filter dispatch
+#
+test {
+  name => 'Test',
+  whut => 'moof',
+}, {
+  query => bag(
+    name => 'Test',
+    whut => 'moof'
+  ),
+}, 'object test simple', class => 'SL::DB::Manager::Part';
+
+test {
+  'part_type' => 'assembly',
+}, {
+  query => [
+             'part_type',
+             'assembly'
+           ] ,
+}, 'object test without prefix', class => 'SL::DB::Manager::Part';
+
+test {
+  'part.part_type' => 'assembly',
+}, {
+  query => [
+             'part.part_type',
+             'assembly'
+           ]
+}, 'object test with prefix', class => 'SL::DB::Manager::OrderItem';
+
+test {
+  'part_type' => [ 'part', 'assembly' ],
+}, {
+  query => [
+             'or',
+             [
+               'part_type',
+               'part',
+               'part_type',
+               'assembly'
+             ]
+           ]
+}, 'object test without prefix but complex value', class => 'SL::DB::Manager::Part';
+test {
+  'part.part_type' => [ 'part', 'assembly' ],
+}, {
+  query => [
+             'or',
+             [
+               'part.part_type',
+               'part',
+               'part.part_type',
+               'assembly'
+             ]
+           ]
+}, 'object test with prefix but complex value', class => 'SL::DB::Manager::OrderItem';
+
+test {
+  description => 'test'
+}, {
+  query => [ description => 'test' ],
+  with_objects => [ 'order' ]
+}, 'with_objects don\'t get clobbered', with_objects => [ 'order' ];
+
+test {
+  customer => {
+    description => 'test'
+  }
+}, {
+  query => [ 'customer.description' => 'test' ],
+  with_objects => [ 'order', 'customer' ]
+}, 'with_objects get extended with auto infered objects', with_objects => [ 'order' ];
+
+test {
+  customer => {
+    description => 'test'
+  }
+}, {
+  query => [ 'customer.description' => 'test' ],
+  with_objects => [ 'order', 'customer' ]
+}, 'with_objects get extended with auto infered objects with classes', class => 'SL::DB::Manager::Order',  with_objects => [ 'order' ];
+
+test {
+  customer => {
+    description => 'test'
+  }
+}, {
+  query => [ 'customer.description' => 'test' ],
+  with_objects => [ 'customer' ]
+}, 'with_objects: no duplicates', with_objects => [ 'customer' ];
+
+test {
+  part => {
+   'partnumber:substr::ilike' => '1',
+  },
+}, {
+  query => [
+   'part.partnumber', {
+     ilike => '%1%'
+   }
+ ],
+ with_objects => [ 'part' ],
+}, 'Regression check: prefixing of fallback filtering in relation with custom filters', class => 'SL::DB::Manager::OrderItem';
+test {
+  'description:substr:multi::ilike' => 'term1 term2',
+}, {
+  query => [
+    and => [
+      description => { ilike => '%term1%' },
+      description => { ilike => '%term2%' },
+    ]
+  ]
+}, 'simple :multi';
+
+test {
+  part => {
+    'all:substr:multi::ilike' => 'term1 term2',
+  },
+}, {
+  query => [
+    and => [
+      or => [
+        'part.partnumber'  => { ilike => '%term1%' },
+        'part.description' => { ilike => '%term1%' },
+        'part.ean'         => { ilike => '%term1%' },
+      ],
+      or => [
+        'part.partnumber'  => { ilike => '%term2%' },
+        'part.description' => { ilike => '%term2%' },
+        'part.ean'         => { ilike => '%term2%' },
+      ],
+    ]
+  ],
+}, 'complex :multi with custom dispatch and prefix', class => 'SL::DB::Manager::OrderItem';
+
+test {
+  'description:substr:multi::ilike' => q|term1 "term2 and half" 'term3 and stuff'|,
+}, {
+  query => [
+    and => [
+      description => { ilike => '%term1%' },
+      description => { ilike => '%term2 and half%' },
+      description => { ilike => '%term3 and stuff%' },
+    ]
+  ]
+}, ':multi with complex tokenizing';
+
+# test tokenizing for custom filters by monkeypatching a custom filter into Part
+SL::DB::Manager::Part->add_filter_specs(
+  test => sub {
+    my ($key, $value, $prefix, @additional) = @_;
+    return "$prefix$key" => { @additional, $value };
+  }
+);
+
+test {
+  'part.test.what' => 2,
+}, {
+  query => [
+    'part.test' => { 'what', 2 },
+  ]
+}, 'additional tokens', class => 'SL::DB::Manager::OrderItem';
+
+test {
+  'part.test.what:substr::ilike' => 2,
+}, {
+  query => [
+    'part.test' => { 'what', { ilike => '%2%' } },
+  ]
+}, 'additional tokens + filters + methods', class => 'SL::DB::Manager::OrderItem';
+
+test {
+  'orderitems.part.test.what:substr::ilike' => 2,
+}, {
+  query => [
+    'orderitems.part.test' => { 'what', { ilike => '%2%' } },
+  ]
+}, 'relationship + additional tokens + filters + methods', class => 'SL::DB::Manager::Order';
+
+test {
+  part => {
+    'obsolete::lazy_bool_eq' => '0',
+  },
+}, {
+  query => [
+      or => [
+        'part.obsolete' => undef,
+        'part.obsolete' => 0
+      ],
+  ],
+  with_objects => [ 'part' ],
+}, 'complex methods modifying the key';
+
+
+test {
+  'customer:substr::ilike' => ' Meyer'
+}, {
+  query => [ customer => { ilike => '%Meyer%' } ]
+}, 'auto trim 1';
+
+test {
+  'customer:head::ilike' => ' Meyer '
+}, {
+  query => [ customer => { ilike => 'Meyer%' } ]
+}, 'auto trim 2';
+
+test {
+  'customer:tail::ilike' => "\nMeyer\x{a0}"
+}, {
+  query => [ customer => { ilike => '%Meyer' } ]
+}, 'auto trim 2';