From 19502fca854e943d852ac89de66e878635ea02a6 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Wed, 8 Jan 2025 16:31:26 -0500 Subject: [PATCH] add test_contained_by_subquery (broken) --- django_mongodb_backend/fields/array.py | 8 ++- tests/model_fields_/test_arrayfield.py | 74 ++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/django_mongodb_backend/fields/array.py b/django_mongodb_backend/fields/array.py index c60b65a2..860233be 100644 --- a/django_mongodb_backend/fields/array.py +++ b/django_mongodb_backend/fields/array.py @@ -260,7 +260,13 @@ class ArrayContainedBy(ArrayRHSMixin, FieldGetDbPrepValueMixin, Lookup): def as_mql(self, compiler, connection): lhs_mql = process_lhs(self, compiler, connection) value = process_rhs(self, compiler, connection) - return {"$and": [{"$ne": [lhs_mql, None]}, {"$setIsSubset": [lhs_mql, value]}]} + return { + "$and": [ + {"$ne": [lhs_mql, None]}, + {"$ne": [value, None]}, + {"$setIsSubset": [lhs_mql, value]}, + ] + } @ArrayField.register_lookup diff --git a/tests/model_fields_/test_arrayfield.py b/tests/model_fields_/test_arrayfield.py index 39ac55c3..a6c359cf 100644 --- a/tests/model_fields_/test_arrayfield.py +++ b/tests/model_fields_/test_arrayfield.py @@ -369,6 +369,80 @@ def test_contains_subquery(self): self.objs[1:3], ) + def test_contained_by_subquery(self): + IntegerArrayModel.objects.create(field=[2, 3]) + inner_qs = IntegerArrayModel.objects.values_list("field", flat=True) + self.assertSequenceEqual( + NullableIntegerArrayModel.objects.filter(field__contained_by=inner_qs[:1]), + self.objs[1:3], + ) + IntegerArrayModel.objects.create(field=[2]) + inner_qs = IntegerArrayModel.objects.filter(field__contained_by=OuterRef("field")) + # fails with "both operands of $setIsSubset must be arrays. Second + # argument is of type: null" + self.assertSequenceEqual( + NullableIntegerArrayModel.objects.filter(Exists(inner_qs)), + self.objs[1:3], + ) + + # [ + # { + # "$lookup": { + # "as": "__subquery0", + # "from": "model_fields__integerarraymodel", + # "let": {"parent__field__0": "$field"}, + # "pipeline": [ + # { + # "$match": { + # "$expr": { + # "$and": [ + # {"$ne": ["$field", None]}, + # {"$ne": ["$$parent__field__0", None]}, + # {"$setIsSubset": ["$field", "$$parent__field__0"]}, + # ] + # } + # } + # }, + # {"$project": {"a": {"$literal": 1}}}, + # {"$limit": 1}, + # ], + # } + # }, + # { + # "$set": { + # "__subquery0": { + # "$cond": { + # "if": { + # "$or": [ + # {"$eq": [{"$type": "$__subquery0"}, "missing"]}, + # {"$eq": [{"$size": "$__subquery0"}, 0]}, + # ] + # }, + # "then": {}, + # "else": {"$arrayElemAt": ["$__subquery0", 0]}, + # } + # } + # } + # }, + # { + # "$match": { + # "$expr": { + # "$eq": [ + # { + # "$not": { + # "$or": [ + # {"$eq": [{"$type": "$__subquery0.a"}, "missing"]}, + # {"$eq": ["$__subquery0.a", None]}, + # ] + # } + # }, + # True, + # ] + # } + # } + # }, + # ] + def test_contains_including_expression(self): self.assertSequenceEqual( NullableIntegerArrayModel.objects.filter(