|
1 |
| -# Copyright © 2023 Ingram Micro Inc. All rights reserved. |
| 1 | +# Copyright © 2024 Ingram Micro Inc. All rights reserved. |
2 | 2 |
|
3 | 3 | import logging
|
| 4 | +from collections import defaultdict |
| 5 | +from contextlib import ContextDecorator |
4 | 6 | from datetime import date, datetime, timedelta
|
5 | 7 | from uuid import UUID
|
6 | 8 |
|
|
10 | 12 |
|
11 | 13 | from dj_cqrs.constants import DB_VENDOR_PG, SUPPORTED_TIMEOUT_DB_VENDORS
|
12 | 14 | from dj_cqrs.logger import install_last_query_capturer
|
| 15 | +from dj_cqrs.state import cqrs_state |
13 | 16 |
|
14 | 17 |
|
15 | 18 | logger = logging.getLogger('django-cqrs')
|
@@ -80,3 +83,60 @@ def apply_query_timeouts(model_cls): # pragma: no cover
|
80 | 83 | cursor.execute(statement, params=(query_timeout,))
|
81 | 84 |
|
82 | 85 | install_last_query_capturer(model_cls)
|
| 86 | + |
| 87 | + |
| 88 | +class _BulkRelateCM(ContextDecorator): |
| 89 | + def __init__(self, cqrs_id=None): |
| 90 | + self._cqrs_id = cqrs_id |
| 91 | + self._mapping = defaultdict(lambda: defaultdict(set)) |
| 92 | + self._cache = {} |
| 93 | + |
| 94 | + def register(self, instance, using=None): |
| 95 | + instance_cqrs_id = getattr(instance, 'CQRS_ID', None) |
| 96 | + if (not instance_cqrs_id) or (self._cqrs_id and instance_cqrs_id != self._cqrs_id): |
| 97 | + return |
| 98 | + |
| 99 | + self._mapping[instance_cqrs_id][using].add(instance.pk) |
| 100 | + |
| 101 | + def get_cached_instance(self, instance, using=None): |
| 102 | + instance_cqrs_id = getattr(instance, 'CQRS_ID', None) |
| 103 | + if (not instance_cqrs_id) or (self._cqrs_id and instance_cqrs_id != self._cqrs_id): |
| 104 | + return |
| 105 | + |
| 106 | + instance_pk = instance.pk |
| 107 | + cached_instances = self._cache.get(instance_cqrs_id, {}).get(using, {}) |
| 108 | + if cached_instances: |
| 109 | + return cached_instances.get(instance_pk) |
| 110 | + |
| 111 | + cached_pks = self._mapping[instance_cqrs_id][using] |
| 112 | + if not cached_pks: |
| 113 | + return |
| 114 | + |
| 115 | + qs = instance.__class__._default_manager.using(using) |
| 116 | + instances_cache = { |
| 117 | + instance.pk: instance |
| 118 | + for instance in instance.__class__.relate_cqrs_serialization(qs) |
| 119 | + .filter( |
| 120 | + pk__in=cached_pks, |
| 121 | + ) |
| 122 | + .order_by() |
| 123 | + .all() |
| 124 | + } |
| 125 | + self._cache.update( |
| 126 | + { |
| 127 | + instance_cqrs_id: { |
| 128 | + using: instances_cache, |
| 129 | + }, |
| 130 | + } |
| 131 | + ) |
| 132 | + return instances_cache.get(instance_pk) |
| 133 | + |
| 134 | + def __enter__(self): |
| 135 | + cqrs_state.bulk_relate_cm = self |
| 136 | + |
| 137 | + def __exit__(self, exc_type, exc_val, exc_tb): |
| 138 | + cqrs_state.bulk_relate_cm = None |
| 139 | + |
| 140 | + |
| 141 | +def bulk_relate_cqrs_serialization(cqrs_id=None): |
| 142 | + return _BulkRelateCM(cqrs_id=cqrs_id) |
0 commit comments