I have an asynchronous python application with database using asyncpg to connect and I would like to avoid typing every query manually. I have found sqlalchemy core to be very helpful with that, but I strugle with one thing. I want my application to be able to create database schema on startup, instead of relying on it being already created and I haven't found an automatic way of doing so. What I would like is something like:
import asyncio
from sqlalchemy import Table, Column, Integer, String, MetaData
import asyncpg
metadata = MetaData()
people = Table(
"people",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("name", String)
)
class Database:
def __init__(self, pool: asyncpg.pool.Pool):
self.pool = pool
async def ensure_schema(self):
async with self.pool.acquire() as con:
await con.execute(
# this method doesn't really exist,
# I'm just looking for something that would
# do the same - return following query:
# CREATE TABLE IF NOT EXISTS people(id INTEGER PRIMARY KEY, name VARCHAR)
people.get_create_query(checkfirst=True)
)
async def main()
pool = await asyncpg.create_pool(host="127.0.0.1", port=5432, user="postgres", password="postgres", database="test")
db = Database(pool)
await db.ensure_schema()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
The problem here is, that sqlalchemy expects metadata
to be bound to an engine, but it doesn't support asynchronous engines. So I just want to get a CREATE query string from the declared table and pass it to my connection to execute.
Analogy for this may be people.select()
which doesn't get executed right away, it just creates an object that also has a string represantation that is the query to be executed.
I can have the sql schema in a separate file and load it on startup, but it doesn't feel right as on every change of schema, I need to change it in two places in my code. Any suggestions?