Quote empty string when formatting list value of domain
This is needed to keep the empty string in the list on a second parsing. Closes #13558 (grafted from 747825bc93a35fef995094be5ca9d7e04c414692) --HG-- branch : 6.0
This commit is contained in:
+8
-4
@@ -1904,10 +1904,13 @@
|
||||
.replace(escape + '%', '%')
|
||||
.replace(escape + '_', '_');
|
||||
},
|
||||
quote: function(value) {
|
||||
quote: function(value, empty=false) {
|
||||
if (typeof value != 'string') {
|
||||
return value;
|
||||
}
|
||||
if (empty && value === '') {
|
||||
return '""';
|
||||
}
|
||||
if (value.contains('\\')) {
|
||||
value = value.replace(new RegExp('\\\\', 'g'), '\\\\');
|
||||
}
|
||||
@@ -2069,7 +2072,8 @@
|
||||
return value;
|
||||
}
|
||||
},
|
||||
format_value: function(field, value, target, context) {
|
||||
format_value: function(
|
||||
field, value, target, context, _quote_empty=false) {
|
||||
if (target === undefined) {
|
||||
target = null;
|
||||
}
|
||||
@@ -2190,7 +2194,7 @@
|
||||
converts.timestamp = converts.datetime;
|
||||
if (value instanceof Array) {
|
||||
return value.map(function(v) {
|
||||
return this.format_value(field, v);
|
||||
return this.format_value(field, v, null, context, true);
|
||||
}.bind(this)).join(';');
|
||||
} else {
|
||||
var func = converts[field.type];
|
||||
@@ -2199,7 +2203,7 @@
|
||||
} else if (value === null) {
|
||||
return '';
|
||||
} else {
|
||||
return this.quote(value);
|
||||
return this.quote(value, _quote_empty);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2192,6 +2192,7 @@
|
||||
[[['name', 'ilike', 'Doe\\%']], 'Name: =Doe%'],
|
||||
[[['name', 'not ilike', '%Doe%']], 'Name: !Doe'],
|
||||
[[['name', 'in', ['John', 'Jane']]], 'Name: John;Jane'],
|
||||
[[['name', 'in', ['John', '']]], 'Name: John;""'],
|
||||
[[['name', 'in', ['John']]], 'Name: =John'],
|
||||
[[['name', 'not in', ['John', 'Jane']]], 'Name: !John;Jane'],
|
||||
[[['name', 'not in', ['John']]], 'Name: !=John'],
|
||||
|
||||
@@ -126,10 +126,12 @@ def unescape(value, escape='\\'):
|
||||
return value.replace(escape + '%', '%').replace(escape + '_', '_')
|
||||
|
||||
|
||||
def quote(value):
|
||||
def quote(value, empty=False):
|
||||
"Quote string if needed"
|
||||
if not isinstance(value, str):
|
||||
return value
|
||||
if empty and value == '':
|
||||
return '""'
|
||||
if '\\' in value:
|
||||
value = value.replace('\\', '\\\\')
|
||||
if '"' in value:
|
||||
@@ -305,7 +307,7 @@ def convert_value(field, value, context=None):
|
||||
return converts.get(field['type'], lambda: value)()
|
||||
|
||||
|
||||
def format_value(field, value, target=None, context=None):
|
||||
def format_value(field, value, target=None, context=None, _quote_empty=False):
|
||||
"Format value for field"
|
||||
if context is None:
|
||||
context = {}
|
||||
@@ -408,9 +410,11 @@ def format_value(field, value, target=None, context=None):
|
||||
'many2one': format_many2one,
|
||||
}
|
||||
if isinstance(value, (list, tuple)):
|
||||
return ';'.join(format_value(field, x, context=context) for x in value)
|
||||
return ';'.join(
|
||||
format_value(field, x, context=context, _quote_empty=True)
|
||||
for x in value)
|
||||
return quote(converts.get(field['type'],
|
||||
lambda: value if value is not None else '')())
|
||||
lambda: value if value is not None else '')(), empty=_quote_empty)
|
||||
|
||||
|
||||
def complete_value(field, value):
|
||||
|
||||
@@ -681,6 +681,8 @@ class DomainParserTestCase(TestCase):
|
||||
dom.string([('name', 'not ilike', '%Doe%')]), 'Name: !Doe')
|
||||
self.assertEqual(
|
||||
dom.string([('name', 'in', ['John', 'Jane'])]), 'Name: John;Jane')
|
||||
self.assertEqual(
|
||||
dom.string([('name', 'in', ['John', ''])]), 'Name: John;""')
|
||||
self.assertEqual(
|
||||
dom.string([('name', 'in', ['John'])]), 'Name: =John')
|
||||
self.assertEqual(
|
||||
|
||||
Reference in New Issue
Block a user