-- | Implements a Full Outer Join operation between two RTables (any type of join predicate is allowed)
-- A full outer join is the union of the left and right outer joins respectively.
-- The common columns will appear from both tables but only the left table column's will retain their original name (just by convention).
runFullOuterJoin ::
    RJoinPredicate
    -> RTable
    -> RTable
    -> RTable
runFullOuterJoin jpred leftRTab rightRTab = -- (lJ jpred leftRTab rightRTab) `u` (rJ jpred leftRTab rightRTab) -- (note that `u` eliminates dublicates)
    let
        --
        -- we want to get to this union:
        -- (lJ jpred leftRTab rightRTab) `u` (d (rJ jpred leftRTab rightRTab) (ij (flip jpred) rightRTab leftRTab))
        -- 
        -- The problem is with the change of column names that are common in both tables. In the right part of the union
        -- rightTab has preserved its original column names while in the left part the have changed to "_1" suffix. 
        -- So we cant do the union as is, we need to change the second part of the union (right one) to have the same column names
        -- as the firts part, i.e., original names for leftTab and changed names for rightTab.
        --
        unionFstPart = lJ jpred leftRTab rightRTab -- in unionFstPart rightTab's columns have changed names
        
        -- we need to construct the 2nd part of the union with leftTab columns unchanged and rightTab changed        
        unionSndPartTemp1 = d (rJ jpred leftRTab rightRTab) (iJ (flip jpred) rightRTab leftRTab)        
        -- isolate the columns of the rightTab
        unionSndPartTemp2 = p (getColumnNamesfromRTab rightRTab) unionSndPartTemp1
        -- this join is a trick in order to change names of the rightTab
        unionSndPart = iJ (\t1 t2 -> True) (createSingletonRTable $ createNullRTuple $ (getColumnNamesfromRTab leftRTab)) unionSndPartTemp2
    in unionFstPart `u` unionSndPart
runFullOuterJoin ::
    RJoinPredicate
    -> RTable
    -> RTable
    -> RTable
runFullOuterJoin jpred leftRTab rightRTab = -- (lJ jpred leftRTab rightRTab) `u` (rJ jpred leftRTab rightRTab) -- (note that `u` eliminates dublicates)
    let
        --
        -- we want to get to this union:
        -- (lJ jpred leftRTab rightRTab) `u` (d (rJ jpred leftRTab rightRTab) (ij (flip jpred) rightRTab leftRTab))
        -- 
        -- The problem is with the change of column names that are common in both tables. In the right part of the union
        -- rightTab has preserved its original column names while in the left part the have changed to "_1" suffix. 
        -- So we cant do the union as is, we need to change the second part of the union (right one) to have the same column names
        -- as the firts part, i.e., original names for leftTab and changed names for rightTab.
        --
        unionFstPart = lJ jpred leftRTab rightRTab -- in unionFstPart rightTab's columns have changed names
        
        -- we need to construct the 2nd part of the union with leftTab columns unchanged and rightTab changed        
        unionSndPartTemp1 = d (rJ jpred leftRTab rightRTab) (iJ (flip jpred) rightRTab leftRTab)        
        -- isolate the columns of the rightTab
        unionSndPartTemp2 = p (getColumnNamesfromRTab rightRTab) unionSndPartTemp1
        -- this join is a trick in order to change names of the rightTab
        unionSndPart = iJ (\t1 t2 -> True) (createSingletonRTable $ createNullRTuple $ (getColumnNamesfromRTab leftRTab)) unionSndPartTemp2
    in unionFstPart `u` unionSndPart
runFullOuterJoin jpred leftRTab rightRTab = -- (lJ jpred leftRTab rightRTab) `u` (rJ jpred leftRTab rightRTab) -- (note that `u` eliminates dublicates)
    let
        --
        -- we want to get to this union:
        -- (lJ jpred leftRTab rightRTab) `u` (d (rJ jpred leftRTab rightRTab) (ij (flip jpred) rightRTab leftRTab))
        -- 
        -- The problem is with the change of column names that are common in both tables. In the right part of the union
        -- rightTab has preserved its original column names while in the left part the have changed to "_1" suffix. 
        -- So we cant do the union as is, we need to change the second part of the union (right one) to have the same column names
        -- as the firts part, i.e., original names for leftTab and changed names for rightTab.
        --
        unionFstPart = lJ jpred leftRTab rightRTab -- in unionFstPart rightTab's columns have changed names
        
        -- we need to construct the 2nd part of the union with leftTab columns unchanged and rightTab changed        
        unionSndPartTemp1 = d (rJ jpred leftRTab rightRTab) (iJ (flip jpred) rightRTab leftRTab)        
        -- isolate the columns of the rightTab
        unionSndPartTemp2 = p (getColumnNamesfromRTab rightRTab) unionSndPartTemp1
        -- this join is a trick in order to change names of the rightTab
        unionSndPart = iJ (\t1 t2 -> True) (createSingletonRTable $ createNullRTuple $ (getColumnNamesfromRTab leftRTab)) unionSndPartTemp2
    in unionFstPart `u` unionSndPart