Skip to content

Commit

Permalink
Add missing constraints for read_status in ReadThrough
Browse files Browse the repository at this point in the history
  • Loading branch information
dato committed Nov 13, 2023
1 parent 009c290 commit b1ce562
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 11 deletions.
37 changes: 37 additions & 0 deletions bookwyrm/migrations/0152_readthrough_read_status_constraints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Generated by Django 3.2.20 on 2023-11-13 23:12

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("bookwyrm", "0152_readthrough_stopped_date_remove"),
]

operations = [
migrations.AddConstraint(
model_name="readthrough",
constraint=models.CheckConstraint(
check=models.Q(
("finish_date__isnull", False),
("read_status", "reading"),
_negated=True,
),
name="currently-reading",
),
),
migrations.AddConstraint(
model_name="readthrough",
constraint=models.CheckConstraint(
check=models.Q(
models.Q(("read_status", "to-read"), _negated=True),
models.Q(
("finish_date__isnull", True), ("start_date__isnull", True)
),
_connector="OR",
),
name="to-read",
),
),
]
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def unmerge_finish_stopped_dates(apps, schema_editor):
class Migration(migrations.Migration):

dependencies = [
("bookwyrm", "0151_auto_20220703_1842"),
("bookwyrm", "0152_readthrough_read_status_add"),
]

operations = [
Expand Down
13 changes: 9 additions & 4 deletions bookwyrm/models/readthrough.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,16 @@ class Meta:
),
# Can't be actively reading the same book twice
# Currently reading status can't have stopped date
# models.CheckConstraint(
# check=~Q(read_status="to-read", finish_date__isnull=False),
# name="currently-reading"
# ),
models.CheckConstraint(
name="currently-reading",
check=~Q(read_status="reading", finish_date__isnull=False),
),
# Can't want to read and have started or finished dates
models.CheckConstraint(
name="to-read",
check=~Q(read_status="to-read")
| Q(start_date__isnull=True, finish_date__isnull=True),
),
]
ordering = ("-start_date",)

Expand Down
42 changes: 36 additions & 6 deletions bookwyrm/tests/models/test_readthrough_model.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
""" testing models """
import datetime
from datetime import timedelta
from unittest.mock import patch
from django.test import TestCase
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from django.db import IntegrityError, transaction
from django.utils import timezone

from bookwyrm import models
Expand All @@ -28,30 +28,60 @@ def setUp(self):


class ReadThroughConstraints(ReadThroughTestBase):
def _assert_create(self, start_date=None, finish_date=None, /):
def _assert_create(self, start_date, finish_date=None, /, read_status="read"):
"""create ReadThrough helper"""
self.assertIsNotNone(
models.ReadThrough.objects.create(
user=self.user,
book=self.edition,
start_date=start_date,
finish_date=finish_date,
read_status=read_status,
)
)

def _fail_create(self, start_date, finish_date, /, read_status):
"""expected failure in ReadThrough creation"""
with self.assertRaises(IntegrityError):
self._assert_create(start_date, finish_date, read_status)

def test_valid_dates(self):
"""valid combinations of start_date and finish_date"""
start = timezone.now()

self._assert_create(None, None)
self._assert_create(start, None)
self._assert_create(None, start)
self._assert_create(start, start + datetime.timedelta(days=1))
self._assert_create(start, start + timedelta(days=1))
self._assert_create(start, start)

self._assert_create(None, None, "to-read")
self._assert_create(None, None, "reading")
self._assert_create(start, None, "reading")

def test_chronology_constraint(self):
"""finish_date >= start_date"""
start = timezone.now()
with self.assertRaises(IntegrityError):
self._assert_create(start, start - datetime.timedelta(days=2))
before_start = start - timedelta(days=2)

self._fail_create(start, before_start, "read")

def test_currently_reading_constraint(self):
"""no finish date allowed for `reading`"""
start = finish = timezone.now()
self._fail_create(start, finish, "reading")

def test_to_read_constraint(self):
"""no dates allowed for `to-read`"""
start = finish = timezone.now()
test_cases = [
("start date", start, None),
("finish date", None, start),
("start and finish", start, finish),
]
for desc, beg, end in test_cases:
with self.subTest(desc), transaction.atomic():
self._fail_create(beg, end, "to-read")


class ReadThroughProgressUpdates(ReadThroughTestBase):
Expand Down

0 comments on commit b1ce562

Please sign in to comment.