Package: advanced-alchemy
Advanced AlchemyProjectStatusCI/CDQualityCommunityMetaCheck out theproject documentation📚 for more information.AboutA carefully crafted, thoroughly tested, optimized companion library for SQLAlchemy,
offering features such as:Sync and async repositories, featuring common CRUD and highly optimized bulk operationsIntegration with major web frameworks including Litestar, Starlette, FastAPI, Sanic.Custom-built alembic configuration and CLI with optional framework integrationUtility base classes with audit columns, primary keys and utility functionsOptimized JSON types including a custom JSON type for Oracle.Integrated support for UUID6 and UUID7 usinguuid-utils(install with theuuidextra)Pre-configured base classes with audit columns UUID or Big Integer primary keys and
asentinel column.Synchronous and asynchronous repositories featuring:Common CRUD operations for SQLAlchemy modelsBulk inserts, updates, upserts, and deletes with dialect-specific enhancementslambda_stmtwhen possible
for improved query building performanceIntegrated counts, pagination, sorting, filtering withLIKE,IN, and dates before and/or after.Tested support for multiple database backends including:SQLite viaaiosqliteorsqlitePostgres viaasyncpgorpsycopg3 (async or sync)MySQL viaasyncmyOracle viaoracledb (async or sync)(tested on 18c and 23c)Google Spanner viaspanner-sqlalchemyDuckDB viaduckdb_engineMicrosoft SQL Server viapyodbcoraioodbcCockroachDB viasqlalchemy-cockroachdb (async or sync)UsageInstallationpipinstalladvanced-alchemy[!IMPORTANT]Check outthe installation guidein our official documentation!RepositoriesAdvanced Alchemy includes a set of asynchronous and synchronous repository classes for easy CRUD operations on your SQLAlchemy models.fromadvanced_alchemy.baseimportUUIDBasefromadvanced_alchemy.filtersimportLimitOffsetfromadvanced_alchemy.repositoryimportSQLAlchemySyncRepositoryfromsqlalchemyimportcreate_enginefromsqlalchemy.ormimportMapped,sessionmakerclassUser(UUIDBase):# you can optionally override the generated table name by manually setting it.__tablename__="user_account"# type: ignore[assignment]email:Mapped[str]name:Mapped[str]classUserRepository(SQLAlchemySyncRepository[User]):"""User repository."""model_type=User# use any compatible sqlalchemy engine.engine=create_engine("duckdb:///:memory:")session_factory=sessionmaker(engine,expire_on_commit=False)# Initializes the database.withengine.begin()asconn:User.metadata.create_all(conn)withsession_factory()asdb_session:repo=UserRepository(session=db_session)# 1) Create multiple users with `add_many`bulk_users=[{"email":'cody@advanced-alchemy.dev','name':'Cody'},{"email":'janek@advanced-alchemy.dev','name':'Janek'},{"email":'peter@advanced-alchemy.dev','name':'Peter'},{"email":'jacob@advanced-alchemy.dev','name':'Jacob'}]objs=repo.add_many([User(**raw_user)forraw_userinbulk_users])db_session.commit()print(f"Created{len(objs)}new objects.")# 2) Select paginated data and total row count.  Pass additional filters as kwargscreated_objs,total_objs=repo.list_and_count(LimitOffset(limit=10,offset=0),name="Cody")print(f"Selected{len(created_objs)}records out of a total of{total_objs}.")# 3) Let's remove the batch of records selected.deleted_objs=repo.delete_many([new_obj.idfornew_objincreated_objs])print(f"Removed{len(deleted_objs)}records out of a total of{total_objs}.")# 4) Let's count the remaining rowsremaining_count=repo.count()print(f"Found{remaining_count}remaining records after delete.")For a full standalone example, see the samplehereServicesAdvanced Alchemy includes an additional service class to make working with a repository easier. This class is designed to accept data as a dictionary or SQLAlchemy model and it will handle the type conversions for you.Here's the same example from above but using a service to create the data:fromadvanced_alchemy.baseimportUUIDBasefromadvanced_alchemy.filtersimportLimitOffsetfromadvanced_alchemyimportSQLAlchemySyncRepository,SQLAlchemySyncRepositoryServicefromsqlalchemyimportcreate_enginefromsqlalchemy.ormimportMapped,sessionmakerclassUser(UUIDBase):# you can optionally override the generated table name by manually setting it.__tablename__="user_account"# type: ignore[assignment]email:Mapped[str]name:Mapped[str]classUserRepository(SQLAlchemySyncRepository[User]):"""User repository."""model_type=UserclassUserService(SQLAlchemySyncRepositoryService[User]):"""User repository."""repository_type=UserRepository# use any compatible sqlalchemy engine.engine=create_engine("duckdb:///:memory:")session_factory=sessionmaker(engine,expire_on_commit=False)# Initializes the database.withengine.begin()asconn:User.metadata.create_all(conn)withsession_factory()asdb_session:service=UserService(session=db_session)# 1) Create multiple users with `add_many`objs=service.create_many([{"email":'cody@advanced-alchemy.dev','name':'Cody'},{"email":'janek@advanced-alchemy.dev','name':'Janek'},{"email":'peter@advanced-alchemy.dev','name':'Peter'},{"email":'jacob@advanced-alchemy.dev','name':'Jacob'}])print(objs)print(f"Created{len(objs)}new objects.")# 2) Select paginated data and total row count.  Pass additional filters as kwargscreated_objs,total_objs=service.list_and_count(LimitOffset(limit=10,offset=0),name="Cody")print(f"Selected{len(created_objs)}records out of a total of{total_objs}.")# 3) Let's remove the batch of records selected.deleted_objs=service.delete_many([new_obj.idfornew_objincreated_objs])print(f"Removed{len(deleted_objs)}records out of a total of{total_objs}.")# 4) Let's count the remaining rowsremaining_count=service.count()print(f"Found{remaining_count}remaining records after delete.")Web FrameworksAdvanced Alchemy works with nearly all Python web frameworks. Several helpers for popular libraries are included, and additional PRs to support others are welcomed.LitestarAdvanced Alchemy is the official SQLAlchemy integration for Litestar.In addition to installed withpip install advanced-alchemy, it can also be installed installed as a Litestar extra withpip install litestar[sqlalchemy].fromlitestarimportLitestarfromlitestar.plugins.sqlalchemyimportSQLAlchemyPlugin,SQLAlchemyAsyncConfig# alternately...# from advanced_alchemy.extensions.litestar.plugins import SQLAlchemyPlugin# from advanced_alchemy.extensions.litestar.plugins.init.config import SQLAlchemyAsyncConfigalchemy=SQLAlchemyPlugin(config=SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///test.sqlite"),)app=Litestar(plugins=[alchemy])For a full Litestar example, checkhereFastAPIfromfastapiimportFastAPIfromadvanced_alchemy.configimportSQLAlchemyAsyncConfigfromadvanced_alchemy.extensions.starletteimportStarletteAdvancedAlchemyapp=FastAPI()alchemy=StarletteAdvancedAlchemy(config=SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///test.sqlite"),app=app,)For a full CRUD example, seehereStarlettefromstarlette.applicationsimportStarlettefromadvanced_alchemy.configimportSQLAlchemyAsyncConfigfromadvanced_alchemy.extensions.starletteimportStarletteAdvancedAlchemyapp=Starlette()alchemy=StarletteAdvancedAlchemy(config=SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///test.sqlite"),app=app,)SanicfromsanicimportSanicfromsanic_extimportExtendfromadvanced_alchemy.configimportSQLAlchemyAsyncConfigfromadvanced_alchemy.extensions.sanicimportSanicAdvancedAlchemyapp=Sanic("AlchemySanicApp")alchemy=SanicAdvancedAlchemy(sqlalchemy_config=SQLAlchemyAsyncConfig(connection_string="sqlite+aiosqlite:///test.sqlite"),)Extend.register(alchemy)ContributingAllJoltprojects will always be a community-centered, available for contributions of any size.Before contributing, please review thecontribution guide.If you have any questions, reach out to us onDiscord, our org-wideGitHub discussionspage,
or theproject-specific GitHub discussions page.AJolt OrganizationProject