Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions caluma/caluma_form/historical_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
from .storage_clients import client


def filter_as_of_deleted(items, exclude_deleted=False):
if not exclude_deleted:
return items

return [item for item in items if item.history_type != "-"]


def historical_qs_as_of(queryset, date, pk_attr):
"""Get history revision as of `date` for queryset.

Expand Down Expand Up @@ -121,14 +128,17 @@ class HistoricalFilesAnswer(FilesAnswer):
HistoricalFile,
required=False,
as_of=graphene.types.datetime.DateTime(required=True),
exclude_deleted=graphene.Boolean(default_value=False),
)

def resolve_value(self, info, as_of, **args):
def resolve_value(self, info, as_of, exclude_deleted=False, **args):
# we need to use the HistoricalFile of the correct revision
return historical_qs_as_of(models.File.history, as_of, pk_attr="id").filter(
qs = historical_qs_as_of(models.File.history, as_of, pk_attr="id").filter(
answer_id=self.id
)

return filter_as_of_deleted(qs, exclude_deleted)

class Meta:
model = models.Answer.history.model
exclude = ("document", "date")
Expand All @@ -140,6 +150,7 @@ class HistoricalDocument(FormDjangoObjectType):
historical_answers = ConnectionField(
HistoricalAnswerConnection,
as_of=graphene.types.datetime.DateTime(required=True),
exclude_deleted=graphene.Boolean(default_value=False),
)
history_date = graphene.types.datetime.DateTime(required=True)
history_user_id = graphene.String()
Expand All @@ -150,11 +161,13 @@ class HistoricalDocument(FormDjangoObjectType):
def resolve_document_id(self, info, *args, **kwargs):
return self.id

def resolve_historical_answers(self, info, as_of, *args, **kwargs):
return historical_qs_as_of(
def resolve_historical_answers(self, info, as_of, exclude_deleted=False, **args):
qs = historical_qs_as_of(
models.Answer.history.filter(document_id=self.id), as_of, "id"
)

return filter_as_of_deleted(qs, exclude_deleted)

class Meta:
model = models.Document.history.model
exclude = ("family", "history_id", "history_change_reason")
Expand All @@ -167,9 +180,10 @@ class HistoricalTableAnswer(TableAnswer):
HistoricalDocument,
required=False,
as_of=graphene.types.datetime.DateTime(required=True),
exclude_deleted=graphene.Boolean(default_value=False),
)

def resolve_value(self, info, as_of, *args):
def resolve_value(self, info, as_of, exclude_deleted=False, **args):
answerdocuments_unordered = historical_qs_as_of(
models.AnswerDocument.history.filter(answer_id=self.id), as_of, "id"
)
Expand All @@ -178,13 +192,15 @@ def resolve_value(self, info, as_of, *args):
answerdocuments = models.AnswerDocument.history.filter(
pk__in=answerdocuments_unordered
).order_by("sort")
answerdocuments = filter_as_of_deleted(answerdocuments, exclude_deleted)

documents = [
models.Document.history.filter(
id=ad.document_id, history_date__lte=as_of
).latest("history_date")
for ad in answerdocuments
]
documents = filter_as_of_deleted(documents, exclude_deleted)

# Since python 3.6, `list(dict.fromkeys(somelist))` is the most performant way
# to remove duplicates from a list, while retaining it's order.
Expand All @@ -201,10 +217,13 @@ class Meta:
interfaces = (HistoricalAnswer, graphene.Node)


def document_as_of(info, document_global_id, timestamp):
def document_as_of(info, document_global_id, timestamp, exclude_deleted=False):
document_id = extract_global_id(document_global_id)
document_qs = HistoricalDocument.get_queryset(models.Document.history.all(), info)
document = document_qs.filter(id=document_id, history_date__lte=timestamp).first()
if exclude_deleted and document and document.history_type == "-":
document = None

if not document:
raise Http404("No HistoricalDocument matches the given query.")
return document
Expand All @@ -215,10 +234,11 @@ class Query:
HistoricalDocument,
id=graphene.ID(required=True),
as_of=graphene.types.datetime.DateTime(required=True),
exclude_deleted=graphene.Boolean(default_value=False),
)

def resolve_document_as_of(self, info, id, as_of):
return document_as_of(info, id, as_of)
def resolve_document_as_of(self, info, id, as_of, exclude_deleted=False):
return document_as_of(info, id, as_of, exclude_deleted)


HISTORICAL_ANSWER_TYPES = {
Expand Down
141 changes: 140 additions & 1 deletion caluma/caluma_form/tests/__snapshots__/test_history.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
dict({
'node': dict({
'__typename': 'HistoricalStringAnswer',
'historyType': '+',
'historyUserId': 'admin',
'value': 'first admin - revision 1',
}),
Expand All @@ -28,6 +29,7 @@
dict({
'node': dict({
'__typename': 'HistoricalStringAnswer',
'historyType': '~',
'historyUserId': 'AnonymousUser',
'value': 'first anon - revision 3',
}),
Expand All @@ -48,6 +50,7 @@
dict({
'node': dict({
'__typename': 'HistoricalStringAnswer',
'historyType': '~',
'historyUserId': 'AnonymousUser',
'value': 'second anon - revision 4',
}),
Expand All @@ -59,14 +62,70 @@
}),
})
# ---
# name: test_historical_table_answer
# name: test_document_as_of.3
dict({
'documentAsOf': dict({
'documentId': '890ca108-d93d-4725-9066-7d0bddad8230',
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'__typename': 'HistoricalStringAnswer',
'historyType': '-',
'historyUserId': 'AnonymousUser',
'value': 'second anon - revision 4',
}),
}),
]),
}),
'meta': dict({
}),
}),
})
# ---
# name: test_document_as_of.4
dict({
'documentAsOf': dict({
'documentId': '890ca108-d93d-4725-9066-7d0bddad8230',
'historicalAnswers': dict({
'edges': list([
]),
}),
'meta': dict({
}),
}),
})
# ---
# name: test_document_as_of.5
dict({
'documentAsOf': dict({
'documentId': '890ca108-d93d-4725-9066-7d0bddad8230',
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'__typename': 'HistoricalStringAnswer',
'historyType': '-',
'historyUserId': 'AnonymousUser',
'value': 'second anon - revision 4',
}),
}),
]),
}),
'meta': dict({
}),
}),
})
# ---
# name: test_historical_table_answer[False]
dict({
'd1': dict({
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'__typename': 'HistoricalTableAnswer',
'historyType': '+',
'value': list([
dict({
'historicalAnswers': dict({
Expand All @@ -79,6 +138,7 @@
}),
]),
}),
'historyType': '+',
}),
dict({
'historicalAnswers': dict({
Expand All @@ -91,19 +151,22 @@
}),
]),
}),
'historyType': '+',
}),
]),
}),
}),
]),
}),
'historyType': '+',
}),
'd2': dict({
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'__typename': 'HistoricalTableAnswer',
'historyType': '+',
'value': list([
dict({
'historicalAnswers': dict({
Expand All @@ -116,6 +179,7 @@
}),
]),
}),
'historyType': '+',
}),
dict({
'historicalAnswers': dict({
Expand All @@ -128,12 +192,87 @@
}),
]),
}),
'historyType': '-',
}),
]),
}),
}),
]),
}),
'historyType': '+',
}),
})
# ---
# name: test_historical_table_answer[True]
dict({
'd1': dict({
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'__typename': 'HistoricalTableAnswer',
'historyType': '+',
'value': list([
dict({
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'historyType': '+',
'value': 'first row value',
}),
}),
]),
}),
'historyType': '+',
}),
dict({
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'historyType': '+',
'value': 'second row value',
}),
}),
]),
}),
'historyType': '+',
}),
]),
}),
}),
]),
}),
'historyType': '+',
}),
'd2': dict({
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'__typename': 'HistoricalTableAnswer',
'historyType': '+',
'value': list([
dict({
'historicalAnswers': dict({
'edges': list([
dict({
'node': dict({
'historyType': '+',
'value': 'first row value',
}),
}),
]),
}),
'historyType': '+',
}),
]),
}),
}),
]),
}),
'historyType': '+',
}),
})
# ---
Loading
Loading