Other tools#
The DB-API#
agensgraph.dbapi is the driver’s PEP 249 module, for
libraries that drive any database through that interface:
>>> import agensgraph.dbapi
>>> agensgraph.dbapi.apilevel, agensgraph.dbapi.threadsafety, agensgraph.dbapi.paramstyle
('2.0', 2, 'pyformat')
>>> other = agensgraph.dbapi.connect("host=localhost dbname=docs user=agens")
>>> type(other).__name__
'Connection'
>>> other.close()
connect() returns the same Connection as agensgraph.connect(), with the graph types and the
server check. The module also has the type constructors (Date, Timestamp, Binary, …) and
the exception hierarchy, as the very classes psycopg raises, so a library that matches on
module.IntegrityError matches the exceptions it really receives. conn.closed and
conn.broken let such a library tell a closed connection from a failed one without reading
messages.
agensgraph.dbapi.__version__ is psycopg’s version, which is what a library asking that module for
its version wants; the driver’s own is agensgraph.__version__.
SQLAlchemy#
SQLAlchemy’s psycopg dialect works with the driver’s DB-API module in place of psycopg’s. Pass it
as module:
import agensgraph.dbapi
from sqlalchemy import create_engine, text
engine = create_engine("postgresql+psycopg://agens@localhost/docs", module=agensgraph.dbapi)
with engine.connect() as session:
session.execute(text("SET graph_path = moviekb"))
rows = session.execute(
text(r"MATCH (m\:movie {title: :title}) RETURN m"), {"title": "Inception"}
).all()
rows holds Vertex values, and the string parameter is sent as text, as everywhere in this
driver. Three things to know:
Escape a colon that starts a label. SQLAlchemy reads
:nameas a bound parameter when nothing word-like comes before the colon, so(:movie)and-[:acted_in]->must be written(\:movie)and-[\:acted_in]->, in a raw string.(m:movie)is left alone.Select the graph on each connection, with
SET graph_pathas above, anALTER ROLE ... SET graph_pathdefault, or a pool event listener. SQLAlchemy rolls back when it returns a connection to its pool, and that undoes aSETmade inside the transaction, so select it again after every rollback, or give the role a default.Use
text()for Cypher. SQLAlchemy’s expression language builds SQL; a Cypher statement goes throughtext()with bound parameters.
To use a URL of its own, such as postgresql+agensgraph://, subclass the dialect and register it:
from sqlalchemy.dialects import registry
from sqlalchemy.dialects.postgresql.psycopg import PGDialect_psycopg
class AgensGraphDialect(PGDialect_psycopg):
driver = "agensgraph"
supports_statement_cache = True
@classmethod
def import_dbapi(cls):
import agensgraph.dbapi
return agensgraph.dbapi
registry.register("postgresql.agensgraph", "myapp.db", "AgensGraphDialect")
The server’s version string matches the PostgreSQL dialect’s own pattern, so SQLAlchemy detects the PostgreSQL version as usual.
A psycopg connection the driver did not make#
The driver registers its graph types only on the connections it makes, never on psycopg’s global
adapters, so a plain psycopg.connect() in the same process is untouched. On such a connection a
vertex is the text the server printed:
>>> import psycopg
>>> plain = psycopg.connect("host=localhost dbname=docs user=agens", autocommit=True)
>>> plain.execute("SET graph_path = moviekb")
<psycopg.Cursor ...>
>>> plain.execute("MATCH (m:movie {title: 'Inception'}) RETURN m").fetchone()[0][:21]
'movie[3.5]{"plot": "A'
To read graph values on a connection you made yourself, register the driver’s adapters on it:
>>> from agensgraph.adapters import register_text
>>> register_text(plain)
>>> plain.execute("MATCH (m:movie {title: 'Inception'}) RETURN m").fetchone()
(Vertex(movie[3.5]),)
>>> plain.close()
register_text reads vertices, edges, paths and identities in the text rendering. It also installs
the driver’s way of sending values on that connection: a str goes as text, a dict as
jsonb, and a NaN is refused, as described in Parameters. Everything else in this
manual, such as execute_query(), the label table and the bulk loaders, needs an
agensgraph.Connection.