class_docstr: Helper class for constructing various join components in a SqlQueryPlan.
docstr: Make a join description where the base condition is a set of equality comparisons between columns.
  
  Typically the columns in column_equality_descriptions are entities we are trying to match,
  although they may include things like dimension partitions or time dimension columns where an
  equality is expected.
  
  Since the framework currently supports join keys OR condition-free cross joins, this helper will require
  either a non-empty set of column equality conditions or a CROSS JOIN.
  
  Args:
      right_source_node: node representing the join target, may be either a table or subquery
      left_source_alias: string alias entity for the join source
      right_source_alias: string alias entity for the join target
      column_equality_descriptions: set of equality constraints for the ON statement
      join_type: type of SQL join, e.g., LEFT, INNER, etc.
      additional_on_conditions: set of additional constraints to add in the ON statement (via AND)
docstr_tok: ["Make","a","join","description","where","the","base","condition","is","a","set","of","equality","comparisons","between","columns",".","Typically","the","columns","in","column_equality_descriptions","are","entities","we","are","trying","to","match",",","although","they","may","include","things","like","dimension","partitions","or","time","dimension","columns","where","an","equality","is","expected",".","Since","the","framework","currently","supports","join","keys","OR","condition-free","cross","joins",",","this","helper","will","require","either","a","non-empty","set","of","column","equality","conditions","or","a","CROSS","JOIN",".","Args",":","right_source_node",":","node","representing","the","join","target",",","may","be","either","a","table","or","subquery","left_source_alias",":","string","alias","entity","for","the","join","source","right_source_alias",":","string","alias","entity","for","the","join","target","column_equality_descriptions",":","set","of","equality","constraints","for","the","ON","statement","join_type",":","type","of","SQL","join",",","e.g.",",","LEFT",",","INNER",",","etc",".","additional_on_conditions",":","set","of","additional","constraints","to","add","in","the","ON","statement","(","via","AND",")"]
code: def make_column_equality_sql_join_description(
      right_source_node: SqlSelectStatementNode,
      left_source_alias: str,
      right_source_alias: str,
      column_equality_descriptions: Sequence[ColumnEqualityDescription],
      join_type: SqlJoinType,
      additional_on_conditions: Sequence[SqlExpressionNode] = tuple(),
  ) -> SqlJoinDescription:
      """Make a join description where the base condition is a set of equality comparisons between columns.
  
      Typically the columns in column_equality_descriptions are entities we are trying to match,
      although they may include things like dimension partitions or time dimension columns where an
      equality is expected.
  
      Since the framework currently supports join keys OR condition-free cross joins, this helper will require
      either a non-empty set of column equality conditions or a CROSS JOIN.
  
      Args:
          right_source_node: node representing the join target, may be either a table or subquery
          left_source_alias: string alias entity for the join source
          right_source_alias: string alias entity for the join target
          column_equality_descriptions: set of equality constraints for the ON statement
          join_type: type of SQL join, e.g., LEFT, INNER, etc.
          additional_on_conditions: set of additional constraints to add in the ON statement (via AND)
      """
      assert (
          len(column_equality_descriptions) > 0
          or join_type is SqlJoinType.CROSS_JOIN
      ), f"No column equality conditions specified for join with type {join_type} - this may render invalid SQL!"
  
      and_conditions: List[SqlExpressionNode] = []
      for column_equality_description in column_equality_descriptions:
          left_column = SqlColumnReferenceExpression(
              SqlColumnReference(
                  table_alias=left_source_alias,
                  column_name=column_equality_description.left_column_alias,
              )
          )
          right_column = SqlColumnReferenceExpression(
              SqlColumnReference(
                  table_alias=right_source_alias,
                  column_name=column_equality_description.right_column_alias,
              )
          )
          column_equality_expression = SqlComparisonExpression(
              left_expr=left_column,
              comparison=SqlComparison.EQUALS,
              right_expr=right_column,
          )
          if column_equality_description.treat_nulls_as_equal:
              null_comparison_expression = SqlLogicalExpression(
                  operator=SqlLogicalOperator.AND,
                  args=(
                      SqlIsNullExpression(arg=left_column),
                      SqlIsNullExpression(arg=right_column),
                  ),
              )
              and_conditions.append(
                  SqlLogicalExpression(
                      operator=SqlLogicalOperator.OR,
                      args=(
                          column_equality_expression,
                          null_comparison_expression,
                      ),
                  )
              )
          else:
              and_conditions.append(column_equality_expression)
  
      and_conditions += additional_on_conditions
  
      on_condition: Optional[SqlExpressionNode]
      if len(and_conditions) == 0:
          on_condition = None
      elif len(and_conditions) == 1:
          on_condition = and_conditions[0]
      else:
          on_condition = SqlLogicalExpression(
              operator=SqlLogicalOperator.AND,
              args=tuple(and_conditions),
          )
  
      return SqlJoinDescription(
          right_source=right_source_node,
          right_source_alias=right_source_alias,
          on_condition=on_condition,
          join_type=join_type,
      )
  
imports: from __future__ import annotations
  from dataclasses import dataclass
  from typing import List, Optional, Sequence, Tuple
  from dbt_semantic_interfaces.protocols.metric import MetricTimeWindow
  from dbt_semantic_interfaces.type_enums.time_granularity import TimeGranularity
  from metricflow.assert_one_arg import assert_exactly_one_arg_set
  from metricflow.dataflow.dataflow_plan import JoinConversionEventsNode, JoinDescription, JoinOverTimeRangeNode, JoinToTimeSpineNode
  from metricflow.dataset.sql_dataset import SqlDataSet
  from metricflow.plan_conversion.sql_expression_builders import make_coalesced_expr
  from metricflow.sql.sql_exprs import SqlColumnReference, SqlColumnReferenceExpression, SqlComparison, SqlComparisonExpression, SqlDateTruncExpression, SqlIsNullExpression, SqlLogicalExpression, SqlLogicalOperator, SqlSubtractTimeIntervalExpression
  from metricflow.sql.sql_plan import SqlExpressionNode, SqlJoinDescription, SqlJoinType, SqlSelectStatementNode
label_desc: Use image node_id 1 for calling the SqlQueryPlanJoinBuilder obj's underlying member method code with example usage: obj.make_column_equality_sql_join_description(right_source_node, left_source_alias, right_source_alias, column_equality_descriptions, join_type, additional_on_conditions) and returns: SqlJoinDescription