ry-pg-utils 1.0.2__tar.gz → 1.0.4__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 (31) hide show
  1. {ry_pg_utils-1.0.2/src/ry_pg_utils.egg-info → ry_pg_utils-1.0.4}/PKG-INFO +268 -78
  2. ry_pg_utils-1.0.4/README.md +632 -0
  3. ry_pg_utils-1.0.4/VERSION +1 -0
  4. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/config.py +11 -0
  5. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/ipc/channels.py +0 -2
  6. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4/src/ry_pg_utils.egg-info}/PKG-INFO +268 -78
  7. ry_pg_utils-1.0.2/README.md +0 -442
  8. ry_pg_utils-1.0.2/VERSION +0 -1
  9. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/LICENSE +0 -0
  10. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/MANIFEST.in +0 -0
  11. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/packages/base_requirements.in +0 -0
  12. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/pyproject.toml +0 -0
  13. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/setup.cfg +0 -0
  14. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/setup.py +0 -0
  15. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/__init__.py +0 -0
  16. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/connect.py +0 -0
  17. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/dynamic_table.py +0 -0
  18. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/ipc/__init__.py +0 -0
  19. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/notify_trigger.py +0 -0
  20. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/parse_args.py +0 -0
  21. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/pb_types/__init__.py +0 -0
  22. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/pb_types/database_pb2.py +0 -0
  23. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/pb_types/database_pb2.pyi +0 -0
  24. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/pb_types/py.typed +0 -0
  25. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/postgres_info.py +0 -0
  26. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/py.typed +0 -0
  27. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils/updater.py +0 -0
  28. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils.egg-info/SOURCES.txt +0 -0
  29. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils.egg-info/dependency_links.txt +0 -0
  30. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils.egg-info/requires.txt +0 -0
  31. {ry_pg_utils-1.0.2 → ry_pg_utils-1.0.4}/src/ry_pg_utils.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ry-pg-utils
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: Utility functions for PostgreSQL
5
5
  Author: Ross Yeager
6
6
  Author-email: ryeager12@email.com
@@ -31,7 +31,7 @@ Dynamic: summary
31
31
 
32
32
  # ry-pg-utils
33
33
 
34
- A Python utility library for PostgreSQL database operations with dynamic table creation, connection management, and Protocol Buffer integration.
34
+ A Python utility library for PostgreSQL database operations with dynamic table creation, connection management, Protocol Buffer integration, and PostgreSQL LISTEN/NOTIFY support.
35
35
 
36
36
  ## Overview
37
37
 
@@ -41,16 +41,19 @@ A Python utility library for PostgreSQL database operations with dynamic table c
41
41
  - Dynamic table creation from Protocol Buffer message definitions
42
42
  - Thread-safe session management
43
43
  - Multi-backend support with automatic backend ID tracking
44
- - Database updater for dynamic configuration
44
+ - PostgreSQL LISTEN/NOTIFY triggers and notifications
45
+ - Database updater for dynamic configuration via Redis
45
46
  - Argument parsing for PostgreSQL connection parameters
46
47
 
47
48
  ## Features
48
49
 
49
- - **Connection Management**: Thread-safe PostgreSQL connection pooling with automatic retry logic
50
+ - **Connection Management**: Thread-safe PostgreSQL connection pooling with automatic retry logic and health checks
50
51
  - **Dynamic Tables**: Automatically create and manage database tables from Protocol Buffer message schemas
51
52
  - **Multi-Backend Support**: Track data across multiple backend instances with automatic ID tagging
52
53
  - **Session Management**: Context managers for safe database session handling
54
+ - **Notification System**: Built-in PostgreSQL LISTEN/NOTIFY support with triggers and callbacks
53
55
  - **Configuration System**: Flexible configuration via environment variables and runtime settings
56
+ - **Redis Integration**: Optional Redis-based database configuration updates
54
57
  - **Type Safety**: Full type hints and mypy support
55
58
 
56
59
  ## Installation
@@ -63,8 +66,13 @@ pip install ry-pg-utils
63
66
 
64
67
  - Python 3.12+
65
68
  - PostgreSQL database
66
- - SQLAlchemy
67
- - Protocol Buffer support
69
+ - SQLAlchemy 2.0+
70
+ - Protocol Buffer support (protobuf)
71
+ - psycopg2-binary
72
+ - tenacity (for retry logic)
73
+ - python-dotenv (for environment variables)
74
+ - ryutils (logging utilities)
75
+ - ry_redis_bus (optional, for Redis integration)
68
76
 
69
77
  ## Configuration
70
78
 
@@ -105,11 +113,11 @@ pg_config.backend_id = "custom_backend_id"
105
113
  | `postgres_db` | str | From env | Database name |
106
114
  | `postgres_user` | str | From env | Database username |
107
115
  | `postgres_password` | str | From env | Database password |
108
- | `backend_id` | str | hostname_ip | Unique identifier for this backend instance |
116
+ | `backend_id` | str | POSTGRES_USER or hostname_ip | Unique identifier for this backend instance |
109
117
  | `add_backend_to_all` | bool | True | Add backend_id column to all tables |
110
118
  | `add_backend_to_tables` | bool | True | Append backend_id to table names |
111
119
  | `raise_on_use_before_init` | bool | True | Raise exception if DB used before initialization |
112
- | `do_publish_db` | bool | False | Enable database publishing features |
120
+ | `do_publish_db` | bool | False | Enable database publishing features (for Redis integration) |
113
121
  | `use_local_db_only` | bool | True | Use only local database connections |
114
122
 
115
123
  ## Quick Start
@@ -118,19 +126,15 @@ pg_config.backend_id = "custom_backend_id"
118
126
 
119
127
  ```python
120
128
  from ry_pg_utils.connect import init_database, ManagedSession
121
- from ry_pg_utils.postgres_info import PostgresInfo
122
129
 
123
- # Create database connection info
124
- db_info = PostgresInfo(
130
+ # Initialize the database connection
131
+ init_database(
125
132
  db_name="myapp_db",
126
- host="localhost",
127
- port=5432,
128
- user="postgres",
129
- password="secret"
133
+ db_host="localhost",
134
+ db_port=5432,
135
+ db_user="postgres",
136
+ db_password="secret"
130
137
  )
131
-
132
- # Initialize the database connection
133
- init_database(db_info, db_name="myapp")
134
138
  ```
135
139
 
136
140
  ### 2. Use Dynamic Tables with Protocol Buffers
@@ -165,12 +169,14 @@ exists = DynamicTableDb.is_in_db(
165
169
 
166
170
  ```python
167
171
  from ry_pg_utils.connect import ManagedSession
172
+ from sqlalchemy import text
168
173
 
169
174
  # Use context manager for automatic session cleanup
170
- with ManagedSession(db="myapp") as session:
171
- result = session.execute("SELECT * FROM my_table")
172
- for row in result:
173
- print(row)
175
+ with ManagedSession(db="myapp_db") as session:
176
+ if session:
177
+ result = session.execute(text("SELECT * FROM my_table"))
178
+ for row in result:
179
+ print(row)
174
180
  ```
175
181
 
176
182
  ## Core Components
@@ -181,21 +187,29 @@ The connection module provides thread-safe database connection and session manag
181
187
 
182
188
  ```python
183
189
  from ry_pg_utils.connect import (
184
- init_database, # Initialize database connection
185
- init_engine, # Initialize SQLAlchemy engine
186
- ManagedSession, # Context manager for sessions
187
- get_backend_id, # Get current backend ID
188
- set_backend_id, # Set backend ID for thread
189
- close_engine, # Close database connection
190
- clear_db, # Clear all connections
190
+ init_database, # Initialize database connection
191
+ init_engine, # Initialize SQLAlchemy engine
192
+ ManagedSession, # Context manager for sessions
193
+ get_backend_id, # Get current backend ID
194
+ set_backend_id, # Set backend ID for thread
195
+ get_engine, # Get engine for database
196
+ close_engine, # Close database connection
197
+ clear_db, # Clear all connections
198
+ get_table_name, # Get table name with backend suffix
199
+ is_database_initialized, # Check if database is initialized
200
+ Base, # SQLAlchemy declarative base
191
201
  )
192
202
  ```
193
203
 
194
204
  **Key Features:**
205
+
195
206
  - Thread-local backend ID tracking
196
- - Connection pooling with configurable parameters
197
- - Automatic connection recovery on failure
207
+ - Connection pooling with configurable parameters (pool_size, max_overflow, pool_recycle)
208
+ - Automatic connection recovery with retry logic (using tenacity)
198
209
  - Session scoping for thread safety
210
+ - Automatic backend_id injection before flush operations
211
+ - Pre-ping health checks to validate connections
212
+ - Support for auto-importing model modules
199
213
 
200
214
  ### `dynamic_table.py` - Dynamic Table Creation
201
215
 
@@ -225,6 +239,7 @@ exists = db.inst_is_in_db(
225
239
  ```
226
240
 
227
241
  **Supported Protocol Buffer Types:**
242
+
228
243
  - `int32`, `int64`, `uint32`, `uint64` → PostgreSQL `Integer`
229
244
  - `float`, `double` → PostgreSQL `Float`
230
245
  - `bool` → PostgreSQL `Boolean`
@@ -234,7 +249,7 @@ exists = db.inst_is_in_db(
234
249
 
235
250
  ### `postgres_info.py` - Connection Information
236
251
 
237
- Data class for PostgreSQL connection parameters:
252
+ Class for PostgreSQL connection parameters:
238
253
 
239
254
  ```python
240
255
  from ry_pg_utils.postgres_info import PostgresInfo
@@ -247,8 +262,12 @@ db_info = PostgresInfo(
247
262
  password="secret"
248
263
  )
249
264
 
250
- # Get connection URI
251
- uri = db_info.get_uri() # postgresql://postgres:secret@localhost:5432/mydb
265
+ # Check if valid
266
+ if not db_info.is_null():
267
+ print(db_info) # Prints info with password masked
268
+
269
+ # Create null instance
270
+ null_info = PostgresInfo.null()
252
271
  ```
253
272
 
254
273
  ### `parse_args.py` - Argument Parsing
@@ -268,48 +287,129 @@ args = parser.parse_args()
268
287
 
269
288
  ### `updater.py` - Database Configuration Updater
270
289
 
271
- Dynamically update database connections based on configuration messages:
290
+ Dynamically update database connections based on configuration messages via Redis:
272
291
 
273
292
  ```python
274
- from ry_pg_utils.updater import PostgresDbUpdater
293
+ from ry_pg_utils.updater import DbUpdater
294
+ from ry_redis_bus.helpers import RedisInfo
295
+ from ryutils.verbose import Verbose
275
296
 
276
- updater = PostgresDbUpdater(
297
+ updater = DbUpdater(
277
298
  redis_info=redis_info,
278
- verbose=verbose,
279
- backend_id="my_backend"
299
+ args=args, # argparse.Namespace with postgres config
300
+ backend_id="my_backend",
301
+ verbose=Verbose(True)
302
+ )
303
+
304
+ # Initialize and start listening for configuration updates
305
+ updater.init()
306
+
307
+ # Run the update loop
308
+ updater.run() # Blocks, continuously checking for updates
309
+ ```
310
+
311
+ ### `notify_trigger.py` - PostgreSQL LISTEN/NOTIFY Support
312
+
313
+ Create database triggers that send notifications on table changes:
314
+
315
+ ```python
316
+ from ry_pg_utils.notify_trigger import (
317
+ create_notify_trigger,
318
+ drop_notify_trigger,
319
+ subscribe_to_notifications,
320
+ NotificationListener,
280
321
  )
322
+ from ry_pg_utils.connect import get_engine
323
+
324
+ engine = get_engine("myapp_db")
325
+
326
+ # Create a trigger that notifies on INSERT/UPDATE/DELETE
327
+ create_notify_trigger(
328
+ engine=engine,
329
+ table_name="users",
330
+ channel_name="user_changes",
331
+ events=["INSERT", "UPDATE", "DELETE"],
332
+ columns=["id", "username", "email"] # Optional: only include specific columns
333
+ )
334
+
335
+ # Subscribe to notifications
336
+ def handle_notification(notification):
337
+ print(f"Table: {notification['table']}")
338
+ print(f"Action: {notification['action']}")
339
+ print(f"Data: {notification['data']}")
340
+
341
+ with subscribe_to_notifications(
342
+ engine=engine,
343
+ channel_name="user_changes",
344
+ callback=handle_notification,
345
+ timeout=60.0
346
+ ) as notifications:
347
+ # Notifications are handled in background thread
348
+ time.sleep(10)
349
+
350
+ # Or use the NotificationListener class for long-running listeners
351
+ listener = NotificationListener(db_name="myapp_db")
352
+ listener.create_listener(
353
+ table_name="users",
354
+ channel_name="user_changes",
355
+ events=["INSERT", "UPDATE"]
356
+ )
357
+ listener.add_callback("user_changes", handle_notification)
358
+ listener.start()
359
+
360
+ # ... your application code ...
281
361
 
282
- # Start listening for configuration updates
283
- updater.run()
362
+ listener.stop()
363
+ ```
364
+
365
+ ### `ipc/channels.py` - Redis Communication Channels
366
+
367
+ Pre-defined Redis channels for database configuration updates (requires ry_redis_bus):
368
+
369
+ ```python
370
+ from ry_pg_utils.ipc.channels import (
371
+ DATABASE_CHANNEL, # DatabaseConfigPb messages
372
+ DATABASE_CONFIG_CHANNEL, # DatabaseSettingsPb messages
373
+ DATABASE_NOTIFY_CHANNEL, # DatabaseNotificationPb messages
374
+ )
375
+
376
+ # These channels are used by DbUpdater for dynamic database configuration
284
377
  ```
285
378
 
286
379
  ## Advanced Usage
287
380
 
288
381
  ### Multi-Backend Support
289
382
 
290
- When `add_backend_to_all` is enabled, all tables automatically get a `backend_id` column:
383
+ When `add_backend_to_all` is enabled (default: True), all tables automatically get a `backend_id` column:
291
384
 
292
385
  ```python
293
386
  from ry_pg_utils.connect import set_backend_id, ManagedSession
387
+ from sqlalchemy import text
294
388
 
295
389
  # Set backend ID for current thread
296
390
  set_backend_id("backend_1")
297
391
 
298
392
  # All subsequent operations will include this backend_id
299
- with ManagedSession(db="myapp") as session:
300
- # Queries automatically filter by backend_id
301
- result = session.execute("SELECT * FROM my_table")
393
+ # ManagedSession automatically sets the backend_id if provided
394
+ with ManagedSession(db="myapp_db", backend_id="backend_1") as session:
395
+ if session:
396
+ # New/dirty records automatically get backend_id injected before flush
397
+ result = session.execute(text("SELECT * FROM my_table"))
302
398
  ```
303
399
 
304
400
  ### Custom Table Names
305
401
 
306
- When `add_backend_to_tables` is enabled, table names are automatically suffixed:
402
+ When `add_backend_to_tables` is enabled (default: True), table names are automatically suffixed:
307
403
 
308
404
  ```python
309
405
  from ry_pg_utils.connect import get_table_name
406
+ from ry_pg_utils.config import pg_config
310
407
 
311
408
  # Returns "events_my_backend" if add_backend_to_tables=True
312
- table_name = get_table_name("events", backend_id="my_backend")
409
+ table_name = get_table_name("events", backend_id="my_backend", verbose=True)
410
+
411
+ # Configure globally
412
+ pg_config.add_backend_to_tables = False # Disable backend suffix
313
413
  ```
314
414
 
315
415
  ### ORM Base Class
@@ -327,27 +427,53 @@ class User(Base):
327
427
  name = Column(String(100))
328
428
  email = Column(String(200))
329
429
 
330
- # If add_backend_to_all=True, backend_id column is automatically added
430
+ # If add_backend_to_all=True (default), backend_id column is automatically added
431
+ # The backend_id is a String(256) column, nullable=False
432
+ ```
433
+
434
+ ### Auto-Importing Models
435
+
436
+ Use the `models_module` parameter to automatically import all models before table creation:
437
+
438
+ ```python
439
+ from ry_pg_utils.connect import init_database
440
+
441
+ # This will walk through 'myapp.models' and import all submodules
442
+ # ensuring all model classes are registered with Base.metadata
443
+ init_database(
444
+ db_name="myapp_db",
445
+ db_host="localhost",
446
+ db_port=5432,
447
+ db_user="postgres",
448
+ db_password="secret",
449
+ models_module="myapp.models" # Dot-separated module path
450
+ )
331
451
  ```
332
452
 
333
453
  ## Error Handling
334
454
 
335
- The library includes robust error handling:
455
+ The library includes robust error handling with automatic retries:
336
456
 
337
457
  ```python
338
458
  from ry_pg_utils.connect import ManagedSession
459
+ from sqlalchemy import text
339
460
 
340
- with ManagedSession(db="myapp") as session:
461
+ with ManagedSession(db="myapp_db") as session:
341
462
  if session is None:
342
- # Connection failed, handle gracefully
463
+ # Connection failed after retries, handle gracefully
343
464
  print("Failed to establish database connection")
344
465
  return
345
466
 
346
467
  try:
347
- session.execute("SELECT * FROM my_table")
468
+ session.execute(text("SELECT * FROM my_table"))
348
469
  except Exception as e:
349
- # Session will automatically rollback
470
+ # Session will automatically rollback on exception
350
471
  print(f"Query failed: {e}")
472
+
473
+ # Retries are built-in:
474
+ # - Session operations retry 3 times on OperationalError
475
+ # - Exponential backoff: min 4s, max 10s
476
+ # - Connection health checks via pool_pre_ping
351
477
  ```
352
478
 
353
479
  ## Type Safety
@@ -378,12 +504,17 @@ pip install -r packages/requirements-dev.txt
378
504
 
379
505
  ### Running Tests
380
506
 
507
+ Tests require a running PostgreSQL instance. Configure test database connection via environment variables or `.env` file.
508
+
381
509
  ```bash
382
510
  # Activate virtual environment
383
511
  source venv-dev/bin/activate
384
512
 
385
- # Run tests
386
- python -m pytest test/
513
+ # Run all tests
514
+ make test
515
+
516
+ # Run specific test module
517
+ make test TESTMODULE=connect_test
387
518
  ```
388
519
 
389
520
  ### Code Quality
@@ -392,16 +523,12 @@ The project uses several tools for code quality:
392
523
 
393
524
  ```bash
394
525
  # Format code
395
- black ry_pg_utils/
396
-
397
- # Type checking
398
- mypy ry_pg_utils/
526
+ make format
399
527
 
400
- # Linting
401
- pylint ry_pg_utils/
528
+ # Run linting
529
+ make lint_full
402
530
 
403
- # Import sorting
404
- isort ry_pg_utils/
531
+ # Type checking is included in lint_full (uses mypy)
405
532
  ```
406
533
 
407
534
  ## Examples
@@ -412,8 +539,8 @@ isort ry_pg_utils/
412
539
  import argparse
413
540
  from ry_pg_utils.parse_args import add_postrgres_db_args
414
541
  from ry_pg_utils.connect import init_database, ManagedSession
415
- from ry_pg_utils.postgres_info import PostgresInfo
416
542
  from ry_pg_utils.dynamic_table import DynamicTableDb
543
+ from sqlalchemy import text
417
544
 
418
545
  def parse_args():
419
546
  parser = argparse.ArgumentParser(description="My Database App")
@@ -424,26 +551,78 @@ def main():
424
551
  args = parse_args()
425
552
 
426
553
  # Initialize database
427
- db_info = PostgresInfo(
554
+ init_database(
428
555
  db_name=args.postgres_db,
429
- host=args.postgres_host,
430
- port=args.postgres_port,
431
- user=args.postgres_user,
432
- password=args.postgres_password
556
+ db_host=args.postgres_host,
557
+ db_port=args.postgres_port,
558
+ db_user=args.postgres_user,
559
+ db_password=args.postgres_password
433
560
  )
434
561
 
435
- init_database(db_info, db_name="myapp")
436
-
437
562
  # Use the database
438
- with ManagedSession(db="myapp") as session:
563
+ with ManagedSession(db=args.postgres_db) as session:
439
564
  if session:
440
- result = session.execute("SELECT version()")
565
+ result = session.execute(text("SELECT version()"))
441
566
  print(f"PostgreSQL version: {result.fetchone()[0]}")
442
567
 
443
568
  if __name__ == "__main__":
444
569
  main()
445
570
  ```
446
571
 
572
+ ### Real-time Notification Example
573
+
574
+ ```python
575
+ from ry_pg_utils.connect import init_database, get_engine, Base
576
+ from ry_pg_utils.notify_trigger import create_notify_trigger, NotificationListener
577
+ from sqlalchemy import Column, Integer, String
578
+ import time
579
+
580
+ # Define a model
581
+ class Product(Base):
582
+ __tablename__ = 'products'
583
+
584
+ id = Column(Integer, primary_key=True)
585
+ name = Column(String(100))
586
+ price = Column(Integer)
587
+
588
+ # Initialize database
589
+ init_database(
590
+ db_name="inventory_db",
591
+ db_host="localhost",
592
+ db_port=5432,
593
+ db_user="postgres",
594
+ db_password="secret"
595
+ )
596
+
597
+ # Create notification trigger
598
+ engine = get_engine("inventory_db")
599
+ create_notify_trigger(
600
+ engine=engine,
601
+ table_name="products",
602
+ channel_name="product_updates",
603
+ events=["INSERT", "UPDATE", "DELETE"],
604
+ columns=["id", "name", "price"]
605
+ )
606
+
607
+ # Set up listener
608
+ listener = NotificationListener(db_name="inventory_db")
609
+
610
+ def on_product_change(notification):
611
+ action = notification['action']
612
+ data = notification['data']
613
+ print(f"Product {action}: {data}")
614
+
615
+ listener.add_callback("product_updates", on_product_change)
616
+ listener.start()
617
+
618
+ # Your application runs...
619
+ try:
620
+ while True:
621
+ time.sleep(1)
622
+ except KeyboardInterrupt:
623
+ listener.stop()
624
+ ```
625
+
447
626
  ## License
448
627
 
449
628
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -460,14 +639,25 @@ Contributions are welcome! Please feel free to submit a Pull Request.
460
639
 
461
640
  ## Author
462
641
 
463
- Ross Yeager - ryeager12@email.com
642
+ Ross Yeager - `ryeager12@email.com`
464
643
 
465
644
  ## Changelog
466
645
 
646
+ ### Version 1.0.2 (Current)
647
+
648
+ - PostgreSQL LISTEN/NOTIFY support with triggers and notifications
649
+ - NotificationListener class for background notification handling
650
+ - Automatic connection health checks with pool_pre_ping
651
+ - Auto-importing models from specified module paths
652
+ - Enhanced retry logic with tenacity
653
+ - Improved error handling and connection recovery
654
+
467
655
  ### Version 1.0.0
656
+
468
657
  - Initial release
469
- - Database connection management
470
- - Dynamic table creation
471
- - Multi-backend support
472
- - Configuration system
658
+ - Database connection management with pooling
659
+ - Dynamic table creation from Protocol Buffers
660
+ - Multi-backend support with automatic ID tagging
661
+ - Configuration system with environment variables
473
662
  - Protocol Buffer integration
663
+ - Redis-based database configuration updates