[IMP] core: introduce subqueries in search

Make the method `_search` return a `Query` object, and make that object
generate a subquery when used on the right-hand side of a condition.

closes odoo/odoo#52403

Related: odoo/enterprise#10945
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
Raphael Collet
2020-08-18 13:02:41 +00:00
parent 0f7f163d2e
commit 69869ab681
8 changed files with 164 additions and 149 deletions
+1 -7
View File
@@ -198,13 +198,7 @@ class User(models.Model):
user.employee_id = self.env['hr.employee'].search([('id', 'in', user.employee_ids.ids), ('company_id', '=', self.env.company.id)], limit=1)
def _search_company_employee(self, operator, value):
employees = self.env['hr.employee'].search([
('name', operator, value),
'|',
('company_id', '=', self.env.company.id),
('company_id', '=', False)
], order='company_id ASC')
return [('id', 'in', employees.mapped('user_id').ids)]
return [('employee_ids', operator, value)]
def action_create_employee(self):
self.ensure_one()
+13 -13
View File
@@ -231,7 +231,7 @@ class TestMailAPIPerformance(BaseMailPerformance):
#voip module read activity_type during create leading to one less query in enterprise on action_feedback
category = activity.activity_type_id.category
with self.assertQueryCount(__system__=18, emp=22):
with self.assertQueryCount(__system__=16, emp=20):
activity.action_feedback(feedback='Zizisse Done !')
@users('__system__', 'emp')
@@ -248,7 +248,7 @@ class TestMailAPIPerformance(BaseMailPerformance):
record.write({'name': 'Dupe write'})
with self.assertQueryCount(__system__=19, emp=22):
with self.assertQueryCount(__system__=17, emp=20):
record.action_close('Dupe feedback')
self.assertEqual(record.activity_ids, self.env['mail.activity'])
@@ -290,7 +290,7 @@ class TestMailAPIPerformance(BaseMailPerformance):
}).create({})
composer.onchange_template_id_wrapper()
with self.assertQueryCount(__system__=39, emp=42):
with self.assertQueryCount(__system__=37, emp=40):
composer.send_mail()
# remove created partner to ensure tests are the same each run
@@ -302,7 +302,7 @@ class TestMailAPIPerformance(BaseMailPerformance):
def test_message_assignation_email(self):
self.user_test.write({'notification_type': 'email'})
record = self.env['mail.test.track'].create({'name': 'Test'})
with self.assertQueryCount(__system__=39, emp=40):
with self.assertQueryCount(__system__=37, emp=38):
record.write({
'user_id': self.user_test.id,
})
@@ -355,7 +355,7 @@ class TestMailAPIPerformance(BaseMailPerformance):
def test_message_post_one_email_notification(self):
record = self.env['mail.test.simple'].create({'name': 'Test'})
with self.assertQueryCount(__system__=32, emp=33):
with self.assertQueryCount(__system__=30, emp=31):
record.message_post(
body='<p>Test Post Performances with an email ping</p>',
partner_ids=self.customer.ids,
@@ -494,7 +494,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
self.container.message_subscribe(self.user_portal.partner_id.ids)
record = self.container.with_user(self.env.user)
with self.assertQueryCount(__system__=68, emp=69):
with self.assertQueryCount(__system__=63, emp=64):
record.message_post(
body='<p>Test Post Performances</p>',
message_type='comment',
@@ -511,7 +511,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
record = self.container.with_user(self.env.user)
template_id = self.env.ref('test_mail.mail_test_container_tpl').id
with self.assertQueryCount(__system__=78, emp=80):
with self.assertQueryCount(__system__=73, emp=75):
record.message_post_with_template(template_id, message_type='comment', composition_mode='comment')
self.assertEqual(record.message_ids[0].body, '<p>Adding stuff on %s</p>' % record.name)
@@ -582,7 +582,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
})
rec1 = rec.with_context(active_test=False) # to see inactive records
self.assertEqual(rec1.message_partner_ids, self.partners | self.env.user.partner_id)
with self.assertQueryCount(__system__=39, emp=40):
with self.assertQueryCount(__system__=37, emp=38):
rec.write({'user_id': self.user_portal.id})
self.assertEqual(rec1.message_partner_ids, self.partners | self.env.user.partner_id | self.user_portal.partner_id)
# write tracking message
@@ -602,7 +602,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
customer_id = self.customer.id
user_id = self.user_portal.id
with self.assertQueryCount(__system__=116, emp=117):
with self.assertQueryCount(__system__=109, emp=110):
rec = self.env['mail.test.ticket'].create({
'name': 'Test',
'container_id': container_id,
@@ -631,7 +631,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
rec1 = rec.with_context(active_test=False) # to see inactive records
self.assertEqual(rec1.message_partner_ids, self.user_portal.partner_id | self.env.user.partner_id)
self.assertEqual(len(rec1.message_ids), 1)
with self.assertQueryCount(__system__=82, emp=82):
with self.assertQueryCount(__system__=77, emp=77):
rec.write({
'name': 'Test2',
'container_id': self.container.id,
@@ -668,7 +668,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
rec1 = rec.with_context(active_test=False) # to see inactive records
self.assertEqual(rec1.message_partner_ids, self.user_portal.partner_id | self.env.user.partner_id)
with self.assertQueryCount(__system__=90, emp=90):
with self.assertQueryCount(__system__=85, emp=85):
rec.write({
'name': 'Test2',
'container_id': container_id,
@@ -701,7 +701,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
rec1 = rec.with_context(active_test=False) # to see inactive records
self.assertEqual(rec1.message_partner_ids, self.partners | self.env.user.partner_id | self.user_portal.partner_id)
with self.assertQueryCount(__system__=32, emp=33):
with self.assertQueryCount(__system__=29, emp=30):
rec.write({
'name': 'Test2',
'customer_id': customer_id,
@@ -951,7 +951,7 @@ class TestMailHeavyPerformancePost(BaseMailPerformance):
]
self.attachements = self.env['ir.attachment'].with_user(self.env.user).create(self.vals)
attachement_ids = self.attachements.ids
with self.assertQueryCount(emp=85):
with self.assertQueryCount(emp=81):
self.cr.sql_log = self.warm and self.cr.sql_log_count
record.with_context({}).message_post(
body='<p>Test body <img src="cid:cid1"> <img src="cid:cid2"></p>',
@@ -51,7 +51,7 @@ class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase):
def test_message_sms_record_1_partner(self):
record = self.test_record.with_user(self.env.user)
pids = self.customer.ids
with self.mockSMSGateway(), self.assertQueryCount(employee=25): # test_mail_enterprise: 25
with self.mockSMSGateway(), self.assertQueryCount(employee=23): # test_mail_enterprise: 25
messages = record._message_sms(
body='Performance Test',
partner_ids=pids,
@@ -66,7 +66,7 @@ class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase):
def test_message_sms_record_10_partners(self):
record = self.test_record.with_user(self.env.user)
pids = self.partners.ids
with self.mockSMSGateway(), self.assertQueryCount(employee=43): # test_mail_enterprise: 43
with self.mockSMSGateway(), self.assertQueryCount(employee=41): # test_mail_enterprise: 43
messages = record._message_sms(
body='Performance Test',
partner_ids=pids,
@@ -80,7 +80,7 @@ class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase):
@warmup
def test_message_sms_record_default(self):
record = self.test_record.with_user(self.env.user)
with self.mockSMSGateway(), self.assertQueryCount(employee=28): # test_mail_enterprise: 28
with self.mockSMSGateway(), self.assertQueryCount(employee=26): # test_mail_enterprise: 28
messages = record._message_sms(
body='Performance Test',
)
@@ -51,7 +51,7 @@ class TestMassMailPerformance(TestMassMailPerformanceBase):
})
# runbot needs +50 compared to local
with self.assertQueryCount(__system__=1914, marketing=1915):
with self.assertQueryCount(__system__=1714, marketing=1715):
mailing.action_send_mail()
self.assertEqual(mailing.sent, 50)
@@ -91,7 +91,7 @@ class TestMassMailBlPerformance(TestMassMailPerformanceBase):
})
# runbot needs +62 compared to local
with self.assertQueryCount(__system__=2241, marketing=2242):
with self.assertQueryCount(__system__=1993, marketing=1994):
mailing.action_send_mail()
self.assertEqual(mailing.sent, 50)
+107 -98
View File
@@ -1130,14 +1130,14 @@ class TestMany2one(TransactionCase):
self.Partner.search([('company_id', '=', self.company.id)])
with self.assertQueries(['''
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text LIKE %s)
ORDER BY "res_company"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."company_id" IN (%s))
WHERE ("res_partner"."company_id" IN (
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text like %s)
ORDER BY "res_company"."id"
))
ORDER BY "res_partner"."display_name"
''']):
self.Partner.search([('company_id.name', 'like', self.company.name)])
@@ -1145,35 +1145,35 @@ class TestMany2one(TransactionCase):
with self.assertQueries(['''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."name"::text LIKE %s)
ORDER BY "res_partner"."id"
''', '''
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."partner_id" IN (%s))
ORDER BY "res_company"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."company_id" IN (%s))
WHERE ("res_partner"."company_id" IN (
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."partner_id" IN (
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."name"::text LIKE %s)
ORDER BY "res_partner"."id"
))
ORDER BY "res_company"."id"
))
ORDER BY "res_partner"."display_name"
''']):
self.Partner.search([('company_id.partner_id.name', 'like', self.company.name)])
with self.assertQueries(['''
SELECT "res_country".id
FROM "res_country"
WHERE ("res_country"."code"::text LIKE %s)
ORDER BY "res_country"."id"
''', '''
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text LIKE %s)
ORDER BY "res_company"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE (("res_partner"."company_id" IN (%s)) OR ("res_partner"."country_id" IN (%s)))
WHERE (("res_partner"."company_id" IN (
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text LIKE %s)
ORDER BY "res_company"."id"
)) OR ("res_partner"."country_id" IN (
SELECT "res_country".id
FROM "res_country"
WHERE ("res_country"."code"::text LIKE %s)
ORDER BY "res_country"."id"
)))
ORDER BY "res_partner"."display_name"
''']):
self.Partner.search([
@@ -1182,6 +1182,23 @@ class TestMany2one(TransactionCase):
('country_id.code', 'like', 'BE'),
])
def test_explicit_subquery(self):
self.Partner.search([('company_id.name', 'like', self.company.name)])
with self.assertQueries(['''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."company_id" IN (
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text like %s)
ORDER BY "res_company"."id"
))
ORDER BY "res_partner"."display_name"
''']):
company_ids = self.company._search([('name', 'like', self.company.name)], order='id')
self.Partner.search([('company_id', 'in', company_ids)])
def test_autojoin(self):
# auto_join on the first many2one
self.patch(self.Partner._fields['company_id'], 'auto_join', True)
@@ -1199,16 +1216,16 @@ class TestMany2one(TransactionCase):
self.Partner.search([('company_id.name', 'like', self.company.name)])
with self.assertQueries(['''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."name"::text LIKE %s)
ORDER BY "res_partner"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
LEFT JOIN "res_company" AS "res_partner__company_id" ON
("res_partner"."company_id" = "res_partner__company_id"."id")
WHERE ("res_partner__company_id"."partner_id" IN (%s))
WHERE ("res_partner__company_id"."partner_id" IN (
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."name"::text LIKE %s)
ORDER BY "res_partner"."id"
))
ORDER BY "res_partner"."display_name"
''']):
self.Partner.search([('company_id.partner_id.name', 'like', self.company.name)])
@@ -1219,16 +1236,16 @@ class TestMany2one(TransactionCase):
self.Partner.search([('company_id.partner_id.name', 'like', self.company.name)])
with self.assertQueries(['''
SELECT "res_company".id
FROM "res_company"
LEFT JOIN "res_partner" AS "res_company__partner_id" ON
("res_company"."partner_id" = "res_company__partner_id"."id")
WHERE ("res_company__partner_id"."name"::text LIKE %s)
ORDER BY "res_company"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."company_id" IN (%s))
WHERE ("res_partner"."company_id" IN (
SELECT "res_company".id
FROM "res_company"
LEFT JOIN "res_partner" AS "res_company__partner_id" ON
("res_company"."partner_id" = "res_company__partner_id"."id")
WHERE ("res_company__partner_id"."name"::text LIKE %s)
ORDER BY "res_company"."id"
))
ORDER BY "res_partner"."display_name"
''']):
self.Partner.search([('company_id.partner_id.name', 'like', self.company.name)])
@@ -1280,14 +1297,14 @@ class TestMany2one(TransactionCase):
self.Partner.search([('company_id', 'like', self.company.name)])
with self.assertQueries(['''
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text LIKE %s)
ORDER BY "res_company"."sequence", "res_company"."name"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."company_id" IN (%s))
WHERE ("res_partner"."company_id" IN (
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text LIKE %s)
ORDER BY "res_company"."sequence", "res_company"."name"
))
ORDER BY "res_partner"."display_name"
''']):
self.Partner.search([('company_id', 'like', self.company.name)])
@@ -1322,37 +1339,31 @@ class TestOne2many(TransactionCase):
self.Partner.search([('bank_ids', 'in', self.partner.bank_ids.ids)])
with self.assertQueries(['''
SELECT "res_partner_bank".id
FROM "res_partner_bank"
WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s)
ORDER BY "res_partner_bank"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."id" IN (
SELECT "partner_id" FROM "res_partner_bank" WHERE "id" IN %s
SELECT "res_partner_bank"."partner_id"
FROM "res_partner_bank"
WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s)
ORDER BY "res_partner_bank"."id"
))
ORDER BY "res_partner"."display_name"
''']):
self.Partner.search([('bank_ids.sanitized_acc_number', 'like', '12')])
with self.assertQueries(['''
SELECT "res_partner_bank".id
FROM "res_partner_bank"
WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s)
ORDER BY "res_partner_bank"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."id" IN (
SELECT "partner_id" FROM "res_partner_bank" WHERE "id" IN %s
))
ORDER BY "res_partner"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."id" IN (
SELECT "parent_id" FROM "res_partner" WHERE "id" IN %s
SELECT "res_partner"."parent_id"
FROM "res_partner"
WHERE ("res_partner"."id" IN (
SELECT "res_partner_bank"."partner_id"
FROM "res_partner_bank"
WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s)
ORDER BY "res_partner_bank"."id"
))
ORDER BY "res_partner"."id"
))
ORDER BY "res_partner"."display_name"
''']):
@@ -1482,15 +1493,13 @@ class TestOne2many(TransactionCase):
self.Partner.search([('bank_ids', 'like', '12')])
with self.assertQueries(['''
SELECT "res_partner_bank".id
FROM "res_partner_bank"
WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s)
ORDER BY "res_partner_bank"."sequence", "res_partner_bank"."id"
''', '''
SELECT "res_partner".id
FROM "res_partner"
WHERE ("res_partner"."id" IN (
SELECT "partner_id" FROM "res_partner_bank" WHERE "id" IN %s
SELECT "res_partner_bank"."partner_id"
FROM "res_partner_bank"
WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s)
ORDER BY "res_partner_bank"."sequence", "res_partner_bank"."id"
))
ORDER BY "res_partner"."display_name"
''']):
@@ -1522,37 +1531,37 @@ class TestMany2many(TransactionCase):
self.User.search([('groups_id', 'in', group.ids)], order='id')
with self.assertQueries(['''
SELECT "res_groups".id
FROM "res_groups"
WHERE ("res_groups"."color" = %s)
ORDER BY "res_groups"."id"
''', '''
SELECT "res_users".id
FROM "res_users"
WHERE ("res_users"."id" IN (
SELECT "uid" FROM "res_groups_users_rel" WHERE "gid" IN %s
SELECT "uid" FROM "res_groups_users_rel" WHERE "gid" IN (
SELECT "res_groups".id
FROM "res_groups"
WHERE ("res_groups"."color" = %s)
ORDER BY "res_groups"."id"
)
))
ORDER BY "res_users"."id"
''']):
self.User.search([('groups_id.color', '=', group.color)], order='id')
with self.assertQueries(['''
SELECT "ir_rule".id
FROM "ir_rule"
WHERE ("ir_rule"."name"::text LIKE %s)
ORDER BY "ir_rule"."id"
''', '''
SELECT "res_groups".id
FROM "res_groups"
WHERE ("res_groups"."id" IN (
SELECT "group_id" FROM "rule_group_rel" WHERE "rule_group_id" IN %s
))
ORDER BY "res_groups"."id"
''', '''
SELECT "res_users".id
FROM "res_users"
WHERE ("res_users"."id" IN (
SELECT "uid" FROM "res_groups_users_rel" WHERE "gid" IN %s
SELECT "uid" FROM "res_groups_users_rel" WHERE "gid" IN (
SELECT "res_groups".id
FROM "res_groups"
WHERE ("res_groups"."id" IN (
SELECT "group_id" FROM "rule_group_rel" WHERE "rule_group_id" IN (
SELECT "ir_rule".id
FROM "ir_rule"
WHERE ("ir_rule"."name"::text LIKE %s)
ORDER BY "ir_rule"."id"
)
))
ORDER BY "res_groups"."id"
)
))
ORDER BY "res_users"."id"
''']):
@@ -1567,15 +1576,15 @@ class TestMany2many(TransactionCase):
self.User.search([('company_ids', 'like', self.company.name)], order='id')
with self.assertQueries(['''
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text LIKE %s)
ORDER BY "res_company"."sequence", "res_company"."name"
''', '''
SELECT "res_users".id
FROM "res_users"
WHERE ("res_users"."id" IN (
SELECT "user_id" FROM "res_company_users_rel" WHERE "cid" IN %s
SELECT "user_id" FROM "res_company_users_rel" WHERE "cid" IN (
SELECT "res_company".id
FROM "res_company"
WHERE ("res_company"."name"::text LIKE %s)
ORDER BY "res_company"."sequence", "res_company"."name"
)
))
ORDER BY "res_users"."id"
''']):
@@ -136,12 +136,12 @@ class TestPerformance(SavepointCaseWithUserDemo):
# delete N lines: O(1) queries
rec1.invalidate_cache()
with self.assertQueryCount(__system__=16, demo=16):
with self.assertQueryCount(__system__=14, demo=14):
rec1.write({'line_ids': [(2, line.id) for line in lines[0]]})
self.assertEqual(rec1.line_ids, lines[1:])
rec1.invalidate_cache()
with self.assertQueryCount(__system__=14, demo=14):
with self.assertQueryCount(__system__=12, demo=12):
rec1.write({'line_ids': [(2, line.id) for line in lines[1:]]})
self.assertFalse(rec1.line_ids)
self.assertFalse(lines.exists())
@@ -151,12 +151,12 @@ class TestPerformance(SavepointCaseWithUserDemo):
# unlink N lines: O(1) queries
rec1.invalidate_cache()
with self.assertQueryCount(__system__=13, demo=13):
with self.assertQueryCount(__system__=11, demo=11):
rec1.write({'line_ids': [(3, line.id) for line in lines[0]]})
self.assertEqual(rec1.line_ids, lines[1:])
rec1.invalidate_cache()
with self.assertQueryCount(__system__=14, demo=14):
with self.assertQueryCount(__system__=12, demo=12):
rec1.write({'line_ids': [(3, line.id) for line in lines[1:]]})
self.assertFalse(rec1.line_ids)
self.assertFalse(lines.exists())
@@ -190,7 +190,7 @@ class TestPerformance(SavepointCaseWithUserDemo):
# empty N lines in rec2: O(1) queries
rec1.invalidate_cache()
with self.assertQueryCount(__system__=15, demo=15):
with self.assertQueryCount(__system__=13, demo=13):
rec2.write({'line_ids': [(5,)]})
self.assertFalse(rec2.line_ids)
@@ -262,12 +262,12 @@ class TestPerformance(SavepointCaseWithUserDemo):
# delete N tags: O(1) queries
rec1.invalidate_cache()
with self.assertQueryCount(__system__=10, demo=10):
with self.assertQueryCount(__system__=8, demo=8):
rec1.write({'tag_ids': [(2, tag.id) for tag in tags[0]]})
self.assertEqual(rec1.tag_ids, tags[1:])
rec1.invalidate_cache()
with self.assertQueryCount(__system__=10, demo=10):
with self.assertQueryCount(__system__=8, demo=8):
rec1.write({'tag_ids': [(2, tag.id) for tag in tags[1:]]})
self.assertFalse(rec1.tag_ids)
self.assertFalse(tags.exists())
+5 -8
View File
@@ -4397,14 +4397,11 @@ Fields:
res = self._cr.fetchone()
return res[0]
order_by = self._generate_order_by(order, query)
from_clause, where_clause, where_clause_params = query.get_sql()
where_str = where_clause and (" WHERE %s" % where_clause) or ''
limit_str = limit and ' limit %d' % limit or ''
offset_str = offset and ' offset %d' % offset or ''
query_str = 'SELECT "%s".id FROM ' % self._table + from_clause + where_str + order_by + limit_str + offset_str
self._cr.execute(query_str, where_clause_params)
return [row[0] for row in self._cr.fetchall()]
query.order = self._generate_order_by(order, query).replace('ORDER BY ', '')
query.limit = limit
query.offset = offset
return query
@api.returns(None, lambda value: value[0])
def copy_data(self, default=None):
+26 -11
View File
@@ -225,9 +225,9 @@ def is_false(model, domain):
stack.append(+1)
elif token == FALSE_LEAF:
stack.append(-1)
elif token[1] == 'in' and not token[2]:
elif token[1] == 'in' and not (isinstance(token[2], Query) or token[2]):
stack.append(-1)
elif token[1] == 'not in' and not token[2]:
elif token[1] == 'not in' and not (isinstance(token[2], Query) or token[2]):
stack.append(+1)
else:
stack.append(0)
@@ -740,10 +740,14 @@ class expression(object):
ids2 = right
else:
ids2 = [right]
if ids2 and inverse_is_int and domain:
if inverse_is_int and domain:
ids2 = comodel._search([('id', 'in', ids2)] + domain, order='id')
if ids2 and comodel._fields[field.inverse_name].store:
if isinstance(ids2, Query) and comodel._fields[field.inverse_name].store:
op1 = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect'
subquery, subparams = ids2.select('"%s"."%s"' % (comodel._table, field.inverse_name))
push(('id', op1, (subquery, subparams)), model, alias, internal=True)
elif ids2 and comodel._fields[field.inverse_name].store:
op1 = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect'
subquery = 'SELECT "%s" FROM "%s" WHERE "id" IN %%s' % (field.inverse_name, comodel._table)
subparams = [tuple(ids2)]
@@ -801,11 +805,18 @@ class expression(object):
else:
ids2 = [right]
# rewrite condition in terms of ids2
subop = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect'
subquery = 'SELECT "%s" FROM "%s" WHERE "%s" IN %%s' % (rel_id1, rel_table, rel_id2)
ids2 = tuple(it for it in ids2 if it) or (None,)
push(('id', subop, (subquery, [ids2])), model, alias, internal=True)
if isinstance(ids2, Query):
# rewrite condition in terms of ids2
subop = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect'
subquery, subparams = ids2.select()
query = 'SELECT "%s" FROM "%s" WHERE "%s" IN (%s)' % (rel_id1, rel_table, rel_id2, subquery)
push(('id', subop, (query, subparams)), model, alias, internal=True)
else:
# rewrite condition in terms of ids2
subop = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect'
subquery = 'SELECT "%s" FROM "%s" WHERE "%s" IN %%s' % (rel_id1, rel_table, rel_id2)
ids2 = tuple(it for it in ids2 if it) or (None,)
push(('id', subop, (subquery, [ids2])), model, alias, internal=True)
else:
# rewrite condition to match records with/without relations
@@ -836,11 +847,11 @@ class expression(object):
operator = dict_op[operator]
res_ids = comodel.with_context(active_test=False)._name_search(right, [], operator, limit=None)
if operator in NEGATIVE_TERM_OPERATORS:
res_ids.append(False) # TODO this should not be appended if False was in 'right'
res_ids = list(res_ids) + [False] # TODO this should not be appended if False was in 'right'
return left, 'in', res_ids
# resolve string-based m2o criterion into IDs
if isinstance(right, str) or \
right and isinstance(right, (tuple, list)) and all(isinstance(item, str) for item in right):
isinstance(right, (tuple, list)) and right and all(isinstance(item, str) for item in right):
push(_get_expression(comodel, left, right, operator), model, alias)
else:
# right == [] or right == False and all other cases are handled by __leaf_to_sql()
@@ -954,6 +965,10 @@ class expression(object):
else:
query = '(%s."%s" IS NULL)' % (table_alias, left)
params = []
elif isinstance(right, Query):
subquery, subparams = right.select()
query = '(%s."%s" %s (%s))' % (table_alias, left, operator, subquery)
params = subparams
elif isinstance(right, (list, tuple)):
if model._fields[left].type == "boolean":
params = [it for it in (True, False) if it in right]