memory (sqla): new pep column in PubsubNode:

This column can be used for quick filtering on PEP nodes.

rel 476
This commit is contained in:
Goffi 2026-04-14 23:10:19 +02:00
commit 3aa58e73dc
3 changed files with 84 additions and 6 deletions

View file

@ -0,0 +1,42 @@
"""add "pep" to PubsubNode
Revision ID: 007439b3b0ce
Revises: f9ce59cfc13f
Create Date: 2026-04-12 00:46:56.674238
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "007439b3b0ce"
down_revision = "f9ce59cfc13f"
branch_labels = None
depends_on = None
def upgrade():
with op.batch_alter_table("pubsub_nodes", schema=None) as batch_op:
batch_op.add_column(
sa.Column(
"pep",
sa.Boolean(create_constraint=True),
server_default=sa.text("0"),
nullable=False,
)
)
batch_op.drop_constraint(batch_op.f("uq_pubsub_nodes_profile_id"), type_="unique")
batch_op.create_unique_constraint(
batch_op.f("uq_pubsub_nodes_profile_id"),
["profile_id", "service", "name", "pep"],
)
def downgrade():
with op.batch_alter_table("pubsub_nodes", schema=None) as batch_op:
batch_op.drop_constraint(batch_op.f("uq_pubsub_nodes_profile_id"), type_="unique")
batch_op.create_unique_constraint(
batch_op.f("uq_pubsub_nodes_profile_id"), ["profile_id", "service", "name"]
)
batch_op.drop_column("pep")

View file

@ -1188,6 +1188,7 @@ class Storage:
service: jid.JID,
name: str | None = None,
node_id: int | None = None,
pep: bool | None = None,
with_items: bool = False,
with_subscriptions: bool = False,
with_affiliations: bool = False,
@ -1203,6 +1204,7 @@ class Storage:
Can't be used with ``node_id``
@param node_id: node's ID
Can't be used with ``node_id` or ``create``
@param pep: if set, filter on PEP/non-PEP nodes
@param with_items: retrieve items in the same query
@param with_subscriptions: retrieve subscriptions in the same query
@param with_affiliations: retrieve affiliations in the same query
@ -1224,11 +1226,14 @@ class Storage:
# When querying by ID, we only need it.
stmt = select(PubsubNode).filter_by(id=node_id)
else:
stmt = select(PubsubNode).filter_by(
service=service,
profile_id=self.profiles[client.profile],
name=name,
)
filters = {
"service": service,
"profile_id": self.profiles[client.profile],
"name": name,
}
if pep is not None:
filters["pep"] = pep
stmt = select(PubsubNode).filter_by(**filters)
if with_items:
stmt = stmt.options(joinedload(PubsubNode.items))
if with_subscriptions:
@ -1444,11 +1449,37 @@ class Storage:
parent_node: PubsubNode | None = None,
linked_node: PubsubNode | None = None,
max_items: int = 0,
pep: bool = False,
) -> PubsubNode:
"""Create a new pubsub node.
@param client: The client creating the node.
@param service: The pubsub service JID.
For PEP nodes (pep=True), this should be the bare JID of the PEP owner.
@param name: The node name.
@param access_model: The access model for the node.
@param publish_model: The publish model for the node.
@param analyser: The analyser for the node.
@param type_: The node type.
@param subtype: The node subtype.
@param subscribed: Whether the creator is subscribed.
@param extra: Extra node metadata.
@param items: Initial items for the node.
@param affiliations: Initial affiliations for the node.
@param subscriptions: Initial subscriptions for the node.
@param parent_node: Parent node (for XEP-0496).
@param linked_node: Linked node (for XEP-0496).
@param max_items: Maximum number of items to persist (0 = unlimited).
@param pep: If True, this is a PEP-scoped node.
For PEP nodes, the service JID should be the bare JID of the PEP owner.
@return: The created node.
@raise ConflictError: If a node with the same name already exists.
"""
node = PubsubNode(
profile_id=self.profiles[client.profile],
service=service,
name=name,
pep=pep,
access_model=access_model,
publish_model=publish_model,
subscribed=subscribed,

View file

@ -615,12 +615,17 @@ class File(Base):
class PubsubNode(Base):
__tablename__ = "pubsub_nodes"
__table_args__ = (UniqueConstraint("profile_id", "service", "name"),)
__table_args__ = (UniqueConstraint("profile_id", "service", "name", "pep"),)
id = Column(Integer, primary_key=True)
profile_id = Column(ForeignKey("profiles.id", ondelete="CASCADE"))
service = Column(JID)
name = Column(Text, nullable=False)
pep = Column(
Boolean(create_constraint=True),
nullable=False,
server_default=false(),
)
access_model = Column(
Enum(
AccessModel,