fix(db): scope row locks to base records
This commit is contained in:
parent
716c8337de
commit
e421a1b55c
@ -178,7 +178,7 @@ def create_qr_login_token(
|
||||
def exchange_qr_login_token(*, raw_token: str, request) -> tuple[str, str]:
|
||||
token_hash = hash_qr_login_token(raw_token)
|
||||
qr_token = (
|
||||
QrLoginToken.objects.select_for_update()
|
||||
QrLoginToken.objects.select_for_update(of=("self",))
|
||||
.select_related("user")
|
||||
.filter(token_hash=token_hash)
|
||||
.first()
|
||||
@ -330,7 +330,7 @@ def poll_qr_login_request(
|
||||
request,
|
||||
) -> dict[str, str | None]:
|
||||
qr_request = (
|
||||
QrLoginRequest.objects.select_for_update()
|
||||
QrLoginRequest.objects.select_for_update(of=("self",))
|
||||
.select_related("approved_by")
|
||||
.filter(
|
||||
client_secret_hash=hash_qr_login_request_client_secret(raw_client_secret),
|
||||
|
||||
@ -150,7 +150,9 @@ def _audit_api_mutation(*, actor, action, instance, period=None, metadata=None):
|
||||
|
||||
def _lock_period_accepting_draft_edits(period_id):
|
||||
period = get_object_or_404(
|
||||
PayrollPeriod.objects.select_for_update().select_related("current_run"),
|
||||
PayrollPeriod.objects.select_for_update(of=("self",)).select_related(
|
||||
"current_run"
|
||||
),
|
||||
pk=period_id,
|
||||
)
|
||||
if period.status == PayrollPeriodStatus.CLOSED:
|
||||
@ -699,7 +701,12 @@ class DraftDetailView(PayrollAdminAPIView):
|
||||
period = _lock_period_accepting_draft_edits(reference.period_id)
|
||||
else:
|
||||
period = None
|
||||
instance = get_object_or_404(scoped_queryset.select_for_update())
|
||||
# Read serializers join nullable audit/revision relations. PostgreSQL
|
||||
# cannot apply FOR UPDATE to the nullable side of those outer joins,
|
||||
# and only the draft itself needs to be locked here.
|
||||
instance = get_object_or_404(
|
||||
scoped_queryset.select_for_update(of=("self",))
|
||||
)
|
||||
if period is not None:
|
||||
instance._state.fields_cache["period"] = period
|
||||
self.validate_period_update(instance, period)
|
||||
@ -1001,7 +1008,9 @@ class EmployeePayRateReviseView(PayrollAdminAPIView):
|
||||
def post(self, request, pk):
|
||||
self.require_permission(request, PAYROLL_PERMISSIONS["manage_inputs"])
|
||||
source = get_object_or_404(
|
||||
EmployeePayRate.objects.select_for_update().select_related("employee"),
|
||||
EmployeePayRate.objects.select_for_update(of=("self",)).select_related(
|
||||
"employee"
|
||||
),
|
||||
pk=pk,
|
||||
status=ApprovalStatus.APPROVED,
|
||||
)
|
||||
@ -1071,7 +1080,7 @@ class PayrollWorkRecordReviseView(PayrollAdminAPIView):
|
||||
)
|
||||
period = _lock_period_accepting_draft_edits(reference.period_id)
|
||||
source = get_object_or_404(
|
||||
PayrollWorkRecord.objects.select_for_update().select_related(
|
||||
PayrollWorkRecord.objects.select_for_update(of=("self",)).select_related(
|
||||
"period", "employee"
|
||||
),
|
||||
pk=pk,
|
||||
|
||||
@ -600,7 +600,7 @@ class TaskViewSet(viewsets.ModelViewSet):
|
||||
visible_task = self.get_object()
|
||||
with transaction.atomic():
|
||||
task = (
|
||||
Task.objects.select_for_update()
|
||||
Task.objects.select_for_update(of=("self",))
|
||||
.select_related("board", "column", "assignee")
|
||||
.get(id=visible_task.id)
|
||||
)
|
||||
|
||||
@ -433,8 +433,10 @@ def build_attendance_work_preview(
|
||||
"employee", "employee__position", "created_by"
|
||||
)
|
||||
if lock:
|
||||
attendance = attendance.select_for_update()
|
||||
work = work.select_for_update()
|
||||
# Both projections contain nullable outer joins (analysis run and
|
||||
# employee position). Lock only the source rows being imported.
|
||||
attendance = attendance.select_for_update(of=("self",))
|
||||
work = work.select_for_update(of=("self",))
|
||||
attendance_records = list(attendance.order_by("employee_id", "date", "id"))
|
||||
work_records = list(work.order_by("employee_id", "revision", "id"))
|
||||
|
||||
@ -594,7 +596,7 @@ def apply_attendance_work_preview(
|
||||
)
|
||||
|
||||
period = (
|
||||
PayrollPeriod.objects.select_for_update()
|
||||
PayrollPeriod.objects.select_for_update(of=("self",))
|
||||
.select_related("current_run")
|
||||
.get(pk=period_id)
|
||||
)
|
||||
|
||||
@ -757,7 +757,7 @@ def bulk_set_point_rate(
|
||||
|
||||
selected_employee_ids = sorted(set(employee_ids))
|
||||
rates = list(
|
||||
EmployeePayRate.objects.select_for_update()
|
||||
EmployeePayRate.objects.select_for_update(of=("self",))
|
||||
.filter(
|
||||
employee_id__in=selected_employee_ids,
|
||||
rate_code=base_rate_code(),
|
||||
@ -984,7 +984,7 @@ def bulk_set_pay_rate(
|
||||
).order_by("pk")
|
||||
}
|
||||
rates = list(
|
||||
EmployeePayRate.objects.select_for_update()
|
||||
EmployeePayRate.objects.select_for_update(of=("self",))
|
||||
.filter(
|
||||
employee_id__in=employees,
|
||||
rate_code=base_rate_code(),
|
||||
@ -1374,7 +1374,7 @@ def save_own_daily_work_entry(
|
||||
"Для сохранения выработки необходимо войти в систему.",
|
||||
)
|
||||
period = (
|
||||
PayrollPeriod.objects.select_for_update()
|
||||
PayrollPeriod.objects.select_for_update(of=("self",))
|
||||
.select_related("current_run")
|
||||
.get(pk=period_id)
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user