Consider in-leaf with a unique value as constrained for domain inversion

Closes #13869
This commit is contained in:
Nicolas Évrard
2025-02-13 01:02:11 +01:00
parent 23d6566664
commit 8066320c0d
5 changed files with 100 additions and 20 deletions
+5 -10
View File
@@ -2418,12 +2418,10 @@
(expression.length > 2) &&
(typeof expression[1] == 'string'));
},
constrained_leaf: function(part, boolop) {
if (boolop === undefined) {
boolop = this.and;
}
constrained_leaf: function(part) {
var operand = part[1];
if ((operand === '=') & (boolop === this.and)) {
let value = part[2];
if ((operand === '=') || ((operand == 'in') && (value.length == 1))) {
// We should consider that other domain inversion will set a
// correct value to this field
return true;
@@ -3049,8 +3047,7 @@
((field in context) &&
(this.domain_inversion.eval_leaf(
part, context, this.domain_inversion.and) ||
this.domain_inversion.constrained_leaf(
part, this.domain_inversion.and)))) {
this.domain_inversion.constrained_leaf(part)))) {
result.push(true);
} else {
return false;
@@ -3105,9 +3102,7 @@
field = this.base(field);
if ((field in context) &&
(this.domain_inversion.eval_leaf(
part, context, this.domain_inversion.or)) ||
this.domain_inversion.constrained_leaf(
part, this.domain_inversion.or)) {
part, context, this.domain_inversion.or))) {
return true;
} else if ((field in context) &&
!this.domain_inversion.eval_leaf(part, context,
+54
View File
@@ -2494,6 +2494,60 @@
'domain_inversion(' + JSON.stringify(domain) + ', \'x\')');
});
QUnit.test('DomainInversion unconstrained_inversion', function() {
let domain_inversion = new Sao.common.DomainInversion();
domain_inversion = domain_inversion.domain_inversion.bind(
domain_inversion);
let compare = Sao.common.compare;
let domain = [['x', '=', 3], ['y', 'in', ['a', 'b']]];
QUnit.assert.ok(
compare(domain_inversion(domain, 'x'), [['x', '=', 3]]),
`domain_inversion(${domain}, 'x')`);
QUnit.assert.ok(
compare(domain_inversion(domain, 'x', {'y': 'a'}), [['x', '=', 3]]),
`domain_inversion(${domain}, 'x', {'y': 'a'})`);
QUnit.assert.strictEqual(
domain_inversion(domain, 'x', {'y': 'c'}), false,
`domain_inversion(${domain}, 'x', {'y': 'c'})`);
});
QUnit.test('DomainInversion constrained_equal_inversion', function() {
let domain_inversion = new Sao.common.DomainInversion();
domain_inversion = domain_inversion.domain_inversion.bind(
domain_inversion);
let compare = Sao.common.compare;
let domain = [['x', '=', 3], ['y', '=', 'a']];
QUnit.assert.ok(
compare(domain_inversion(domain, 'x'), [['x', '=', 3]]),
`domain_inversion(${domain}, 'x')`);
QUnit.assert.ok(
compare(domain_inversion(domain, 'x', {'y': 'a'}), [['x', '=', 3]]),
`domain_inversion(${domain}, 'x', {'y': 'a'})`);
QUnit.assert.ok(
compare(domain_inversion(domain, 'x', {'y': 'c'}), [['x', '=', 3]]),
`domain_inversion(${domain}, 'x', {'y': 'c'})`);
});
QUnit.test('DomainInversion constrained_in_inversion', function() {
let domain_inversion = new Sao.common.DomainInversion();
domain_inversion = domain_inversion.domain_inversion.bind(
domain_inversion);
let compare = Sao.common.compare;
let domain = [['x', '=', 3], ['y', 'in', ['a']]];
QUnit.assert.ok(
compare(domain_inversion(domain, 'x'), [['x', '=', 3]]),
`domain_inversion(${domain}, 'x')`);
QUnit.assert.ok(
compare(domain_inversion(domain, 'x', {'y': 'a'}), [['x', '=', 3]]),
`domain_inversion(${domain}, 'x', {'y': 'a'})`);
QUnit.assert.ok(
compare(domain_inversion(domain, 'x', {'y': 'c'}), [['x', '=', 3]]),
`domain_inversion(${domain}, 'x', {'y': 'c'})`);
});
QUnit.test('DomainInversion and_inversion', function() {
var domain_inversion = new Sao.common.DomainInversion();
domain_inversion = domain_inversion.domain_inversion.bind(
+4 -5
View File
@@ -79,9 +79,9 @@ def is_leaf(expression):
and isinstance(expression[1], str))
def constrained_leaf(part, boolop=operator.and_):
def constrained_leaf(part):
field, operand, value = part[:3]
if operand == '=' and boolop == operator.and_:
if operand == '=' or (operand == 'in' and len(value) == 1):
# We should consider that other domain inversion will set a correct
# value to this field
return True
@@ -502,7 +502,7 @@ class And(object):
if (field not in context
or field in context
and (eval_leaf(part, context, operator.and_)
or constrained_leaf(part, operator.and_))):
or constrained_leaf(part))):
result.append(True)
else:
return False
@@ -544,8 +544,7 @@ class Or(And):
field = part[0]
field = self.base(field)
if (field in context
and (eval_leaf(part, context, operator.or_)
or constrained_leaf(part, operator.or_))):
and eval_leaf(part, context, operator.or_)):
return True
elif (field in context
and not eval_leaf(part, context, operator.or_)):
+33
View File
@@ -596,6 +596,39 @@ class DomainInversionTestCase(TestCase):
domain = [['x.id', '>', 5]]
self.assertEqual(domain_inversion(domain, 'x'), [['x.id', '>', 5]])
def test_unconstrained_inversion(self):
domain = [['x', '=', 3], ['y', 'in', ['a', 'b']]]
self.assertEqual(domain_inversion(domain, 'x'), [['x', '=', 3]])
self.assertEqual(
domain_inversion(domain, 'x', {'y': 'a'}),
[['x', '=', 3]])
self.assertEqual(
domain_inversion(domain, 'x', {'y': 'c'}),
False)
def test_constrained_equal_inversion(self):
domain = [['x', '=', 3], ['y', '=', 'a']]
self.assertEqual(domain_inversion(domain, 'x'), [['x', '=', 3]])
self.assertEqual(
domain_inversion(domain, 'x', {'y': 'a'}),
[['x', '=', 3]])
self.assertEqual(
domain_inversion(domain, 'x', {'y': 'c'}),
[['x', '=', 3]])
def test_constrained_in_inversion(self):
domain = [['x', '=', 3], ['y', 'in', ['a']]]
self.assertEqual(domain_inversion(domain, 'x'), [['x', '=', 3]])
self.assertEqual(
domain_inversion(domain, 'x', {'y': 'a'}),
[['x', '=', 3]])
self.assertEqual(
domain_inversion(domain, 'x', {'y': 'c'}),
[['x', '=', 3]])
def test_and_inversion(self):
domain = [['x', '=', 3], ['y', '>', 5]]
self.assertEqual(domain_inversion(domain, 'x'), [['x', '=', 3]])
+4 -5
View File
@@ -79,9 +79,9 @@ def is_leaf(expression):
and isinstance(expression[1], str))
def constrained_leaf(part, boolop=operator.and_):
def constrained_leaf(part):
field, operand, value = part[:3]
if operand == '=' and boolop == operator.and_:
if operand == '=' or (operand == 'in' and len(value) == 1):
# We should consider that other domain inversion will set a correct
# value to this field
return True
@@ -502,7 +502,7 @@ class And(object):
if (field not in context
or field in context
and (eval_leaf(part, context, operator.and_)
or constrained_leaf(part, operator.and_))):
or constrained_leaf(part))):
result.append(True)
else:
return False
@@ -544,8 +544,7 @@ class Or(And):
field = part[0]
field = self.base(field)
if (field in context
and (eval_leaf(part, context, operator.or_)
or constrained_leaf(part, operator.or_))):
and eval_leaf(part, context, operator.or_)):
return True
elif (field in context
and not eval_leaf(part, context, operator.or_)):