Skip to content

Feature request: NestJS-style DatabaseModule for ORM integration #130

@ItayTheDar

Description

@ItayTheDar

Summary

Introduce a NestJS-style database integration module for PyNest, similar in spirit to NestJS dynamic modules like TypeOrmModule.forRoot(...) and TypeOrmModule.forFeature(...).

The current ORM integration encourages app code to create a global OrmProvider instance, usually in config.py, and import it directly from services. That works for small examples, but it does not feel very Nest-like and makes lifecycle, dependency injection, testing, and future repository patterns harder to model cleanly.

Current pattern

Typical app code today looks like this:

# src/config.py
config = OrmProvider(
    db_type="postgresql",
    config_params={...},
)

# service.py
from src.config import config

with config.get_session() as session:
    ...

Problems with this pattern:

  • Database configuration is a global object rather than an injected dependency.
  • Services import infrastructure directly instead of receiving dependencies through DI.
  • DB lifecycle has to be managed manually or by app-specific provider glue.
  • Sessions are manually opened in every service method.
  • It is hard to support multiple DB connections, test replacement providers, or a repository-oriented API later.
  • The app module does not clearly express that database infrastructure is part of the module graph.

Proposed direction

Add a framework-level DatabaseModule with a dynamic-module style API:

@Module(
    imports=[
        DatabaseModule.for_root(
            driver="postgresql",
            host="localhost",
            database="default_nest_db",
            user="postgres",
            password="postgres",
            port=5432,
        ),
        AuthorModule,
        BookModule,
    ],
)
class AppModule:
    pass

The module would register providers such as:

  • DATABASE_OPTIONS
  • DATABASE_ENGINE
  • DATABASE_SESSION_FACTORY
  • DatabaseService

DatabaseService would own lifecycle hooks:

@Injectable
class DatabaseService(OnModuleInit, OnModuleDestroy):
    def on_module_init(self):
        Base.metadata.create_all(bind=self.engine)

    def on_module_destroy(self):
        self.engine.dispose()

    def session(self):
        ...

App services would then receive the database dependency through DI:

@Injectable
class AuthorService:
    def __init__(self, db: DatabaseService):
        self.db = db

    def get_authors(self):
        with self.db.session() as session:
            return session.query(AuthorEntity).all()

Future extension

After DatabaseModule.for_root(...), add a repository-oriented API, similar to NestJS TypeOrmModule.forFeature(...):

@Module(
    imports=[DatabaseModule.for_feature([AuthorEntity])],
    providers=[AuthorService],
)
class AuthorModule:
    pass

Then services could receive repositories rather than raw sessions:

@Injectable
class AuthorService:
    def __init__(self, authors: Repository[AuthorEntity]):
        self.authors = authors

    def get_authors(self):
        return self.authors.find_all()

Suggested implementation phases

  1. Add DatabaseModule.for_root(...) and DatabaseService while preserving backward compatibility with OrmProvider.
  2. Update generated templates to prefer DatabaseModule.for_root(...) instead of global config = OrmProvider(...).
  3. Add tests for lifecycle behavior, DI replacement, and app startup/shutdown.
  4. Later, add DatabaseModule.for_feature(...) and repository injection.

Why this matters

This would make PyNest database integration feel much closer to NestJS:

  • database infrastructure becomes part of the module graph
  • configuration is explicit at the app-module boundary
  • lifecycle is owned by the database provider
  • services use dependency injection instead of global imports
  • testing becomes easier by overriding providers
  • the framework gets a clean path toward repository injection

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions