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