pgsync 6.2.0__tar.gz → 7.0.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.
Files changed (75) hide show
  1. {pgsync-6.2.0 → pgsync-7.0.1}/PKG-INFO +5 -5
  2. {pgsync-6.2.0 → pgsync-7.0.1}/README.md +1 -1
  3. {pgsync-6.2.0 → pgsync-7.0.1}/README.rst +1 -1
  4. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/__init__.py +1 -1
  5. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/settings.py +3 -0
  6. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/sync.py +20 -12
  7. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/trigger.py +1 -1
  8. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync.egg-info/PKG-INFO +5 -5
  9. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync.egg-info/requires.txt +3 -3
  10. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_sync.py +3 -1
  11. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_trigger.py +1 -1
  12. {pgsync-6.2.0 → pgsync-7.0.1}/AUTHORS.rst +0 -0
  13. {pgsync-6.2.0 → pgsync-7.0.1}/CONTRIBUTING.rst +0 -0
  14. {pgsync-6.2.0 → pgsync-7.0.1}/HISTORY.rst +0 -0
  15. {pgsync-6.2.0 → pgsync-7.0.1}/LICENSE +0 -0
  16. {pgsync-6.2.0 → pgsync-7.0.1}/MANIFEST.in +0 -0
  17. {pgsync-6.2.0 → pgsync-7.0.1}/bin/bootstrap +0 -0
  18. {pgsync-6.2.0 → pgsync-7.0.1}/bin/parallel_sync +0 -0
  19. {pgsync-6.2.0 → pgsync-7.0.1}/bin/pgsync +0 -0
  20. {pgsync-6.2.0 → pgsync-7.0.1}/docs/Makefile +0 -0
  21. {pgsync-6.2.0 → pgsync-7.0.1}/docs/authors.rst +0 -0
  22. {pgsync-6.2.0 → pgsync-7.0.1}/docs/changelog.rst +0 -0
  23. {pgsync-6.2.0 → pgsync-7.0.1}/docs/conf.py +0 -0
  24. {pgsync-6.2.0 → pgsync-7.0.1}/docs/contributing.rst +0 -0
  25. {pgsync-6.2.0 → pgsync-7.0.1}/docs/history.rst +0 -0
  26. {pgsync-6.2.0 → pgsync-7.0.1}/docs/index.rst +0 -0
  27. {pgsync-6.2.0 → pgsync-7.0.1}/docs/installation.rst +0 -0
  28. {pgsync-6.2.0 → pgsync-7.0.1}/docs/logo.png +0 -0
  29. {pgsync-6.2.0 → pgsync-7.0.1}/docs/make.bat +0 -0
  30. {pgsync-6.2.0 → pgsync-7.0.1}/docs/readme.rst +0 -0
  31. {pgsync-6.2.0 → pgsync-7.0.1}/docs/usage.rst +0 -0
  32. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/base.py +0 -0
  33. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/constants.py +0 -0
  34. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/exc.py +0 -0
  35. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/helper.py +0 -0
  36. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/node.py +0 -0
  37. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/plugin.py +0 -0
  38. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/querybuilder.py +0 -0
  39. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/redisqueue.py +0 -0
  40. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/search_client.py +0 -0
  41. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/singleton.py +0 -0
  42. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/transform.py +0 -0
  43. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/urls.py +0 -0
  44. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/utils.py +0 -0
  45. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync/view.py +0 -0
  46. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync.egg-info/SOURCES.txt +0 -0
  47. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync.egg-info/dependency_links.txt +0 -0
  48. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync.egg-info/not-zip-safe +0 -0
  49. {pgsync-6.2.0 → pgsync-7.0.1}/pgsync.egg-info/top_level.txt +0 -0
  50. {pgsync-6.2.0 → pgsync-7.0.1}/pyproject.toml +0 -0
  51. {pgsync-6.2.0 → pgsync-7.0.1}/setup.cfg +0 -0
  52. {pgsync-6.2.0 → pgsync-7.0.1}/setup.py +0 -0
  53. {pgsync-6.2.0 → pgsync-7.0.1}/tests/__init__.py +0 -0
  54. {pgsync-6.2.0 → pgsync-7.0.1}/tests/conftest.py +0 -0
  55. {pgsync-6.2.0 → pgsync-7.0.1}/tests/fixtures/schema.json +0 -0
  56. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_base.py +0 -0
  57. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_constants.py +0 -0
  58. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_env_vars.py +0 -0
  59. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_helper.py +0 -0
  60. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_log_handlers.py +0 -0
  61. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_node.py +0 -0
  62. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_query_builder.py +0 -0
  63. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_redisqueue.py +0 -0
  64. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_search_client.py +0 -0
  65. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_settings.py +0 -0
  66. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_sync_nested_children.py +0 -0
  67. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_sync_root.py +0 -0
  68. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_sync_single_child_fk_on_child.py +0 -0
  69. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_sync_single_child_fk_on_parent.py +0 -0
  70. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_transform.py +0 -0
  71. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_unique_behaviour.py +0 -0
  72. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_urls.py +0 -0
  73. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_utils.py +0 -0
  74. {pgsync-6.2.0 → pgsync-7.0.1}/tests/test_view.py +0 -0
  75. {pgsync-6.2.0 → pgsync-7.0.1}/tests/testing_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgsync
3
- Version: 6.2.0
3
+ Version: 7.0.1
4
4
  Summary: Postgres/MySQL/MariaDB to Elasticsearch/OpenSearch sync
5
5
  Home-page: https://github.com/toluaina/pgsync
6
6
  Author: Tolu Aina
@@ -33,8 +33,8 @@ License-File: LICENSE
33
33
  License-File: AUTHORS.rst
34
34
  Requires-Dist: async-timeout==5.0.1
35
35
  Requires-Dist: backports-datetime-fromisoformat==2.0.3
36
- Requires-Dist: boto3==1.42.1
37
- Requires-Dist: botocore==1.42.1
36
+ Requires-Dist: boto3==1.42.8
37
+ Requires-Dist: botocore==1.42.8
38
38
  Requires-Dist: certifi==2025.11.12
39
39
  Requires-Dist: charset-normalizer==3.4.4
40
40
  Requires-Dist: click==8.1.8
@@ -60,7 +60,7 @@ Requires-Dist: requests==2.32.5
60
60
  Requires-Dist: requests-aws4auth==1.3.1
61
61
  Requires-Dist: s3transfer==0.16.0
62
62
  Requires-Dist: six==1.17.0
63
- Requires-Dist: sqlalchemy==2.0.44
63
+ Requires-Dist: sqlalchemy==2.0.45
64
64
  Requires-Dist: sqlparse==0.5.4
65
65
  Requires-Dist: typing-extensions==4.15.0
66
66
  Requires-Dist: urllib3==1.26.20
@@ -92,7 +92,7 @@ expose structured denormalized documents in [Elasticsearch](https://www.elastic.
92
92
 
93
93
  - [Python](https://www.python.org) 3.9+
94
94
  - [Postgres](https://www.postgresql.org) 9.6+ or [MySQL](https://www.mysql.com/) 8.0.0+ or [MariaDB](https://mariadb.org/) 12.0.0+
95
- - [Redis](https://redis.io) 3.1.0+ or [Valkey](https://valkey.io) 7.2.0+
95
+ - [Redis](https://redis.io) 3.1.0+ or [Valkey](https://valkey.io) 7.2.0+ (Optional in wal mode)
96
96
  - [Elasticsearch](https://www.elastic.co/products/elastic-stack) 6.3.1+ or [OpenSearch](https://opensearch.org/) 1.3.7+
97
97
  - [SQLAlchemy](https://www.sqlalchemy.org) 1.3.4+
98
98
 
@@ -241,7 +241,7 @@ Key features of PGSync are:
241
241
 
242
242
  - [Python](https://www.python.org) 3.9+
243
243
  - [Postgres](https://www.postgresql.org) 9.6+ or [MySQL](https://www.mysql.com/) 5.7.22+ or [MariaDB](https://mariadb.org/) 10.5.0+
244
- - [Redis](https://redis.io) 3.1.0+ or [Valkey](https://valkey.io) 7.2.0+
244
+ - [Redis](https://redis.io) 3.1.0+ or [Valkey](https://valkey.io) 7.2.0+ (Optional in wal mode)
245
245
  - [Elasticsearch](https://www.elastic.co/products/elastic-stack) 6.3.1+ or [OpenSearch](https://opensearch.org/) 1.3.7+
246
246
  - [SQLAlchemy](https://www.sqlalchemy.org) 1.3.4+
247
247
 
@@ -10,7 +10,7 @@ expose structured denormalized documents in [Elasticsearch](https://www.elastic.
10
10
 
11
11
  - [Python](https://www.python.org) 3.9+
12
12
  - [Postgres](https://www.postgresql.org) 9.6+ or [MySQL](https://www.mysql.com/) 8.0.0+ or [MariaDB](https://mariadb.org/) 12.0.0+
13
- - [Redis](https://redis.io) 3.1.0+ or [Valkey](https://valkey.io) 7.2.0+
13
+ - [Redis](https://redis.io) 3.1.0+ or [Valkey](https://valkey.io) 7.2.0+ (Optional in wal mode)
14
14
  - [Elasticsearch](https://www.elastic.co/products/elastic-stack) 6.3.1+ or [OpenSearch](https://opensearch.org/) 1.3.7+
15
15
  - [SQLAlchemy](https://www.sqlalchemy.org) 1.3.4+
16
16
 
@@ -2,4 +2,4 @@
2
2
 
3
3
  __author__ = "Tolu Aina"
4
4
  __email__ = "tolu@pgsync.com"
5
- __version__ = "6.2.0"
5
+ __version__ = "7.0.1"
@@ -52,6 +52,9 @@ STREAM_RESULTS = env.bool("STREAM_RESULTS", default=True)
52
52
  POLL_INTERVAL = env.float("POLL_INTERVAL", default=0.1)
53
53
  FORMAT_WITH_COMMAS = env.bool("FORMAT_WITH_COMMAS", default=True)
54
54
 
55
+ POLLING = env.bool("POLLING", default=False)
56
+ WAL = env.bool("WAL", default=False)
57
+
55
58
  # SQLAlchemy Settings:
56
59
  # Use NullPool (no connection pooling) - useful for testing or when you want to close connections immediately
57
60
  SQLALCHEMY_USE_NULLPOOL = env.bool("SQLALCHEMY_USE_NULLPOOL", default=False)
@@ -126,8 +126,9 @@ class Sync(Base, metaclass=Singleton):
126
126
  self.tree: Tree = Tree(
127
127
  self.models, nodes=self.nodes, database=doc["database"]
128
128
  )
129
+
129
130
  if bootstrap:
130
- self.setup(polling=polling)
131
+ self.setup(polling=polling, wal=wal)
131
132
 
132
133
  if validate:
133
134
  self.validate(repl_slots=repl_slots, polling=polling)
@@ -322,7 +323,9 @@ class Sync(Base, metaclass=Singleton):
322
323
  routing=self.routing,
323
324
  )
324
325
 
325
- def setup(self, no_create: bool = False, polling: bool = False) -> None:
326
+ def setup(
327
+ self, no_create: bool = False, polling: bool = False, wal: bool = False
328
+ ) -> None:
326
329
  """Create the database triggers and replication slot.
327
330
  Generally bootstrap should not require Redis as it is optional in certain cases.
328
331
  """
@@ -340,9 +343,9 @@ class Sync(Base, metaclass=Singleton):
340
343
  ):
341
344
  if if_not_exists:
342
345
 
343
- self.teardown(drop_view=False)
346
+ self.teardown(drop_view=False, polling=polling, wal=wal)
344
347
 
345
- if not polling:
348
+ if not polling and not wal:
346
349
  for schema in self.schemas:
347
350
  if schema not in self.tree.schemas:
348
351
  logger.warning(
@@ -428,6 +431,7 @@ class Sync(Base, metaclass=Singleton):
428
431
  self,
429
432
  drop_view: bool = True,
430
433
  polling: bool = False,
434
+ wal: bool = False,
431
435
  ) -> None:
432
436
  """Drop the database triggers and replication slot."""
433
437
  if self.is_mysql_compat:
@@ -447,14 +451,17 @@ class Sync(Base, metaclass=Singleton):
447
451
  f"Checkpoint file not found: {self.checkpoint_file}"
448
452
  )
449
453
 
450
- try:
451
- if self.redis is None:
452
- raise RuntimeError("Redis is not configured.")
453
- self.redis.delete()
454
- except Exception as e:
455
- logger.warning(f"Could not clear Redis checkpoint queue: {e}")
454
+ if not wal and not settings.REDIS_CHECKPOINT:
455
+ try:
456
+ if self.redis is None:
457
+ raise RuntimeError("Redis is not configured.")
458
+ self.redis.delete()
459
+ except Exception as e:
460
+ logger.warning(
461
+ f"Could not clear Redis checkpoint queue: {e}"
462
+ )
456
463
 
457
- if not polling:
464
+ if not polling and not wal:
458
465
  for schema in self.schemas:
459
466
  if schema not in self.tree.schemas:
460
467
  logger.warning(
@@ -2134,6 +2141,7 @@ class Sync(Base, metaclass=Singleton):
2134
2141
  @click.option(
2135
2142
  "--polling",
2136
2143
  is_flag=True,
2144
+ default=settings.POLLING,
2137
2145
  help="Polling mode (Incompatible with -d)",
2138
2146
  cls=MutuallyExclusiveOption,
2139
2147
  mutually_exclusive=["daemon", "wal"],
@@ -2142,7 +2150,7 @@ class Sync(Base, metaclass=Singleton):
2142
2150
  "--wal",
2143
2151
  "-w",
2144
2152
  is_flag=True,
2145
- default=False,
2153
+ default=settings.WAL,
2146
2154
  help="Use WAL for replication",
2147
2155
  cls=MutuallyExclusiveOption,
2148
2156
  mutually_exclusive=[
@@ -27,7 +27,7 @@ BEGIN
27
27
 
28
28
  IF TG_OP = 'DELETE' THEN
29
29
 
30
- SELECT primary_keys INTO _primary_keys
30
+ SELECT primary_keys, indices INTO _primary_keys, _indices
31
31
  FROM {MATERIALIZED_VIEW}
32
32
  WHERE table_name = TG_TABLE_NAME;
33
33
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgsync
3
- Version: 6.2.0
3
+ Version: 7.0.1
4
4
  Summary: Postgres/MySQL/MariaDB to Elasticsearch/OpenSearch sync
5
5
  Home-page: https://github.com/toluaina/pgsync
6
6
  Author: Tolu Aina
@@ -33,8 +33,8 @@ License-File: LICENSE
33
33
  License-File: AUTHORS.rst
34
34
  Requires-Dist: async-timeout==5.0.1
35
35
  Requires-Dist: backports-datetime-fromisoformat==2.0.3
36
- Requires-Dist: boto3==1.42.1
37
- Requires-Dist: botocore==1.42.1
36
+ Requires-Dist: boto3==1.42.8
37
+ Requires-Dist: botocore==1.42.8
38
38
  Requires-Dist: certifi==2025.11.12
39
39
  Requires-Dist: charset-normalizer==3.4.4
40
40
  Requires-Dist: click==8.1.8
@@ -60,7 +60,7 @@ Requires-Dist: requests==2.32.5
60
60
  Requires-Dist: requests-aws4auth==1.3.1
61
61
  Requires-Dist: s3transfer==0.16.0
62
62
  Requires-Dist: six==1.17.0
63
- Requires-Dist: sqlalchemy==2.0.44
63
+ Requires-Dist: sqlalchemy==2.0.45
64
64
  Requires-Dist: sqlparse==0.5.4
65
65
  Requires-Dist: typing-extensions==4.15.0
66
66
  Requires-Dist: urllib3==1.26.20
@@ -92,7 +92,7 @@ expose structured denormalized documents in [Elasticsearch](https://www.elastic.
92
92
 
93
93
  - [Python](https://www.python.org) 3.9+
94
94
  - [Postgres](https://www.postgresql.org) 9.6+ or [MySQL](https://www.mysql.com/) 8.0.0+ or [MariaDB](https://mariadb.org/) 12.0.0+
95
- - [Redis](https://redis.io) 3.1.0+ or [Valkey](https://valkey.io) 7.2.0+
95
+ - [Redis](https://redis.io) 3.1.0+ or [Valkey](https://valkey.io) 7.2.0+ (Optional in wal mode)
96
96
  - [Elasticsearch](https://www.elastic.co/products/elastic-stack) 6.3.1+ or [OpenSearch](https://opensearch.org/) 1.3.7+
97
97
  - [SQLAlchemy](https://www.sqlalchemy.org) 1.3.4+
98
98
 
@@ -1,7 +1,7 @@
1
1
  async-timeout==5.0.1
2
2
  backports-datetime-fromisoformat==2.0.3
3
- boto3==1.42.1
4
- botocore==1.42.1
3
+ boto3==1.42.8
4
+ botocore==1.42.8
5
5
  certifi==2025.11.12
6
6
  charset-normalizer==3.4.4
7
7
  click==8.1.8
@@ -27,7 +27,7 @@ requests==2.32.5
27
27
  requests-aws4auth==1.3.1
28
28
  s3transfer==0.16.0
29
29
  six==1.17.0
30
- sqlalchemy==2.0.44
30
+ sqlalchemy==2.0.45
31
31
  sqlparse==0.5.4
32
32
  typing-extensions==4.15.0
33
33
  urllib3==1.26.20
@@ -937,7 +937,9 @@ class TestSync(object):
937
937
  },
938
938
  )
939
939
  mock_create_function.assert_called_once_with("public")
940
- mock_teardown.assert_called_once_with(drop_view=False)
940
+ mock_teardown.assert_called_once_with(
941
+ drop_view=False, polling=False, wal=False
942
+ )
941
943
 
942
944
  @patch("pgsync.redisqueue.RedisQueue.delete")
943
945
  def test_teardown(self, mock_redis_delete, sync):
@@ -37,7 +37,7 @@ BEGIN
37
37
 
38
38
  IF TG_OP = 'DELETE' THEN
39
39
 
40
- SELECT primary_keys INTO _primary_keys
40
+ SELECT primary_keys, indices INTO _primary_keys, _indices
41
41
  FROM _view
42
42
  WHERE table_name = TG_TABLE_NAME;
43
43
 
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
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