changeset 5f35f461245c in sao:default
details: https://hg.tryton.org/sao?cmd=changeset&node=5f35f461245c
description:
        Deduplicate entries in domain inversion's simplify

        issue11248
        review397301002
diffstat:

 src/common.js |  81 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 tests/sao.js  |  67 ++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 125 insertions(+), 23 deletions(-)

diffs (193 lines):

diff -r b426134f663b -r 5f35f461245c src/common.js
--- a/src/common.js     Sat Mar 26 13:00:03 2022 +0100
+++ b/src/common.js     Wed Mar 30 19:20:31 2022 +0200
@@ -2571,22 +2571,79 @@
                 return models;
             }
         },
+        _bool_operator: function(domain) {
+            var bool_op = 'AND';
+            if ((domain.length > 0) &&
+                ((domain[0] == 'AND') || (domain[0] == 'OR'))) {
+                bool_op = domain[0];
+            }
+            return bool_op;
+        },
+        simplify_nested: function(domain) {
+            if (!domain.length) {
+                return [];
+            } else if (this.is_leaf(domain)) {
+                return [domain];
+            } else if ((domain == 'AND') || (domain == 'OR')) {
+                return [domain];
+            } else if ((domain instanceof Array) && (domain.length == 1)) {
+                return this.simplify_nested(domain[0]);
+            } else {
+                var simplified = [];
+                var domain_op = this._bool_operator(domain);
+                for (var branch of domain) {
+                    var simplified_branch = this.simplify_nested(branch);
+                    if ((this._bool_operator(branch) == domain_op) ||
+                        (simplified_branch.length == 1)) {
+                        simplified.push(...simplified_branch);
+                    } else {
+                        simplified.push(simplified_branch);
+                    }
+                }
+                return simplified;
+            }
+        },
+        simplify_duplicate: function(domain) {
+            var dedup_branches = [];
+            var bool_op = null;
+            if (~['AND', 'OR'].indexOf(domain[0])) {
+                bool_op = domain[0];
+                domain = domain.slice(1);
+            }
+            for (var branch of domain) {
+                var simplified_branch = this.simplify(branch);
+                if (simplified_branch.length == 0) {
+                    if (bool_op === 'OR') {
+                        return [];
+                    } else {
+                        continue;
+                    }
+                }
+                var found_branch = false;
+                for (var duped_branch of dedup_branches) {
+                    if (Sao.common.compare(
+                        simplified_branch, duped_branch)) {
+                        found_branch = true;
+                        break;
+                    }
+                }
+                if (!found_branch) {
+                    dedup_branches.push(simplified_branch);
+                }
+            }
+
+            if (bool_op && (dedup_branches.length > 1)) {
+                dedup_branches.unshift(bool_op);
+            }
+            return dedup_branches;
+        },
         simplify: function(domain) {
             if (this.is_leaf(domain)) {
-                return domain;
-            } else if (~['OR', 'AND'].indexOf(domain)) {
-                return domain;
-            } else if ((domain instanceof Array) && (domain.length == 1) &&
-                    (~['OR', 'AND'].indexOf(domain[0]))) {
+                return [domain];
+            } else if (!domain.length) {
                 return [];
-            } else if ((domain instanceof Array) && (domain.length == 1) &&
-                    (!this.is_leaf(domain[0]))) {
-                return this.simplify(domain[0]);
-            } else if ((domain instanceof Array) && (domain.length == 2) &&
-                    ~['AND', 'OR'].indexOf(domain[0])) {
-                return [this.simplify(domain[1])];
             } else {
-                return domain.map(this.simplify.bind(this));
+                return this.simplify_nested(this.simplify_duplicate(domain));
             }
         },
         merge: function(domain, domoperator) {
diff -r b426134f663b -r 5f35f461245c tests/sao.js
--- a/tests/sao.js      Sat Mar 26 13:00:03 2022 +0100
+++ b/tests/sao.js      Wed Mar 30 19:20:31 2022 +0200
@@ -2574,7 +2574,7 @@
                 JSON.stringify(context) + ')');
         context = {y: 4, z: 'b'};
         QUnit.ok(compare(domain_inversion(domain, 'x', context),
-                ['OR', [['x', '=', 3]], [['x', '=', 2]]]),
+                ['OR', ['x', '=', 3], ['x', '=', 2]]),
             'domain_inversion(' + JSON.stringify(domain) + ', \'x\', ' +
                 JSON.stringify(context) + ')');
     });
@@ -2600,15 +2600,25 @@
         var compare = Sao.common.compare;
 
         [
-        [[['x', '=', 3]], [['x', '=', 3]]],
-        [[[['x', '=', 3]]], [['x', '=', 3]]],
-        [['OR', ['x', '=', 3]], [['x', '=', 3]]],
-        [['OR', [['x', '=', 3]], [['y', '=', 5]]],
-            ['OR', [['x', '=', 3]], [['y', '=', 5]]]],
-        [['OR', ['x', '=', 3], ['AND', ['y', '=', 5]]],
-            ['OR', ['x', '=', 3], [['y', '=', 5]]]],
-        [['AND'], []],
-        [['OR'], []]
+            [[['x', '=', 3]], [['x', '=', 3]]],
+            [[[['x', '=', 3]]], [['x', '=', 3]]],
+            [
+                [[['x', '=', 3], ['y', '=', 4]]], 
+                [['x', '=', 3], ['y', '=', 4]]],
+            [['OR', ['x', '=', 3]], [['x', '=', 3]]],
+            [
+                ['OR', [['x', '=', 3]], [['y', '=', 5]]],
+                ['OR', ['x', '=', 3], ['y', '=', 5]]],
+            [
+                ['OR', ['x', '=', 3], ['AND', ['y', '=', 5]]],
+                ['OR', ['x', '=', 3], ['y', '=', 5]]],
+            [[['x', '=', 3], ['OR']], [['x', '=', 3]]],
+            [['OR', ['x', '=', 3], []], []],
+            [['OR', ['x', '=', 3], ['OR']], []],
+            [[['x', '=', 3], []], [['x', '=', 3]]],
+            [[['x', '=', 3], ['AND']], [['x', '=', 3]]],
+            [['AND'], []],
+            [['OR'], []]
         ].forEach(function(test) {
             var domain = test[0];
             var result = test[1];
@@ -2617,6 +2627,41 @@
         });
     });
 
+    QUnit.test('DomainInversion simplify deduplicate', function() {
+        var domain_inversion = new Sao.common.DomainInversion();
+        var simplify = domain_inversion.simplify.bind(domain_inversion);
+        var compare = Sao.common.compare;
+
+        var clause = ['x', '=', 3];
+        var another = ['y', '=', 4];
+        var third = ['z', '=', 5];
+        [
+            [[], []],
+            [['OR', []], []],
+            [['AND', []], []],
+            [[clause], [clause]],
+            [['OR', clause], [clause]],
+            [[clause, clause], [clause]],
+            [['OR', clause, clause], [clause]],
+            [[clause, [clause, clause]], [clause]],
+            [[clause, another], [clause, another]],
+            [['OR', clause, another], ['OR', clause, another]],
+            [[clause, clause, another], [clause, another]],
+            [[clause, [clause, clause], another], [clause, another]],
+            [[clause, clause, another, another], [clause, another]],
+            [[clause, another, clause, another], [clause, another]],
+            [
+                ['AND', ['OR', clause, another], third],
+                ['AND', ['OR', clause, another], third]],
+        ].forEach(function(test) {
+            var domain = test[0];
+            var result = test[1];
+            QUnit.ok(compare(simplify(domain), result),
+                'simplify(' + JSON.stringify(domain) + ')');
+        });
+
+    });
+
     QUnit.test('DomainInversion merge', function() {
         var domain_inversion = new Sao.common.DomainInversion();
         var merge = domain_inversion.merge.bind(domain_inversion);
@@ -2669,7 +2714,7 @@
         QUnit.ok(compare(concat([[], []]), []),
             'compare(' + JSON.stringify([[], []]) + ')');
         QUnit.ok(compare(concat([domain1, domain2], 'OR'),
-                ['OR', [['a', '=', 1]], [['b', '=', 2]]]),
+                ['OR', ['a', '=', 1], ['b', '=', 2]]),
             'compare(' + JSON.stringify([domain1, domain2]) + ', \'OR\')');
     });
 

Reply via email to