PolyNOM sessions and queries

Sessions and transactions

Import Session from polynom.session. Create Session(application, log_user=None) inside an active application and enter its context before working with models. Each session has its own connection. A session begins in state INITIALIZED, changes to ACTIVE on entry, and reaches COMPLETED after commit() or rollback(). Use get_session_state() to inspect its state.

Method Behavior
add(model, tracking=True), add_all(models, tracking=True) Insert one or more model instances in the current transaction. Tracking lets later field assignments produce updates.
delete(model), delete_all(models) Delete one or more rows from the current transaction. PolyNOM invalidates any deleted instance it tracks.
flush() Write updates for changed fields on tracked instances. Queries flush pending updates before executing. The transaction remains open.
commit() Flush and commit the transaction. Tracked instances become inactive.
rollback() Roll back the transaction and invalidate the tracked instances.
detach_child(parent, attr_name) Clear the named Relationship on a parent object. A configured delete-orphan relationship can delete the detached object in this session. Update the database foreign key field yourself when retaining the row.

A session that exits while active rolls back and closes its cursor and connection. Create another session after a commit or rollback. Query results are normally tracked. If a query returns a new instance of the same row, PolyNOM tracks the new one and invalidates the previous instance. Keep writes inside the session that owns the instance.

An optional log_user labels the field changes written to the database change log when the session flushes tracked updates. Application statement logging is a separate option. Logging

Queries

Call Model.query(session) to create a Query for a model. The builder methods update the query object, so create a fresh query when you want a different filter.

Method Behavior
filter_by(**kwargs) Add equality conditions joined by AND. Keys are the Python names of declared fields, and values are bound parameters.
filter(*expressions) Add conditions written as (operator, database_field_name, value) tuples. Use fixed operators and field names in application code because they are inserted into SQL. The value is bound separately.
order_by(field_name) Order by a declared Python field in ascending order.
limit(n) Limit the result rows. Use a nonnegative integer.
join(related_model, on=None) Add a SQL left join. PolyNOM can infer a join from a declared foreign key. An explicit on value is SQL text, so keep it fixed in code. Plain joins return the base model and can repeat it when several rows match.
all() Return the matching model instances.
first() Return the first matching model or None. Add an ordering when the result order matters.
get(pk_value) Retrieve a row by its first primary key field, normally _entry_id. Return None if it is absent. This is a direct lookup.
exists() Return whether a matching row exists.
count() Count rows in the base table that match the filters. The implementation ignores joins, ordering, and limits for the count.
update(values) Set attributes on matching models and return the number changed. The session flushes or commits the updates.
delete() Delete matching rows and return the number selected for deletion. Commit to persist the changes.

first() and exists() add their own row limit. Call them without a preceding limit(). distinct() accepts the call but does not emit DISTINCT in 0.4.0. This release also has an import error in options(JoinedLoad(...)). Use separate queries to fetch related rows. Relationships

Filter, update, and roll back

This example uses a running plain Prism 2.2 server and the same connection environment variables as the getting started guide. It creates its own namespace, commits a filtered update, then rolls back a deletion. It prints Review docs 3.

from contextlib import closing
from os import getenv
from uuid import uuid4

import polypheny
from polynom.application import Application
from polynom.model.model import BaseModel
from polynom.schema.field import Field
from polynom.schema.polytypes import Integer, VarChar
from polynom.schema.schema import BaseSchema
from polynom.schema.schema_registry import polynom_schema
from polynom.session import Session

address = (getenv("POLYPHENY_HOST", "127.0.0.1"), int(getenv("POLYPHENY_PORT", "20590")))
user = getenv("POLYPHENY_USER", "pa")
password = getenv("POLYPHENY_PASSWORD", "")
app_id = str(uuid4())
namespace = f"polynom_tasks_{uuid4().hex}"


@polynom_schema
class TaskSchema(BaseSchema):
    namespace_name = namespace
    entity_name = "tasks"
    fields = [
        Field("title", VarChar(80), nullable=False),
        Field("priority", Integer(), nullable=False),
    ]


class Task(BaseModel):
    schema = TaskSchema()

    def __init__(self, title, priority, _entry_id=None):
        super().__init__(_entry_id)
        self.title = title
        self.priority = priority


with closing(polypheny.connect(address, username=user, password=password, transport="plain")) as cleanup:
    try:
        with Application(app_id, address, user=user, password=password) as app:
            with Session(app) as session:
                session.add_all([Task("Draft docs", 1), Task("Review docs", 2)])
                session.commit()

            with Session(app) as session:
                changed = Task.query(session).filter_by(title="Review docs").update({"priority": 3})
                assert changed == 1
                session.commit()

            with Session(app) as session:
                deleted = Task.query(session).filter_by(title="Review docs").delete()
                assert deleted == 1
                session.rollback()

            with Session(app) as session:
                selected = Task.query(session).filter((">=", "priority", 2)).order_by("title").all()
                assert len(selected) == 1
                print(selected[0].title, selected[0].priority)
    finally:
        with closing(cleanup.cursor()) as cursor:
            cursor.execute(f'DROP NAMESPACE IF EXISTS "{namespace}"')
            cursor.execute(
                'DELETE FROM "polynom_internal"."snapshot" WHERE "_entry_id" = ?',
                (app_id,),
            )
            cleanup.commit()
© Polypheny GmbH. All Rights Reserved.