xync-db 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {xync_db-0.2.0 → xync_db-0.2.1}/PKG-INFO +1 -1
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/models/__init__.py +49 -39
- {xync_db-0.2.0 → xync_db-0.2.1}/.gitignore +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/README.md +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/pyproject.toml +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/__init__.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/config.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/enums.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/exceptions.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/graph.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/i18n.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/logo.png +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/CLAUDE.md +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/__init__.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/0001_initial.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/0002_triggers.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/0003_files_seed.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/0004_all_seed.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/__init__.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/seed/__init__.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/seed/a_actor_seed.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/seed/a_tg_seed.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/seed/b_htx_seed.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/migrations/models/seed/xync_files.sql +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/models/CLAUDE.md +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/py.typed +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/shared.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/typs/__init__.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/typs/db/__init__.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/typs/db/actor.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/typs/db/ad.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/typs/db/common.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/typs/db/cred.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/typs/db/order.py +0 -0
- {xync_db-0.2.0 → xync_db-0.2.1}/src/xync_db/typs/db/pm.py +0 -0
|
@@ -321,25 +321,37 @@ class Person(Model, TsTrait):
|
|
|
321
321
|
# pm_agents: BackwardFKRelation[PmAgent]
|
|
322
322
|
|
|
323
323
|
async def merge(self, new_person: Person):
|
|
324
|
-
"""Вмерджить new_person в self
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
324
|
+
"""Вмерджить new_person в self (перенести акторов и креды) и удалить new_person — АТОМАРНО,
|
|
325
|
+
одной транзакцией: сбой посреди переноса не должен оставлять пол-мерджа (актор на одной
|
|
326
|
+
персоне, кред на другой) и травить окружающую транзакцию запроса.
|
|
327
|
+
|
|
328
|
+
Коллизия uniq(person,pmcur,ovr_pm)/(person,pmcur,detail): у self уже есть «тот же» кред
|
|
329
|
+
(типично XyncPay по той же pmcur, забутстрапленный на другой бирже) — простой re-point
|
|
330
|
+
person_id упал бы IntegrityError. Молча сливать финансовые креды нельзя, поэтому громко
|
|
331
|
+
падаем ValueError (аномалию данных разруливает человек); транзакция всё откатывает чисто."""
|
|
332
|
+
if new_person.user_id not in (self.user_id, None):
|
|
333
|
+
raise ValueError(f"refuse to merge user-bound person#{new_person.id} into person#{self.id}")
|
|
334
|
+
async with in_transaction():
|
|
335
|
+
await new_person.fetch_related("creds", "actors")
|
|
336
|
+
for cred in new_person.creds:
|
|
337
|
+
if dup := await Cred.get_or_none(
|
|
338
|
+
person=self, pmcur_id=cred.pmcur_id, ovr_pm_id=cred.ovr_pm_id
|
|
339
|
+
) or await Cred.get_or_none(person=self, pmcur_id=cred.pmcur_id, detail=cred.detail):
|
|
340
|
+
txt = (
|
|
341
|
+
f"У старого person#{self.id}:{self.name}:{self.note} уже есть cred#{dup.id}:{dup.detail} " # noqa: RUF001
|
|
342
|
+
f"c pmcur:{dup.pmcur_id}:{dup.ovr_pm_id}, а мы на него пытаем перевесить " # noqa: RUF001
|
|
343
|
+
f"новый cred#{cred.id}:{cred.detail} c pmcur:{cred.pmcur_id}:{cred.ovr_pm_id} "
|
|
344
|
+
f"нового person#{new_person.id}:{new_person.name}:{new_person.note}"
|
|
345
|
+
)
|
|
346
|
+
raise ValueError(txt)
|
|
347
|
+
cred.person = self
|
|
348
|
+
await cred.save(update_fields=["person_id"])
|
|
349
|
+
for actor in new_person.actors:
|
|
350
|
+
actor.person = self
|
|
351
|
+
await actor.save(update_fields=["person_id"])
|
|
352
|
+
self.name = self.name or new_person.name
|
|
353
|
+
await self.save(update_fields=["name"])
|
|
337
354
|
await new_person.delete()
|
|
338
|
-
else:
|
|
339
|
-
raise ValueError(
|
|
340
|
-
f"Merge to person#{self.id} failed: new person#{new_person.id} still has "
|
|
341
|
-
f"{len(new_person.creds)} creds, {len(new_person.actors)} actors, user_id={new_person.user_id}"
|
|
342
|
-
)
|
|
343
355
|
|
|
344
356
|
|
|
345
357
|
class User(TgUser, TsTrait):
|
|
@@ -902,27 +914,25 @@ class Actor(Model):
|
|
|
902
914
|
logging.error(txt)
|
|
903
915
|
return 3, txt, user
|
|
904
916
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
if not merged:
|
|
925
|
-
# все персоны юзера заняты акторами с другими именами — оставляем новую, привязываем к юзеру # noqa: RUF003
|
|
917
|
+
# Цель мерджа выбираем БЕЗ зависимости от порядка выборки (старый цикл с `elif i` ошибочно
|
|
918
|
+
# ловил «аномалию», если пустая базовая персона оказывалась не первой):
|
|
919
|
+
# 1) занятая персона с тем же именем — тот же человек на другой бирже;
|
|
920
|
+
# 2) иначе базовая пустая персона юзера (её единственный актор — внутренний ex0).
|
|
921
|
+
# Пустых (без биржевого актора) персон у юзера норм быть не больше одной — базовая от триггера.
|
|
922
|
+
empties = [p for p in user_persons if not any(a.ex_id for a in p.actors)]
|
|
923
|
+
if len(empties) > 1:
|
|
924
|
+
txt = f"У юзера #{username_id} больше одной персоны без биржевых акторов — аномалия" # noqa: RUF001
|
|
925
|
+
logging.error(txt)
|
|
926
|
+
return 2, txt, user
|
|
927
|
+
target = next(
|
|
928
|
+
(p for p in user_persons if any(a.ex_id for a in p.actors) and p.name == self.person.name), None
|
|
929
|
+
) or (empties[0] if empties else None)
|
|
930
|
+
if target:
|
|
931
|
+
await target.merge(self.person)
|
|
932
|
+
else:
|
|
933
|
+
# все персоны юзера заняты акторами с другими именами — это другой человек под тем же # noqa: RUF003
|
|
934
|
+
# ТГ-аккаунтом: оставляем новую персону актора и привязываем к юзеру. Осиротевшей пустой
|
|
935
|
+
# базы тут не остаётся — будь она, стала бы target выше и была бы поглощена.
|
|
926
936
|
self.person.user = user
|
|
927
937
|
await self.person.save(update_fields=["user_id"])
|
|
928
938
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|