class_docstr: Helper class for constructing various join components in a SqlQueryPlan.
docstr: Make a join description to link two base output DataSets by matching entities.
  
  In addition to the entity equality condition, this will ensure datasets are joined on all partition
  columns and account for validity windows, if those are defined in one of the datasets.
docstr_tok: ["Make","a","join","description","to","link","two","base","output","DataSets","by","matching","entities",".","In","addition","to","the","entity","equality","condition",",","this","will","ensure","datasets","are","joined","on","all","partition","columns","and","account","for","validity","windows",",","if","those","are","defined","in","one","of","the","datasets","."]
code: def make_base_output_join_description(
      left_data_set: AnnotatedSqlDataSet,
      right_data_set: AnnotatedSqlDataSet,
      join_description: JoinDescription,
  ) -> SqlJoinDescription:
      """Make a join description to link two base output DataSets by matching entities.
  
      In addition to the entity equality condition, this will ensure datasets are joined on all partition
      columns and account for validity windows, if those are defined in one of the datasets.
      """
      join_on_entity = join_description.join_on_entity
  
      # Figure out which columns in the "left" data set correspond to the entity that we want to join on.
      # The column associations tell us which columns correspond to which instances in the data set.
      left_data_set_entity_column_associations = (
          left_data_set.data_set.column_associations_for_entity(
              join_on_entity
          )
      )
      left_data_set_entity_cols = [
          c.column_name
          for c in left_data_set_entity_column_associations
      ]
  
      # Figure out which columns in the "right" data set correspond to the entity that we want to join on.
      right_data_set_column_associations = (
          right_data_set.data_set.column_associations_for_entity(
              join_on_entity
          )
      )
      right_data_set_entity_cols = [
          c.column_name for c in right_data_set_column_associations
      ]
  
      assert len(left_data_set_entity_cols) == len(
          right_data_set_entity_cols
      ), (
          f"Cannot construct join - the number of columns on the left ({left_data_set_entity_cols}) side of "
          f"the join does not match the right ({right_data_set_entity_cols})"
      )
  
      # We have the columns that we need to "join on" in the query, so add it to the list of join descriptions to
      # use later.
      column_equality_descriptions = []
      for idx in range(len(left_data_set_entity_cols)):
          column_equality_descriptions.append(
              ColumnEqualityDescription(
                  left_column_alias=left_data_set_entity_cols[idx],
                  right_column_alias=right_data_set_entity_cols[idx],
              )
          )
      # Add the partition columns as well.
      for (
          dimension_join_description
      ) in join_description.join_on_partition_dimensions:
          column_equality_descriptions.append(
              ColumnEqualityDescription(
                  left_column_alias=left_data_set.data_set.column_association_for_dimension(
                      dimension_join_description.start_node_dimension_spec
                  ).column_name,
                  right_column_alias=right_data_set.data_set.column_association_for_dimension(
                      dimension_join_description.node_to_join_dimension_spec
                  ).column_name,
              )
          )
  
      for (
          time_dimension_join_description
      ) in join_description.join_on_partition_time_dimensions:
          column_equality_descriptions.append(
              ColumnEqualityDescription(
                  left_column_alias=left_data_set.data_set.column_association_for_time_dimension(
                      time_dimension_join_description.start_node_time_dimension_spec
                  ).column_name,
                  right_column_alias=right_data_set.data_set.column_association_for_time_dimension(
                      time_dimension_join_description.node_to_join_time_dimension_spec
                  ).column_name,
              )
          )
  
      validity_conditions = (
          SqlQueryPlanJoinBuilder._make_validity_window_on_conditions(
              left_data_set=left_data_set,
              right_data_set=right_data_set,
              join_description=join_description,
          )
      )
  
      return SqlQueryPlanJoinBuilder.make_column_equality_sql_join_description(
          right_source_node=right_data_set.data_set.sql_select_node,
          left_source_alias=left_data_set.alias,
          right_source_alias=right_data_set.alias,
          column_equality_descriptions=column_equality_descriptions,
          join_type=join_description.join_type,
          additional_on_conditions=validity_conditions,
      )
  
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 2 for calling the SqlQueryPlanJoinBuilder obj's underlying member method code with example usage: obj.make_base_output_join_description(left_data_set, right_data_set, join_description) and returns: SqlQueryPlanJoinBuilder