src/query-ast-to-sql-ast/index.js
function handleUnionSelections(
  sqlASTNode,
  children,
  selections,
  gqlType,
  namespace,
  depth,
  options,
  context,
  internalOptions = {}
) {
  for (let selection of selections) {
    // we need to figure out what kind of selection this is
    switch (selection.kind) {
    case 'Field':
      // has this field been requested once already? GraphQL does not protect against duplicates so we have to check for it
      const existingNode = children.find(child => child.fieldName === selection.name.value && child.type === 'table')
      let newNode = new SQLASTNode(sqlASTNode)
      if (existingNode) {
        newNode = existingNode
      } else {
        children.push(newNode)
      }
      if (internalOptions.defferedFrom) {
        newNode.defferedFrom = internalOptions.defferedFrom
      }
      populateASTNode.call(this, selection, gqlType, newNode, namespace, depth + 1, options, context)
      break
    // if its an inline fragment, it has some fields and we gotta recurse thru all them
    case 'InlineFragment':
      {
        const selectionNameOfType = selection.typeCondition.name.value
        // normally, we would scan for the extra join-monster data on the current gqlType.
        // but the gqlType is the Union. The data isn't there, its on each of the types that make up the union
        // lets find that type and handle the selections based on THAT type instead
        const deferredType = this.schema._typeMap[selectionNameOfType]
        const deferToObjectType = deferredType.constructor.name === 'GraphQLObjectType'
        const handler = deferToObjectType ? handleSelections : handleUnionSelections
        if (deferToObjectType) {
          const typedChildren = sqlASTNode.typedChildren
          children = typedChildren[deferredType.name] = typedChildren[deferredType.name] || []
          internalOptions.defferedFrom = gqlType
        }
        handler.call(
          this, sqlASTNode, children,
          selection.selectionSet.selections, deferredType, namespace,
          depth, options, context,
          internalOptions
        )
      }
      break
    // if its a named fragment, we need to grab the fragment definition by its name and recurse over those fields
    case 'FragmentSpread':
      {
        const fragmentName = selection.name.value
        const fragment = this.fragments[fragmentName]
        const fragmentNameOfType = fragment.typeCondition.name.value
        const deferredType = this.schema._typeMap[fragmentNameOfType]
        const deferToObjectType = deferredType.constructor.name === 'GraphQLObjectType'
        const handler = deferToObjectType ? handleSelections : handleUnionSelections
        if (deferToObjectType) {
          const typedChildren = sqlASTNode.typedChildren
          children = typedChildren[deferredType.name] = typedChildren[deferredType.name] || []
          internalOptions.defferedFrom = gqlType
        }
        handler.call(
          this, sqlASTNode, children,
          fragment.selectionSet.selections, deferredType, namespace,
          depth, options, context,
          internalOptions
        )
      }
      break
    /* istanbul ignore next */
    default:
      throw new Error('Unknown selection kind: ' + selection.kind)
    }
  }
}
function handleUnionSelections(
  sqlASTNode,
  children,
  selections,
  gqlType,
  namespace,
  depth,
  options,
  context,
  internalOptions = {}
) {
  for (let selection of selections) {
    // we need to figure out what kind of selection this is
    switch (selection.kind) {
    case 'Field':
      // has this field been requested once already? GraphQL does not protect against duplicates so we have to check for it
      const existingNode = children.find(child => child.fieldName === selection.name.value && child.type === 'table')
      let newNode = new SQLASTNode(sqlASTNode)
      if (existingNode) {
        newNode = existingNode
      } else {
        children.push(newNode)
      }
      if (internalOptions.defferedFrom) {
        newNode.defferedFrom = internalOptions.defferedFrom
      }
      populateASTNode.call(this, selection, gqlType, newNode, namespace, depth + 1, options, context)
      break
    // if its an inline fragment, it has some fields and we gotta recurse thru all them
    case 'InlineFragment':
      {
        const selectionNameOfType = selection.typeCondition.name.value
        // normally, we would scan for the extra join-monster data on the current gqlType.
        // but the gqlType is the Union. The data isn't there, its on each of the types that make up the union
        // lets find that type and handle the selections based on THAT type instead
        const deferredType = this.schema._typeMap[selectionNameOfType]
        const deferToObjectType = deferredType.constructor.name === 'GraphQLObjectType'
        const handler = deferToObjectType ? handleSelections : handleUnionSelections
        if (deferToObjectType) {
          const typedChildren = sqlASTNode.typedChildren
          children = typedChildren[deferredType.name] = typedChildren[deferredType.name] || []
          internalOptions.defferedFrom = gqlType
        }
        handler.call(
          this, sqlASTNode, children,
          selection.selectionSet.selections, deferredType, namespace,
          depth, options, context,
          internalOptions
        )
      }
      break
    // if its a named fragment, we need to grab the fragment definition by its name and recurse over those fields
    case 'FragmentSpread':
      {
        const fragmentName = selection.name.value
        const fragment = this.fragments[fragmentName]
        const fragmentNameOfType = fragment.typeCondition.name.value
        const deferredType = this.schema._typeMap[fragmentNameOfType]
        const deferToObjectType = deferredType.constructor.name === 'GraphQLObjectType'
        const handler = deferToObjectType ? handleSelections : handleUnionSelections
        if (deferToObjectType) {
          const typedChildren = sqlASTNode.typedChildren
          children = typedChildren[deferredType.name] = typedChildren[deferredType.name] || []
          internalOptions.defferedFrom = gqlType
        }
        handler.call(
          this, sqlASTNode, children,
          fragment.selectionSet.selections, deferredType, namespace,
          depth, options, context,
          internalOptions
        )
      }
      break
    /* istanbul ignore next */
    default:
      throw new Error('Unknown selection kind: ' + selection.kind)
    }
  }
}
we need to collect all fields from all the fragments requested in the union type and ask for them in SQL