docs: def create_graph_database_interface(db: Engine,
                                      session: Session,
                                      declarative_meta: DeclarativeMeta,
                                      relationship: RelationshipProperty) -> GraphDatabaseInterface:
      """
      Creates a graph database interface to the database specified by the input arguments.
  
      Note that the created database model assumes that the database enforces constraints such
      as foreign key validity. This is _not true_ for SQLite databases for example, where
      `PRAGMA foreign_key` is off by default. If you don't ensure that the database enforces
      constraints, then some of the database tables might end up containing invalid records.
  
      SQLAlchemy example:
          >>> try:
          >>>     import sqlalchemy
          >>>     from sqlalchemy.ext.declarative import declarative_base
          >>>     from sqlalchemy.orm import sessionmaker
          >>> except ImportError:
          >>>     raise ImportError("SQLAlchemy not found.")
          >>>
          >>> # Import this method
          >>> # import create_graph_database_interface
          >>>
          >>> # Database interface setup.
          >>> Base = declarative_base()
          >>> engine = sqlalchemy.create_engine("sqlite://")
          >>> Session = sessionmaker(bind=engine)
          >>> dbi: GraphDatabaseInterface = create_graph_database_interface(
          >>>     sqlalchemy,
          >>>     Session(),
          >>>     Base,
          >>>     sqlalchemy.orm.relationship
          >>> )
          >>>
          >>> # Complete database reset.
          >>> Base.metadata.drop_all(engine)
          >>> Base.metadata.create_all(engine)
          >>>
          >>> # Database interface test.
          >>> node: DBNode = dbi.Node("Some vertex")
          >>> dbi.session.add(node)
          >>> dbi.session.commit()
          >>>
          >>> node = dbi.Node.find_by_name("Some vertex")
          >>> if node is not None:
          >>>     print("Got it!")
  
      Flask-SQLAlchemy example:
          >>> try:
          >>>     from flask import Flask
          >>>     from flask_sqlalchemy import SQLAlchemy
          >>> except ImportError:
          >>>     raise ImportError("The flask and flask-sqlalchemy libraries are required in this example.")
          >>>
          >>> # Import this method
          >>> # import create_graph_database_interface
          >>>
          >>> # Set up the Flask application.
          >>> app = Flask(__name__)
          >>> app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite://"
          >>> flask_db = SQLAlchemy(app)
          >>>
          >>> # Create the database interface
          >>> dbi: GraphDatabaseInterface = create_graph_database_interface(
          >>>     flask_db,
          >>>     flask_db.session,
          >>>     flask_db.Model,
          >>>     flask_db.relationship
          >>> )
          >>>
          >>> # Complete database reset.
          >>> flask_db.drop_all()
          >>> flask_db.create_all()
          >>>
          >>> # Database interface test.
          >>> node: DBNode = dbi.Node("Some vertex")
          >>> dbi.session.add(node)
          >>> dbi.session.commit()
          >>>
          >>> node = dbi.Node.find_by_name("Some vertex")
          >>> if node is not None:
          >>>     print("Got it!")
  
      Arguments:
          db (Engine): The SQLAlchemy or Flask-SQLAlchemy database to use.
          session (Session): The session database operations are executed on.
          declarative_meta (DeclarativeMeta): The metaclass that should be the base class
                                              of the database model classes.
          relationship (RelationshipProperty): Relationship property generator.
  
      Returns:
          A graph database interface object the user can use to query and manipulate the database
          that is specified by the input arguments of the method.
      """
  
      class DBNode(declarative_meta):
          """
          Declarative database object model representing a node.
          """
  
          # Metaclass definition
          # ------------------------------------------------------------
  
          # __bind_key__ = bind_key  # Variable name must not be changed.
          __tablename__ = "nodes"  # Variable name must not be changed.
  
          _creation_date = db.Column(db.Date,
                                     nullable=False,
                                     default=datetime.date.today)
  
          are_neighbors_cached = db.Column(db.Boolean,
                                           default=False)
          name = db.Column(db.String(100),
                           primary_key=True)
          external_id = db.Column(db.String(100))
  
          edges_where_source = relationship("DBEdge",
                                            primaryjoin="DBNode.name==DBEdge.source_name",
                                            cascade="all, delete-orphan",
                                            backref="source")
          edges_where_target = relationship("DBEdge",
                                            primaryjoin="DBNode.name==DBEdge.target_name",
                                            cascade="all, delete-orphan",
                                            backref="target")
  
          # Initialization
          # ------------------------------------------------------------
  
          def __init__(self, node_name: str, external_id: str = None):
              """
              Initialization.
  
              Arguments:
                  node_name (str): The name of the node.
                  external_id (str): The external ID of the node.
              """
              if node_name is None:
                  raise ValueError("Node name must not be None.")
  
              node_name = node_name.strip()
              if len(node_name) == 0:
                  raise ValueError("Node name must contain non-whitespace characters.")
  
              self.name = node_name
              self.external_id = external_id.strip() if external_id is not None else None
  
          # Special methods
          # ------------------------------------------------------------
  
          def __repr__(self) -> str:
              """
              The string representation of the object.
              """
              return "DBNode(name={}, external_id={})".format(self.name, self.external_id)
  
          # Properties
          # ------------------------------------------------------------
  
          @property
          def creation_date(self) -> datetime.date:
              """
              The date when the node was created.
              """
              return self._creation_date
  
          @property
          def edges(self) -> List["DBEdge"]:
              """
              The edges where this node is one of the endpoints.
              """
              result: List["DBEdge"] = []
              edges: List["DBEdge"] = self.edges_where_target
              if edges is not None:
                  result.extend(edges)
  
              edges = self.edges_where_source
              if edges is not None:
                  result.extend(edges)
  
              return result
  
          @property
          def neighbor_names(self) -> List[str]:
              """
              The names of the neighbors of the node that are currently in the database.
              """
              result: List[str] = []
              neighbors: List[str] = [edge.source_name
                                      for edge in DBEdge.query.filter_by(target_name=self.name)]
              if neighbors is not None:
                  result.extend(neighbors)
  
              neighbors = [edge.target_name
                           for edge in DBEdge.query.filter_by(source_name=self.name)]
              if neighbors:
                  result.extend(neighbors)
  
              return result
  
          @property
          def neighbors(self) -> List["DBNode"]:
              """
              The list of neighbors the node currently has in the database.
              """
              result: List[DBNode] = []
  
              neighbors: List[DBNode] = [edge.source for edge in DBEdge.query.filter_by(target_name=self.name)]
              if neighbors is not None:
                  result.extend(neighbors)
  
              neighbors = [edge.target for edge in DBEdge.query.filter_by(source_name=self.name)]
              if neighbors is not None:
                  result.extend(neighbors)
  
              return result
  
          # Class methods
          # ------------------------------------------------------------
  
          @classmethod
          def find_by_name(cls, node_name: str) -> Optional["DBNode"]:
              """
              Returns the `DBNode` with the given name if such a node exists in the database.
  
              Arguments:
                  node_name (str): The queried node name.
  
              Returns:
                  The node with the given name if it exists.
              """
              return cls.query.filter_by(name=node_name).first()
  
          @classmethod
          def find_by_external_id(cls, external_id: str) -> Optional["DBNode"]:
              """
              Returns the `DBNode` with the given external ID if such a node exists in the database.
  
              Arguments:
                  external_id (str): The queried external ID.
  
              Returns:
                  The node with the given external ID if it exists.
              """
              if external_id is None:
                  return None
  
              nodes: Optional[List[DBNode]] = cls.query.filter_by(external_id=external_id)
              return nodes.first() if len(nodes) == 1 else None
  
      class DBEdge(declarative_meta):
          """
          Declarative database object model representing an edge.
          """
  
          # Metaclass definition
          # ------------------------------------------------------------
  
          # __bind_key__ = bind_key  # Variable name must not be changed.
          __tablename__ = "edges"  # Variable name must not be changed.
  
          _creation_date = db.Column(db.Date,
                                     nullable=False,
                                     default=datetime.date.today)
  
          source_name = db.Column(db.String,
                                  db.ForeignKey("nodes.name"),
                                  db.CheckConstraint("source_name < target_name"),
                                  primary_key=True)
          target_name = db.Column(db.String,
                                  db.ForeignKey("nodes.name"),
                                  db.CheckConstraint("source_name < target_name"),
                                  primary_key=True)
          weight = db.Column(db.Float,
                             db.CheckConstraint("weight > 0"),
                             default=1)
  
          # Initialization
          # ------------------------------------------------------------
  
          def __init__(self, source_name: str, target_name: str, weight: float = 1):
              """
              Initialization.
  
              Arguments:
                  source_name (str): The name of the source node of the edge.
                  target_name (str): The name of the target node of the edge.
                  weight (float): The weight of the edge.
              """
              if source_name is None or target_name is None or source_name == target_name:
                  raise ValueError("Invalid source and target name pair: {} - {}".format(
                      source_name, target_name)
                  )
  
              # Make sure the order is right, we don't want the graph to be directed.
              if source_name < target_name:
                  self.source_name = source_name
                  self.target_name = target_name
              else:
                  self.source_name = target_name
                  self.target_name = source_name
  
              self.weight = weight
  
          # Special methods
          # ------------------------------------------------------------
  
          def __repr__(self):
              """
              The string representation of the object.
              """
              return "DBEdge({} <> {})".format(self.source_name, self.target_name)
  
          # Properties
          # ------------------------------------------------------------
  
          @property
          def creation_date(self) -> datetime.date:
              """
              The date when the edge was created.
              """
              return self._creation_date
  
          # Class methods
          # ------------------------------------------------------------
  
          @classmethod
          def find_by_name(cls, source_name: str, target_name: str) -> Optional["DBEdge"]:
              """
              Returns the `DBEdge` connecting the edges with the given names if such an edge
              currently exists in the database.
  
              Arguments:
                  source_name (str): The name of one of the endpoints of the queried edge.
                  target_name (str): The name of the other endpoint of the queried edge.
  
              Returns:
                  The edge connecting the given nodes in the database if such an edge exists.
              """
              if source_name < target_name:
                  return cls.query.filter_by(source_name=source_name, target_name=target_name).first()
              else:
                  return cls.query.filter_by(source_name=target_name, target_name=source_name).first()
  
      return GraphDatabaseInterface(session, DBNode, DBEdge)