Skip to content

Commit

Permalink
🐛 [#324] Fixed retrieval of overlapping objects by filtering with exc…
Browse files Browse the repository at this point in the history
…lusive end date.
  • Loading branch information
alextreme authored and joeribekker committed Apr 3, 2023
1 parent 45ea40c commit 77056dc
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 12 deletions.
8 changes: 4 additions & 4 deletions src/objects/api/v1/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -654,12 +654,12 @@ components:
startAt:
type: string
format: date
description: Legal start date of the object record
description: Legal start date of the object record (inclusive)
endAt:
type: string
format: date
readOnly: true
description: Legal end date of the object record
description: Legal end date of the object record (exclusive)
registrationAt:
type: string
format: date
Expand Down Expand Up @@ -801,12 +801,12 @@ components:
startAt:
type: string
format: date
description: Legal start date of the object record
description: Legal start date of the object record (inclusive)
endAt:
type: string
format: date
readOnly: true
description: Legal end date of the object record
description: Legal end date of the object record (exclusive)
registrationAt:
type: string
format: date
Expand Down
8 changes: 4 additions & 4 deletions src/objects/api/v2/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -742,12 +742,12 @@ components:
startAt:
type: string
format: date
description: Legal start date of the object record
description: Legal start date of the object record (inclusive)
endAt:
type: string
format: date
readOnly: true
description: Legal end date of the object record
description: Legal end date of the object record (exclusive)
registrationAt:
type: string
format: date
Expand Down Expand Up @@ -894,12 +894,12 @@ components:
startAt:
type: string
format: date
description: Legal start date of the object record
description: Legal start date of the object record (inclusive)
endAt:
type: string
format: date
readOnly: true
description: Legal end date of the object record
description: Legal end date of the object record (exclusive)
registrationAt:
type: string
format: date
Expand Down
30 changes: 30 additions & 0 deletions src/objects/core/migrations/0028_auto_20230331_1239.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 2.2.28 on 2023-03-31 10:39

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0027_auto_20211203_1209"),
]

operations = [
migrations.AlterField(
model_name="objectrecord",
name="end_at",
field=models.DateField(
help_text="Legal end date of the object record (exclusive)",
null=True,
verbose_name="end at",
),
),
migrations.AlterField(
model_name="objectrecord",
name="start_at",
field=models.DateField(
help_text="Legal start date of the object record (inclusive)",
verbose_name="start at",
),
),
]
6 changes: 4 additions & 2 deletions src/objects/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,12 @@ class ObjectRecord(models.Model):
encoder=DjangoJSONEncoder,
)
start_at = models.DateField(
_("start at"), help_text=_("Legal start date of the object record")
_("start at"), help_text=_("Legal start date of the object record (inclusive)")
)
end_at = models.DateField(
_("end at"), null=True, help_text=_("Legal end date of the object record")
_("end at"),
null=True,
help_text=_("Legal end date of the object record (exclusive)"),
)
registration_at = models.DateField(
_("registration at"),
Expand Down
4 changes: 2 additions & 2 deletions src/objects/core/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def filter_for_date(self, date):
return (
self.filter(records__start_at__lte=date)
.filter(
models.Q(records__end_at__gte=date)
models.Q(records__end_at__gt=date)
| models.Q(records__end_at__isnull=True)
)
.distinct()
Expand Down Expand Up @@ -59,7 +59,7 @@ def filter_for_date(self, date):
"""
return self.filter(start_at__lte=date).filter(
models.Q(end_at__gte=date) | models.Q(end_at__isnull=True)
models.Q(end_at__gt=date) | models.Q(end_at__isnull=True)
)

def filter_for_registration_date(self, date):
Expand Down
47 changes: 47 additions & 0 deletions src/objects/tests/v2/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,53 @@ def test_filter_exclude_old_records(self):
data = response.json()["results"]
self.assertEqual(len(data), 0)

response = self.client.get(self.url, {"data_attrs": "diameter__exact__50"})

self.assertEqual(response.status_code, status.HTTP_200_OK)

data = response.json()["results"]
self.assertEqual(len(data), 1)

def test_filter_exclude_old_records_issue_324(self):
"""
Filter and conflict resolution.
If record A ends at X and a newer record B starts at X, both match on
date X. Normally, conflict resolution returns only record B. However,
when you add a filter, it first finds the record matching this filter.
If the filter only results in record A, there are no conflicts and
record A is returned.
"""
record_old = ObjectRecordFactory.create(
data={"adres": {"straat": "Bospad"}},
object__object_type=self.object_type,
start_at=date.today() - timedelta(days=1),
end_at=date.today(),
)
record_new = ObjectRecordFactory.create(
data={"adres": {"straat": "Dorpsstraat"}},
object=record_old.object,
start_at=record_old.end_at,
)

response = self.client.get(
self.url, {"data_attrs": "adres__straat__exact__Bospad"}
)

self.assertEqual(response.status_code, status.HTTP_200_OK)

data = response.json()["results"]
self.assertEqual(len(data), 0)

response = self.client.get(
self.url, {"data_attrs": "adres__straat__exact__Dorpsstraat"}
)

self.assertEqual(response.status_code, status.HTTP_200_OK)

data = response.json()["results"]
self.assertEqual(len(data), 1)

def test_filter_date_field_gte(self):
record = ObjectRecordFactory.create(
data={"dateField": "2000-10-10"}, object__object_type=self.object_type
Expand Down
72 changes: 72 additions & 0 deletions src/objects/tests/v2/test_object_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,75 @@ def test_updating_object_after_changing_the_startAt_value_returns_200(self, m):
response_updating_data_after_startAt_modification.status_code,
status.HTTP_200_OK,
)


@requests_mock.Mocker()
class ObjectApiTodayTests(TokenAuthMixin, APITestCase):
maxDiff = None

@classmethod
def setUpTestData(cls):
super().setUpTestData()

cls.object_type = ObjectTypeFactory(service__api_root=OBJECT_TYPES_API)
PermissionFactory.create(
object_type=cls.object_type,
mode=PermissionModes.read_and_write,
token_auth=cls.token_auth,
)

def test_update_object_issue_324(self, m):
mock_service_oas_get(m, OBJECT_TYPES_API, "objecttypes")
m.get(
f"{self.object_type.url}/versions/1",
json=mock_objecttype_version(self.object_type.url),
)
m.get(self.object_type.url, json=mock_objecttype(self.object_type.url))
today = date.today()

data = {
"type": self.object_type.url,
"record": {
"typeVersion": 1,
"data": {"adres": {"straat": "Bospad"}, "diameter": 30},
"startAt": today,
},
}
url = reverse("object-list")
response = self.client.post(url, data, **GEO_WRITE_KWARGS)

self.assertEqual(response.status_code, status.HTTP_201_CREATED)
object = Object.objects.get()

url = reverse("object-detail", args=[object.uuid])
data = {
"type": object.object_type.url,
"record": {
"typeVersion": 1,
"data": {"adres": {"straat": "Dorpsstraat"}, "diameter": 30},
"startAt": today,
},
}

response = self.client.put(url, data, **GEO_WRITE_KWARGS)
self.assertEqual(response.status_code, status.HTTP_200_OK)

object.refresh_from_db()
self.assertEqual(object.object_type, self.object_type)
self.assertEqual(object.records.count(), 2)
url = reverse("object-list")
response = self.client.get(url, {"data_attrs": "adres__straat__exact__Bospad"})

self.assertEqual(response.status_code, status.HTTP_200_OK)

data = response.json()["results"]
self.assertEqual(len(data), 0)

response = self.client.get(
url, {"data_attrs": "adres__straat__exact__Dorpsstraat"}
)

self.assertEqual(response.status_code, status.HTTP_200_OK)

data = response.json()["results"]
self.assertEqual(len(data), 1)

0 comments on commit 77056dc

Please sign in to comment.