-- Test it with this, from ghci:
-- ---------------------------------
-- :set -XOverloadedStrings
-- :m + Data.HashMap.Strict
--
-- let t1 = fromList [("c1",RInt 1),("c2", Null)]
-- let t2 = fromList [("c1",RInt 2),("c2", Null)]
-- let t3 = fromList [("c1",RInt 3),("c2", Null)]
-- let t4 = fromList [("c1",RInt 4),("c2", Null)]
-- :m + Data.Vector
-- let tab1 = Data.Vector.fromList [t1,t2,t3,t4]
-- let tab2 = Data.Vector.fromList [t1,t2]

-- > d tab1 tab2
-- ---------------------------------

-- | Implements the set Difference of two RTables as the diff of two lists (see 'Data.List').
runDiff :: 
    RTable
    -> RTable
    -> RTable
runDiff rt1 rt2 =
    if isRTabEmpty rt1
        then
            emptyRTable
        else 
            if isRTabEmpty rt2
                then
                    rt1
                else  
                    -- construct the diff result by traversing the left table and checking if each tuple exists in the right table
                    V.foldr (diff) emptyRTable rt1
                    where
                        diff :: RTuple -> RTable -> RTable
                        diff tupLeft acc = 
                            -- Can we find tupLeft in the right table?            
                            if didYouFindIt tupLeft rt2 
                                then acc  -- then discard tuplLeft ,leave result unchanged
                                else V.snoc acc tupLeft  -- else insert tupLeft into final result

-- Important Note:
-- we need to implement are own equality comparison function "areTheyEqual" and not rely on the instance of Eq defined for RDataType above
-- because of "Null Logic". If we compare two RTuples that have Null values in any column, then these can never be equal, because
-- Null == Null returns False.
-- However, in SQL when you run a minus or interesection between two tables containing Nulls, it works! For example:
-- with q1
-- as (
--     select rownum c1, Null c2
--     from dual
--     connect by level < 5
-- ),
-- q2
-- as (
--     select rownum c1, Null c2
--     from dual
--     connect by level < 3
-- )
-- select *
-- from q1
-- minus
-- select *
-- from q2
-- 
-- q1:
-- C1  | C2 
-- ---   ---
-- 1   |                                      
-- 2   |                                     
-- 3   |                                      
-- 4   |                                     
--
-- q2:
-- C1  | C2 
-- ---   ---
-- 1   |                                      
-- 2   |                                     
--
-- And it will return:                
-- C1  | C2 
-- ---   ---
-- 3   |                                      
-- 4   |                                     
-- So for Minus and Intersection, when we compare RTuples we need to "bypass" the Null Logic
runDiff :: 
    RTable
    -> RTable
    -> RTable
runDiff rt1 rt2 =
    if isRTabEmpty rt1
        then
            emptyRTable
        else 
            if isRTabEmpty rt2
                then
                    rt1
                else  
                    -- construct the diff result by traversing the left table and checking if each tuple exists in the right table
                    V.foldr (diff) emptyRTable rt1
                    where
                        diff :: RTuple -> RTable -> RTable
                        diff tupLeft acc = 
                            -- Can we find tupLeft in the right table?            
                            if didYouFindIt tupLeft rt2 
                                then acc  -- then discard tuplLeft ,leave result unchanged
                                else V.snoc acc tupLeft  -- else insert tupLeft into final result

-- Important Note:
-- we need to implement are own equality comparison function "areTheyEqual" and not rely on the instance of Eq defined for RDataType above
-- because of "Null Logic". If we compare two RTuples that have Null values in any column, then these can never be equal, because
-- Null == Null returns False.
-- However, in SQL when you run a minus or interesection between two tables containing Nulls, it works! For example:
-- with q1
-- as (
--     select rownum c1, Null c2
--     from dual
--     connect by level < 5
-- ),
-- q2
-- as (
--     select rownum c1, Null c2
--     from dual
--     connect by level < 3
-- )
-- select *
-- from q1
-- minus
-- select *
-- from q2
-- 
-- q1:
-- C1  | C2 
-- ---   ---
-- 1   |                                      
-- 2   |                                     
-- 3   |                                      
-- 4   |                                     
--
-- q2:
-- C1  | C2 
-- ---   ---
-- 1   |                                      
-- 2   |                                     
--
-- And it will return:                
-- C1  | C2 
-- ---   ---
-- 3   |                                      
-- 4   |                                     
-- So for Minus and Intersection, when we compare RTuples we need to "bypass" the Null Logic
runDiff rt1 rt2 =
    if isRTabEmpty rt1
        then
            emptyRTable
        else 
            if isRTabEmpty rt2
                then
                    rt1
                else  
                    -- construct the diff result by traversing the left table and checking if each tuple exists in the right table
                    V.foldr (diff) emptyRTable rt1
                    where
                        diff :: RTuple -> RTable -> RTable
                        diff tupLeft acc = 
                            -- Can we find tupLeft in the right table?            
                            if didYouFindIt tupLeft rt2 
                                then acc  -- then discard tuplLeft ,leave result unchanged
                                else V.snoc acc tupLeft  -- else insert tupLeft into final result

-- Important Note:
-- we need to implement are own equality comparison function "areTheyEqual" and not rely on the instance of Eq defined for RDataType above
-- because of "Null Logic". If we compare two RTuples that have Null values in any column, then these can never be equal, because
-- Null == Null returns False.
-- However, in SQL when you run a minus or interesection between two tables containing Nulls, it works! For example:
-- with q1
-- as (
--     select rownum c1, Null c2
--     from dual
--     connect by level < 5
-- ),
-- q2
-- as (
--     select rownum c1, Null c2
--     from dual
--     connect by level < 3
-- )
-- select *
-- from q1
-- minus
-- select *
-- from q2
-- 
-- q1:
-- C1  | C2 
-- ---   ---
-- 1   |                                      
-- 2   |                                     
-- 3   |                                      
-- 4   |                                     
--
-- q2:
-- C1  | C2 
-- ---   ---
-- 1   |                                      
-- 2   |                                     
--
-- And it will return:                
-- C1  | C2 
-- ---   ---
-- 3   |                                      
-- 4   |                                     
-- So for Minus and Intersection, when we compare RTuples we need to "bypass" the Null Logic