tracktolib 0.49.0__py3-none-any.whl → 0.50.0__py3-none-any.whl

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.
tracktolib/pg/__init__.py CHANGED
@@ -11,5 +11,6 @@ from .query import (
11
11
  update_returning,
12
12
  update_one,
13
13
  insert_pg,
14
+ OnConflict,
14
15
  )
15
16
  from .utils import iterate_pg, upsert_csv, safe_pg, safe_pg_context, PGError, PGException
tracktolib/pg/query.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import typing
2
2
  from dataclasses import dataclass, field
3
3
  from typing import TypeVar, Iterable, Callable, Generic, Iterator, TypeAlias, overload, Any, Literal
4
+
4
5
  from ..pg_utils import get_conflict_query
5
6
 
6
7
  try:
@@ -32,6 +33,7 @@ def _get_on_conflict_query(
32
33
  constraint: K | None,
33
34
  on_conflict: K | None,
34
35
  where: K | None,
36
+ merge_columns: Iterable[K] | None,
35
37
  ) -> str:
36
38
  _on_conflict = get_conflict_query(
37
39
  columns=columns,
@@ -40,6 +42,7 @@ def _get_on_conflict_query(
40
42
  constraint=constraint,
41
43
  on_conflict=on_conflict,
42
44
  where=where,
45
+ merge_columns=merge_columns,
43
46
  )
44
47
  return f"{query} {_on_conflict}"
45
48
 
@@ -72,6 +75,7 @@ class PGConflictQuery(Generic[K]):
72
75
  query: str | None = None
73
76
  constraint: str | None = None
74
77
  where: str | None = None
78
+ merge_keys: Iterable[K] | None = None
75
79
 
76
80
  def __post_init__(self):
77
81
  _has_keys = 1 if (self.keys or self.ignore_keys) else 0
@@ -172,6 +176,7 @@ class PGInsertQuery(PGQuery):
172
176
  self.on_conflict.constraint,
173
177
  self.on_conflict.query,
174
178
  self.on_conflict.where,
179
+ self.on_conflict.merge_keys,
175
180
  )
176
181
 
177
182
  # Returning
tracktolib/pg_sync.py CHANGED
@@ -18,6 +18,7 @@ from .pg_utils import get_tmp_table_query
18
18
  def fetch_all(engine: Connection, query: LiteralString, *data) -> list[dict]:
19
19
  with engine.cursor(row_factory=dict_row) as cur:
20
20
  resp = (cur.execute(query) if not data else cur.execute(query, data)).fetchall()
21
+ engine.commit()
21
22
  return resp
22
23
 
23
24
 
@@ -27,7 +28,7 @@ def fetch_count(engine: Connection, table: str, *args, where: str | None = None)
27
28
  query = f"{query} WHERE {where}"
28
29
  with engine.cursor() as cur:
29
30
  count = cur.execute(cast(LiteralString, query), params=args).fetchone()
30
-
31
+ engine.commit()
31
32
  return count[0] if count else None
32
33
 
33
34
 
@@ -46,6 +47,7 @@ def fetch_one(engine: Connection, query: Query, *args) -> dict | None: ...
46
47
  def fetch_one(engine: Connection, query: Query, *args, required: bool = False) -> dict | None:
47
48
  with engine.cursor(row_factory=dict_row) as cur:
48
49
  _data = cur.execute(query, args).fetchone()
50
+ engine.commit()
49
51
  if required and not _data:
50
52
  raise ValueError("No value found for query")
51
53
  return _data
tracktolib/pg_utils.py CHANGED
@@ -1,7 +1,8 @@
1
- from typing_extensions import LiteralString
2
1
  from typing import Iterable
3
2
  from typing import cast
4
3
 
4
+ from typing_extensions import LiteralString
5
+
5
6
 
6
7
  def get_tmp_table_query(
7
8
  schema: LiteralString,
@@ -41,6 +42,7 @@ def get_conflict_query(
41
42
  constraint: str | None = None,
42
43
  on_conflict: str | None = None,
43
44
  where: str | None = None,
45
+ merge_columns: Iterable[str] | None = None,
44
46
  ) -> LiteralString:
45
47
  if on_conflict:
46
48
  return cast(LiteralString, on_conflict)
@@ -55,8 +57,19 @@ def get_conflict_query(
55
57
  else:
56
58
  raise NotImplementedError("update_keys or constraint must be set")
57
59
 
58
- _ignore_columns = [*(update_columns or []), *(ignore_columns or [])]
60
+ _update_columns = update_columns or []
61
+ _ignore_columns = ignore_columns or []
62
+ _merge_columns = merge_columns or []
63
+
64
+ if set(_merge_columns) & set(_update_columns):
65
+ raise ValueError("Duplicate keys found between merge and update")
66
+ if set(_merge_columns) & set(_ignore_columns):
67
+ raise ValueError("Merge column cannot be ignored")
68
+
69
+ _ignore_columns = [*_update_columns, *_ignore_columns, *_merge_columns]
59
70
  fields = ", ".join(f"{x} = COALESCE(EXCLUDED.{x}, t.{x})" for x in columns if x not in _ignore_columns)
71
+ if merge_columns:
72
+ fields += ", ".join(f"{x} = COALESCE(t.{x}, jsonb_build_object()) || EXCLUDED.{x}" for x in merge_columns)
60
73
  if not fields:
61
74
  raise ValueError("No fields set")
62
75
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tracktolib
3
- Version: 0.49.0
3
+ Version: 0.50.0
4
4
  Summary: Utility library for python
5
5
  Home-page: https://github.com/tracktor/tracktolib
6
6
  License: MIT
@@ -3,17 +3,17 @@ tracktolib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  tracktolib/api.py,sha256=xArVgRj_g7bw2tEDbjC9qs9f55b9X0-kJoc8-s1rsYo,9616
4
4
  tracktolib/http_utils.py,sha256=c10JGmHaBw3VSDMYhz2dvVw2lo4PUAq1xMub74I7xDc,2625
5
5
  tracktolib/logs.py,sha256=M5RZ8OYKgLEBJeC1AwUCSRbFAH09hwdTjjs-AQ9QGg8,2204
6
- tracktolib/pg/__init__.py,sha256=32kKBJzIDyppszZMAOSMgM3ggz7Ow0TaNKiMs740gyw,333
7
- tracktolib/pg/query.py,sha256=KESY4g0XePUrRIakygmzhPP2vIOfJGWc2PAZsIj_PfI,13580
6
+ tracktolib/pg/__init__.py,sha256=j67e3B3gBbCHLD20QBybptmNdbbVMzNhZE6XjIPuKVo,349
7
+ tracktolib/pg/query.py,sha256=otLukOink4qQDUAN2VaPvlq5Ig8Sz7yfQlg-8gjI4iY,13744
8
8
  tracktolib/pg/utils.py,sha256=cL24KEt4SWJQ7LJPzaO3c8Xg0ZLmjhn22DtTWg86nwc,6324
9
- tracktolib/pg_sync.py,sha256=OsmEbFzqlJDm1jfuxpFi2Lhjj9nEGxGlnNmZCnqWZ6c,5106
10
- tracktolib/pg_utils.py,sha256=8DDlZVSgfNie9M-zL7wilFufXMMvSPw5d7aIDs_pQCM,1976
9
+ tracktolib/pg_sync.py,sha256=z6EB0hELq6t129gnVnX0rNXv2McZXxI8khy-TEG65Ag,5165
10
+ tracktolib/pg_utils.py,sha256=asFAyTC_RCRaYr9fiJxTiSs3yxZM6xyoOKLA6olg6yg,2529
11
11
  tracktolib/s3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  tracktolib/s3/minio.py,sha256=wMEjkSes9Fp39fD17IctALpD6zB2xwDRQEmO7Vzan3g,1387
13
13
  tracktolib/s3/s3.py,sha256=d0Q63Zb62ef4jAt05zQwpgYvAoxHC9kSQuHzzK90VvE,4825
14
14
  tracktolib/tests.py,sha256=Pbc4yGQrIWFLBEgX-kDBxhMCqH-bfOJtkH2agvaM6ZQ,382
15
15
  tracktolib/utils.py,sha256=jwLww8bqDu8zEip9uN4yW0lE5_YMWfrAHYtagr8sYOA,5295
16
- tracktolib-0.49.0.dist-info/LICENSE,sha256=uUanH0X7SeZEPdsRTHegMSMTiIHMurt9H0jSwEwKE1Y,1081
17
- tracktolib-0.49.0.dist-info/METADATA,sha256=jwSGn-VdiGimYNLizSMhI_cLSyM8GgQDNkickFcfJ-4,3641
18
- tracktolib-0.49.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
19
- tracktolib-0.49.0.dist-info/RECORD,,
16
+ tracktolib-0.50.0.dist-info/LICENSE,sha256=uUanH0X7SeZEPdsRTHegMSMTiIHMurt9H0jSwEwKE1Y,1081
17
+ tracktolib-0.50.0.dist-info/METADATA,sha256=MbyudDqUlbPAKAomAy94zIDnKTnhKPnvxSzI9VUQU2s,3641
18
+ tracktolib-0.50.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
19
+ tracktolib-0.50.0.dist-info/RECORD,,