xync-db 0.5.5.dev9__tar.gz → 0.5.5.dev10__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.
Files changed (40) hide show
  1. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/PKG-INFO +1 -1
  2. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/models/CLAUDE.md +7 -0
  3. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/models/__init__.py +6 -2
  4. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/.gitignore +0 -0
  5. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/README.md +0 -0
  6. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/pyproject.toml +0 -0
  7. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/__init__.py +0 -0
  8. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/config.py +0 -0
  9. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/enums.py +0 -0
  10. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/exceptions.py +0 -0
  11. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/graph.py +0 -0
  12. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/i18n.py +0 -0
  13. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/login_store.py +0 -0
  14. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/logo.png +0 -0
  15. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/CLAUDE.md +0 -0
  16. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/__init__.py +0 -0
  17. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/0001_initial.py +0 -0
  18. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/0002_triggers.py +0 -0
  19. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/0003_seed.py +0 -0
  20. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/__init__.py +0 -0
  21. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/__init__.py +0 -0
  22. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/a_actor_seed.py +0 -0
  23. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/a_bin_seed.py +0 -0
  24. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/a_country_seed.py +0 -0
  25. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/a_tg_seed.py +0 -0
  26. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/b_htx_seed.py +0 -0
  27. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/c_net_seed.py +0 -0
  28. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/countries.json +0 -0
  29. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/ranges.csv +0 -0
  30. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/migrations/models/seed/xync_files.sql +0 -0
  31. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/py.typed +0 -0
  32. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/shared.py +0 -0
  33. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/typs/__init__.py +0 -0
  34. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/typs/db/__init__.py +0 -0
  35. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/typs/db/actor.py +0 -0
  36. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/typs/db/ad.py +0 -0
  37. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/typs/db/common.py +0 -0
  38. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/typs/db/cred.py +0 -0
  39. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/typs/db/order.py +0 -0
  40. {xync_db-0.5.5.dev9 → xync_db-0.5.5.dev10}/src/xync_db/typs/db/pm.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-db
3
- Version: 0.5.5.dev9
3
+ Version: 0.5.5.dev10
4
4
  Summary: Xync DB schema: Tortoise ORM models, enums, pydantic DTOs.
5
5
  Author-email: Mike Artemiev <mixartemev@gmail.com>
6
6
  License: LicenseRef-EULA
@@ -110,6 +110,13 @@ actor.set_user(username_id):
110
110
  ### `exclude(**kwargs)` negates each kwarg separately (NOT Django's `NOT(AND)`)
111
111
  Tortoise `QuerySet.exclude(a=1, b=2)` → `NOT(a=1) AND NOT(b=2)` = `a!=1 AND b!=2` (drops a row if EITHER holds), NOT Django's `NOT(a=1 AND b=2)`. Source: `tortoise.queryset.QuerySet._filter_or_exclude` appends `~Q(**{k:v})` per kwarg, AND-joined. To exclude the **intersection**, wrap in ONE `Q`: `exclude(Q(a=1, b=2))` → `NOT(a=1 AND b=2)`. Real bug: `User.get_hot_ads` `exclude(hex__isnull=True, ad__maker__ex_id__in=SHARE_HEX_EX_IDS)` hid all hex-less ads AND all share-hex ads separately instead of only the unshared-share-hex ones; fixed with `exclude(Q(...))` + `from tortoise.expressions import Q`.
112
112
 
113
+ ### Filtering by an m2m field multiplies rows — add `.distinct()`
114
+ `filter(credexs__cred__ovr_pm_id=0)` is a JOIN through `myad_cred`, so a `MyAd` with TWO matching
115
+ credentials comes back **twice**. Real bug: `/hot/ads?mine=true` showed every 2-payment ad doubled
116
+ (the taker path hid it — `_dedup_hot_by_slot` collapses by slot) and `BaseAgentClient.ads_share`
117
+ shared it twice. Fixed with `.distinct()` in `MyAd.hot_mads_query` (test `test_hot_mads_distinct.py`);
118
+ `unshared_ad_ids` already had it. Rule: any queryset filtered through an m2m relation needs `.distinct()`.
119
+
113
120
  ### id=0 rows are unhashable — never `set[Model]`
114
121
  The XyncPay `Pm` row has **pk id=0** (norm='xyncpay'). Tortoise's `Model.__hash__` does `if not self.pk: raise TypeError(... unhashable)` — and `not 0` is `True`, so a fully-saved id=0 row is unhashable; putting it in a `set[Model]` (literal, `set(...)`, comprehension, or a pydantic `set[Model]` field) raises at construction. Rule: never build a `set` of model instances if any row can be id=0 (Pm especially, ovr_pm_id=0). Diff/dedup m2m by `pm.id` instead (`{p.id: p for p in pms}`, `{p.id for p in ...}`) — int sets are always hashable. Bit us in `Ad.upsert`/`_sync_pms` (the pms m2m path: `AdXIn.pms` is `list[Pm]` not `set`, diffs by id). Test `test_ad_upsert_pms_sync`.
115
122
 
@@ -1567,8 +1567,12 @@ class MyAd(Model): # Road
1567
1567
  fltr["ad__status"] = AdStatus.active
1568
1568
  if ex_ids:
1569
1569
  fltr["ad__maker__ex_id__in"] = ex_ids
1570
- return cls.filter(**fltr).prefetch_related(
1571
- "ad__pair_side__pair__coin", "ad__pair_side__pair__cur", "ad__maker__ex"
1570
+ # distinct: credexs — m2m, и объява с двумя платёжками (2 credex с ovr_pm_id=0) иначе # noqa: RUF003
1571
+ # приезжает JOIN'ом дважды (дубли строк в /hot/ads?mine=true и двойной ads_share) # noqa: RUF003
1572
+ return (
1573
+ cls.filter(**fltr)
1574
+ .distinct()
1575
+ .prefetch_related("ad__pair_side__pair__coin", "ad__pair_side__pair__cur", "ad__maker__ex")
1572
1576
  )
1573
1577
 
1574
1578
  @classmethod
File without changes
File without changes