# `pglast.visitors` — Other ways to inspect and manipulate the AST

class pglast.visitors.Action

  Abstract action singleton.

class pglast.visitors.ActionMeta

  Metaclass used to implement action singleton.

class pglast.visitors.Add

  Marker used to tell the iterator to insert nodes in the current sequence.

  Return `(Add, node, ...)` from a visitor to insert one or more nodes after the current one.

class pglast.visitors.Ancestor(parent=None, node=None, member=None)

  Simple object to keep track of the node’s ancestors while it’s being visited.

  Parameters:

    - parent (Ancestor) – the parent of the new instance

    - node – the tracked object

    - member – either the name of the attribute or the index in the sequence that points to the tracked object in the parent container

  An instance of this class represent a particular ancestor in the hierarchy chain: it carries a reference that points to the higher item in the chain, the associated `ast.Node` instance and a member, either the attribute name or sequential index in the parent node: the latter happens when the parent node is actually a tuple, not an `Node` instance.

  Accessing an instance with a positive index returns the nth node up in the hierarchy.

  When applied (using the `@` operator) to an `ast.Node` instance will traverse that node returning the leaf one corresponding to the whole chain.

  Example:

      >>> tree = parse_sql('select 1')
      >>> root = Ancestor()
      >>> root
      ROOT
      >>> root@tree is tree
      True
      >>> root[0] is None
      True
      >>> select_stmt_path = root / (tree, 0) / (tree[0], 'stmt')
      >>> select_stmt_path
      ROOT → 0 → stmt
      >>> select_stmt_path@tree is tree[0].stmt
      True
      >>> select_stmt_path[0] is tree[0]
      True
      >>> columns_path = (select_stmt_path
      ...                 / (tree[0].stmt, 'targetList'))
      >>> first_col_path = (columns_path
      ...                   / (tree[0].stmt.targetList[0], 0))
      >>> first_col_path
      ROOT → 0 → stmt → targetList → 0
      >>> first_col_path[0]
      <ResTarget val=<A_Const isnull=False val=<Integer ival=1>>>
      >>> first_col_path[1] is columns_path[0]
      True

  As said, the node is not always a `ast.Node`, but may be a tuple, possibly containing subtuples, for example the `functions` slot of `RangeFunction` that is a tuple of tuples, each containing a `FuncCall` and possibly other values:

      >>> tree = parse_sql('SELECT * FROM ROWS'
      ...                  ' FROM (generate_series(10,11),'
      ...                  '       get_users())')
      >>> class VerboseVisitor(Visitor):
      ...   all_ancestors = []
      ...   def visit(self, ancestors, node):
      ...     print(f'{len(self.all_ancestors):2d}.',
      ...           "node:", type(node).__name__,
      ...           "ancestor:", type(ancestors.node).__name__)
      ...     self.all_ancestors.append(ancestors)
      >>> VerboseVisitor()(tree)
       0. node: RawStmt ancestor: tuple
       1. node: SelectStmt ancestor: RawStmt
       2. node: ResTarget ancestor: tuple
       3. node: RangeFunction ancestor: tuple
       4. node: ColumnRef ancestor: ResTarget
       5. node: A_Star ancestor: tuple
       6. node: FuncCall ancestor: tuple
       7. node: FuncCall ancestor: tuple
       8. node: String ancestor: tuple
       9. node: A_Const ancestor: tuple
      10. node: A_Const ancestor: tuple
      11. node: String ancestor: tuple
      12. node: Integer ancestor: A_Const
      13. node: Integer ancestor: A_Const
      ...

  To find the closest ancestor that is actually pointing to an AST node you may use the `abs()` function:

      >>> range_function = tree[0].stmt.fromClause[0]
      >>> gen_series_funccall = range_function.functions[0][0]
      >>> gen_series_funccall
      <FuncCall funcname=(<String sval='generate_series'>,) ...>
      >>> generate_series_ancestry = VerboseVisitor.all_ancestors[6]
      >>> generate_series_ancestry@tree is gen_series_funccall
      True
      >>> abs(generate_series_ancestry).node is range_function
      True

  As an aid to visitors that apply changes to the AST, there are two methods, `update()` and `apply()`, that takes care of the different cases, when node is an AST instance or instead it’s a tuple (or subtuple); the former does not directly change the AST tree, but postpones that when the latter is called.

  apply()

    Apply the pending change, if any, to the actual node.

  find_nearest(cls)

    Find the nearest ancestor with a node of the given cls.

  update(new_value)

    Set new_value as a pending change to the tracked node.

class pglast.visitors.Continue

  Marker used to tell the iterator to keep going.

class pglast.visitors.Delete

  Marker used to tell the iterator to delete current node.

class pglast.visitors.ReferencedRelations(cte_names=None, skip_with_clause=None)

  Concrete implementation of the `referenced_relations()` function.

  Parameters:

    - cte_names (set) – the set of surrounding CTE names

    - skip_with_clause (WithClause) – skip this clause, when specified

  Calling an instance of this class will return a set of the names of the relations referenced by the given `node`.

  visit_RangeVar(ancestors, node)

    Collect relation names, taking into account defined CTE names

class pglast.visitors.Skip

  Marker used to tell the iterator to not descend into the current node.

class pglast.visitors.Visitor

  Base class implementing the visitor pattern.

  To use it, you shall write a subclass that implements a set of particular named methods, specifically `visit_XYZ` where `XYZ` is the name of a class name defined in the `pglast.ast` module.

  Instances of this class are callables and accept either a `ast.Node` instance or a sequence of instances, typically the result of `parse_sql()`. The argument will be traversed in a breadth first order and each `Node` instance will be passed to the corresponding `visit_XYZ` method if it is implemented, falling back to the default `visit()` method.

  The `visit_XYZ` methods receive two arguments: the ancestry chain of the node, an instance of `Ancestor` and the `Node` instance itself. The methods may return either `None`, an action or a new node that will replace the original one.

  iterate(node)

    Iterate thru node’s AST using a breadth-first traversing.

    Parameters:

      node – either a `ast.Node` instance or a tuple of those

    This is a generator, that yields `Node` instances together with their ancestors chain as it finds them while traversing the tree.

  visit(ancestors, node)

    The default visit method for any node without a specific one.

    This implementation is a no-op.

pglast.visitors.referenced_relations(stmt)

  Return the set of relation names referenced in the given stmt.

  Parameters:

    stmt – either a string containing the `SQL` statement or a `ast.Node` instance

  Returns:

    a set of strings, the names of the relations

  Example:

      >>> referenced_relations('WITH q1(x,y) AS (SELECT 1,2)'
      ...                      ' SELECT * FROM q1, q2')
      {'q2'}