Hello, I am the psycopg maintainer. ![]()
Template strings look the most exciting thing happening since DBAPI. I have seen they have been just merged in Python 3.14, thank you very much!
I have just started to add support in psycopg 3, and it looks pretty good! Please see here the current unit tests for an idea of how it looks:
vstr = "hello"
cur = await aconn.execute(t"select {vstr}")
assert await cur.fetchone() == ("hello",)
So far so good. Often times people have a list of fields and values to work on, and it’s easy to compose them into a query. Before that, we would have used the psycopg.sql objects. Now it.s easy… almost?
fields = t""
for i, name in enumerate(("foo", "bar", "baz")):
if i:
fields += ", "
fields += t"{i} as {name:i}"
cur = await aconn.execute(t"select {fields}")
assert await cur.fetchone() == (0, 1, 2)
assert cur.description[0].name == "foo"
This is not a new pattern: it is exactly str.join(), but taking a sequence of Templates or strings and returning a Template. It comes over and over: join a list of fields by commas, join a list of conditions by AND, join a list of snippets by empty string…
I have big expectations that the end user will be able to express the above with a much more succint:
fields = t','.join(
t"{i} as {name:i}" for i, name in enumerate(("foo", "bar", "baz"))
)
cur = await aconn.execute(t"select {fields}")
However Template.join() is left out of the interface. I find this bizarre: Template already supports the + operator and joining a sequence is pretty much a generalization of the concatenation.
The above pattern is so useful that, if not available, I will stretch the existing sql.SQL object to allow to take templates as join() input:
fields = sql.SQL(',').join(
t"{i} as {name:i}" for i, name in enumerate(("foo", "bar", "baz"))
)
This is a worst option for the end users because:
- with string templates, the need of using
psycopg.sqlobject pretty much disappears - a Template as a value in
psycopg.SQLobject is only handled as special case in.execute(Template), using it asexecute(Composable)would try to adapt template to Postgres syntax and fail.
Therefore, I don’t ask it for myself, because the problem is solved on my part, but I ask it for the end users of whoever will use template strings: please considering adding Template.join() before feature freeze.
Thank you very much for your amazing work ![]()