class_docstr: A recipe for how to join a node containing linkable instances to the "start_node".
  
  node_to_join contains the linkable instances that are needed - it should be filtered so that the output data set of
  that node only includes the entity instance for the join and the instances associated with
  satisfiable_linkable_specs.
class_docstr_tok: ["A","recipe","for","how","to","join","a","node","containing","linkable","instances","to","the","``","start_node","''",".","node_to_join","contains","the","linkable","instances","that","are","needed","-","it","should","be","filtered","so","that","the","output","data","set","of","that","node","only","includes","the","entity","instance","for","the","join","and","the","instances","associated","with","satisfiable_linkable_specs","."]
docstr: The recipe as a join description to use in the dataflow plan node.
docstr_tok: ["The","recipe","as","a","join","description","to","use","in","the","dataflow","plan","node","."]
code: def join_description(self) -> JoinDescription:
      """The recipe as a join description to use in the dataflow plan node."""
      # Figure out what elements to filter from the joined node.
      include_specs: List[LinkableInstanceSpec] = []
      assert all(
          [
              len(spec.entity_links) > 0
              for spec in self.satisfiable_linkable_specs
          ]
      )
      include_specs.extend(
          [
              LinklessEntitySpec.from_reference(spec.entity_links[0])
              for spec in self.satisfiable_linkable_specs
          ]
      )
  
      include_specs.extend(
          [
              join.node_to_join_dimension_spec
              for join in self.join_on_partition_dimensions
          ]
      )
      include_specs.extend(
          [
              join.node_to_join_time_dimension_spec
              for join in self.join_on_partition_time_dimensions
          ]
      )
      if self.validity_window:
          include_specs.extend(
              [
                  self.validity_window.window_start_dimension,
                  self.validity_window.window_end_dimension,
              ]
          )
  
      # `satisfiable_linkable_specs` describes what can be satisfied after the join, so remove the entity
      # link when filtering before the join.
      # e.g. if the node is used to satisfy "user_id__country", then the node must have the entity
      # "user_id" and the "country" dimension so that it can be joined to the source node.
      include_specs.extend(
          [
              spec.without_first_entity_link
              for spec in self.satisfiable_linkable_specs
          ]
      )
      filtered_node_to_join = FilterElementsNode(
          parent_node=self.node_to_join,
          include_specs=InstanceSpecSet.from_specs(include_specs),
      )
  
      return JoinDescription(
          join_node=filtered_node_to_join,
          join_on_entity=self.join_on_entity,
          join_on_partition_dimensions=self.join_on_partition_dimensions,
          join_on_partition_time_dimensions=self.join_on_partition_time_dimensions,
          validity_window=self.validity_window,
          join_type=self.join_type,
      )
  
imports: from __future__ import annotations
  import itertools
  import logging
  from dataclasses import dataclass
  from typing import List, Optional, Sequence, Tuple
  from dbt_semantic_interfaces.pretty_print import pformat_big_objects
  from metricflow.dataflow.builder.node_data_set import DataflowPlanNodeOutputDataSetResolver
  from metricflow.dataflow.builder.partitions import PartitionJoinResolver
  from metricflow.dataflow.dataflow_plan import BaseOutput, FilterElementsNode, JoinDescription, PartitionDimensionJoinDescription, PartitionTimeDimensionJoinDescription, ValidityWindowJoinDescription
  from metricflow.dataset.sql_dataset import SqlDataSet
  from metricflow.instances import InstanceSet
  from metricflow.model.semantics.semantic_model_join_evaluator import SemanticModelJoinEvaluator
  from metricflow.plan_conversion.instance_converters import CreateValidityWindowJoinDescription
  from metricflow.protocols.semantics import SemanticModelAccessor
  from metricflow.specs.specs import InstanceSpecSet, LinkableInstanceSpec, LinklessEntitySpec
  from metricflow.sql.sql_plan import SqlJoinType
label_desc: Use image node_id 1 for calling the JoinLinkableInstancesRecipe obj's underlying member method code with example usage: obj.join_description() and returns: JoinDescription