Source code for system.interfaces.query_processing.operators
#
# This is ExplainDB, educational database systems materials.
#
# Copyright (C) 2026 Prof. Dr. Jens Dittrich, Saarland University
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
#
"""Abstract interface for query-processing operators."""
from abc import ABC, abstractmethod
from typing import Self
# tuples are represented as dictionary from attribute name to attribute value
Tuple = dict
[docs]
class Operator(ABC):
"""
Abstract operator interface to construct QEPs.
"""
def __init__(self, parent: Self | None, children: list[Self] | None):
"""Initialize the operator as a node in a QEP operator tree.
:param parent: Parent operator that consumes the tuples pushed by this operator, or ``None`` for the root.
:param children: Child operators that feed tuples into this operator, or ``None`` for a leaf.
"""
self.parent = parent
self.children = children
[docs]
def set_parent(self, parent: Self) -> None:
"""Set the parent operator that this operator pushes its output tuples to.
:param parent: The parent operator to attach.
"""
self.parent = parent
[docs]
@abstractmethod
def interpret_open(self) -> None:
"""
Interpreter: `open()` method in push-based iterator model, i.e., initializes the operator.
"""
raise NotImplementedError
[docs]
@abstractmethod
def interpret_next(self, tup: Tuple) -> None:
"""
Interpreter: `next()` method in push-based iterator model, i.e., processes the given tuple and
optionally pushes the next tuple to the parent operator.
:param tup: Pushed tuple to process.
"""
raise NotImplementedError
[docs]
@abstractmethod
def interpret_close(self) -> None:
"""
Interpreter: `close()` method in push-based iterator model, i.e., closes the operator. This may be used to free
resources like temporary files.
"""
raise NotImplementedError
[docs]
@abstractmethod
def compile(self, emit: str = None) -> str:
"""
Compiler: Compiles the QEP rooted at `self` into Python code.
:param emit: Parent code to emit.
:return: Compiled QEP.
"""
raise NotImplementedError
[docs]
@abstractmethod
def dump(self, indent: int = 0) -> None:
"""
Prints the QEP rooted at `self`.
:param indent: Indentation level.
"""
raise NotImplementedError
[docs]
@staticmethod
def indent_emit_(emit: str, n: int = 1) -> str:
"""
Indents the given code to emit.
:param emit: Code to emit.
:param n: Indentation level.
:return: Indented code to emit.
"""
indent = " " * n
return f"\n{indent}".join(emit.split("\n"))
[docs]
@staticmethod
def indent_(n: int = 1) -> str:
"""
Creates an indentation.
:param n: Indentation level.
:return: Indentation.
"""
return " " * n