sqlalchemy-pglogical is a sqlalchemy extension to automatically send DDL through
pglogical.replicate_ddl_command
sqlalchemy-pglogical may be for you if:
- you use
sqlalchemyand/oralembicfor DDL, and - you use
pglogicalfor logical replication
There are two keys to using sqlalchemy-pglogical:
import sqlalchemy_pglogical- because of the way extendingsqlalchemyworks, you can do this in pretty much any file that is loaded before DDL is called- Explicitly define your schema. If you're using
sqlalchemy's declaritive syntax, you define your schema by adding__table_args__to each table:if you're usingBase = declarative_base() class User(Base): __tablename__ = "users" __table_args__ = {"schema": "public"}
sqlalchemycore and usingMetaDatato define your tables, addschemaas a keyword arg to yourMetaDatainitialization:metadata = Metadata(schema="public")
It probably makes the most sense to import it wherever you create your engine
to be sure it's always applied. For most apps, this is probably most important
for your migration toolchain (e.g. alembic), and less likely to be needed
for your running application. If you're relying on alembic to build your
sqlalchemy.engine (e.g, it's only defined in your alembic.ini), then you
should probably add this to your migration mako template.
from sqlalchemy import create_engine
import sqlalchemy_pglogicalWe currently assume you're using the default_ddl publication and only publish to that publication.
pglogical can't propagate {CREATE, DROP} INDEX CONCURRENTLY statements. sqlachemy-pglogical makes
no attempt to catch the CONCURRENTLY keyword in INDEX statements, so they will likely fail.
DDL operations are represented in SQLAlchemy 1.x with a subclass of DDLElement. To
extend a DDL type, you can do this:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.ddl import CreateTable
@compiles(CreateTable)
def visit_create_table(element, compiler, **kwargs) -> str:
normal_ddl_sql: str = compiler.visit_create_table(element, **kwargs)
modified: str = some_modification_we_define_elsewhere(normal_ddl_sql)
return modifiedWe use this to extend all subclasses of DDLElement and wrap them in pglogical.replicate_ddl_command