{"id":9988,"library":"nsj-multi-database-lib","title":"NSJ Multi-Database Library","description":"The NSJ Multi-Database Library is a Python module designed to enable applications, particularly those built with FastAPI, to efficiently manage and interact with multiple database connections within the same application. It provides an abstraction layer for various database engines (e.g., PostgreSQL, Oracle, SQL Server), simplifying connection pooling, session management, and transactional data access objects (DAOs). The current version is 2.1.0, and the library maintains a steady release cadence for improvements and bug fixes, supporting Python versions 3.6 up to 3.9.","status":"active","version":"2.1.0","language":"en","source_language":"en","source_url":"https://github.com/nelsonjchen/nsj-multi-database-lib","tags":["database","multi-database","sqlalchemy","orm","connection-pooling","fastapi"],"install":[{"cmd":"pip install nsj-multi-database-lib","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Core dependency for ORM and database interactions. The library specifically requires SQLAlchemy < 2.0.0.","package":"SQLAlchemy","optional":false}],"imports":[{"symbol":"ConnectionPool","correct":"from nsj_multi_database_lib.connection.connection_pool import ConnectionPool"},{"symbol":"DatabaseManager","correct":"from nsj_multi_database_lib.connection.database_manager import DatabaseManager"},{"note":"DaoBase is within the 'dao' submodule, not directly under the root package.","wrong":"from nsj_multi_database_lib.dao_base import DaoBase","symbol":"DaoBase","correct":"from nsj_multi_database_lib.dao.dao_base import DaoBase"},{"symbol":"TransactionalDao","correct":"from nsj_multi_database_lib.dao.transactional_dao import TransactionalDao"}],"quickstart":{"code":"import os\nfrom nsj_multi_database_lib.connection.connection_pool import ConnectionPool\nfrom nsj_multi_database_lib.connection.database_manager import DatabaseManager\nfrom sqlalchemy import text\n\n# Mock Database setup for example (using SQLite in-memory)\nDB_NAME_DEFAULT = \"default_db\"\nDB_NAME_AUDIT = \"audit_db\"\n\n# NOTE: In a real application, connection_string would use actual DB credentials.\n# Example for PostgreSQL: \"postgresql://user:password@host:port/database\"\nDATABASE_CONFIGS = {\n    DB_NAME_DEFAULT: {\n        \"engine\": \"sqlite\",\n        \"db\": \":memory:\",\n        \"connection_string\": \"sqlite:///:memory:\",\n        \"schema\": None,\n        \"label\": DB_NAME_DEFAULT\n    },\n    DB_NAME_AUDIT: {\n        \"engine\": \"sqlite\",\n        \"db\": \":memory:\",\n        \"connection_string\": \"sqlite:///:memory:\",\n        \"schema\": None,\n        \"label\": DB_NAME_AUDIT\n    }\n}\n\n# 1. Initialize the connection pool with your database configurations\nConnectionPool.configure(DATABASE_CONFIGS)\n\ntry:\n    print(\"\\n--- Using Default Database ---\")\n    # 2. Get a database session using the context manager\n    with DatabaseManager.get_session(DB_NAME_DEFAULT) as session:\n        # Example operations with SQLAlchemy 1.x compatible syntax\n        session.execute(text(\"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)\"))\n        session.execute(text(\"INSERT INTO users (id, name) VALUES (1, 'Alice')\"))\n        session.execute(text(\"INSERT INTO users (id, name) VALUES (2, 'Bob')\"))\n        session.commit()\n        result = session.execute(text(\"SELECT * FROM users\")).fetchall()\n        print(f\"Retrieved from {DB_NAME_DEFAULT}: {result}\")\n\n    print(\"\\n--- Using Audit Database ---\")\n    with DatabaseManager.get_session(DB_NAME_AUDIT) as session:\n        session.execute(text(\"CREATE TABLE logs (id INTEGER PRIMARY KEY, event TEXT)\"))\n        session.execute(text(\"INSERT INTO logs (id, event) VALUES (1, 'User Alice created')\"))\n        session.commit()\n        result = session.execute(text(\"SELECT * FROM logs\")).fetchall()\n        print(f\"Retrieved from {DB_NAME_AUDIT}: {result}\")\n\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")\nfinally:\n    # 3. Always close connections when done to release resources\n    ConnectionPool.close_all_connections()\n    print(\"\\nAll database connections closed.\")","lang":"python","description":"This quickstart demonstrates how to configure multiple in-memory SQLite databases using `nsj-multi-database-lib`. It shows how to initialize the `ConnectionPool` with a dictionary of database configurations, obtain sessions for different databases using `DatabaseManager.get_session()`, and perform basic SQL operations within a transactional context. Remember to replace the SQLite in-memory setup with your actual database connection strings and credentials."},"warnings":[{"fix":"Update your `ConnectionPool.configure()` call to pass a dictionary of configurations. For example, `ConnectionPool.configure({'my_db': {'engine': 'pg', 'connection_string': '...'}})`.","message":"The `ConnectionPool.configure()` method signature changed significantly in version 2.0.0. It now expects a dictionary where keys are database labels (strings) and values are configuration dictionaries, instead of a list of `DatabaseConnectionConfigDTO` objects.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure your project's `requirements.txt` or `pyproject.toml` pins `SQLAlchemy` to a `1.x` version (e.g., `SQLAlchemy~=1.4.0`). Do not install `SQLAlchemy 2.x` if you are using `nsj-multi-database-lib`.","message":"This library explicitly depends on `SQLAlchemy` versions less than 2.0.0 (e.g., `SQLAlchemy>=1.4.0,<2.0.0`). Attempting to use `SQLAlchemy 2.x` will lead to dependency conflicts or runtime errors, as its API has breaking changes.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always initialize the connection pool at application startup using `ConnectionPool.configure(your_configs_dict)` before any database operations.","message":"Failure to call `ConnectionPool.configure()` before attempting to retrieve a session via `DatabaseManager.get_session()` will result in an `AttributeError` or `TypeError`.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Verify that the database label passed to `DatabaseManager.get_session()` exactly matches one of the keys in the `DATABASE_CONFIGS` dictionary used for `ConnectionPool.configure()`.","cause":"Attempting to get a session for a database label that was not configured during `ConnectionPool.configure()`.","error":"KeyError: 'my_unregistered_db_label'"},{"fix":"Ensure `ConnectionPool.configure(DATABASE_CONFIGS)` is executed at the start of your application, typically once, before any database session is requested.","cause":"`ConnectionPool.configure()` was not called before `DatabaseManager.get_session()`, meaning the database manager was not properly initialized.","error":"AttributeError: 'NoneType' object has no attribute 'get_session'"},{"fix":"Double-check the `connection_string` in your `DATABASE_CONFIGS` for typos, correct usernames, passwords, hostnames, and port numbers. Test the connection string directly with `sqlalchemy.create_engine()` if necessary.","cause":"Incorrect database connection string, credentials, host, or port specified in the `DATABASE_CONFIGS`.","error":"sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) FATAL: password authentication failed for user \"wrong_user\""}]}