{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE IncoherentInstances #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} -- TODO(kps): this module stretches my understanding of Haskell. -- There is probably better than that. {-| Defines the notion of renaming something. This is closed over a few well-defined types. -} module Spark.Core.Internal.CanRename where import qualified Data.Text as T import Formatting import Spark.Core.Try import Spark.Core.StructuresInternal import Spark.Core.Internal.ColumnFunctions() import Spark.Core.Internal.ColumnStructures import Spark.Core.Internal.DatasetStructures import Spark.Core.Internal.Utilities -- | The class of types that can be renamed. -- It is made generic because it covers 2 notions: -- - the name of a compute node that will eventually determine its compute path -- - the name of field (which may become an object path) -- This syntax tries to be convenient and will fail immediately -- for basic errors such as illegal characters. -- -- This could be revisited in the future, but it is a compromise -- on readability. class CanRename a txt where (@@) :: a -> txt -> a infixl 1 @@ instance forall ref a. CanRename (ColumnData ref a) FieldName where c @@ fn = c { _cReferingPath = Just fn } instance forall ref a s. (s ~ String) => CanRename (Column ref a) s where c @@ str = case fieldName (T.pack str) of Right fp -> c @@ fp Left msg -> -- The syntax check here is pretty lenient, so it fails, it has -- some good reasons. We stop here. failure $ sformat ("Could not make a field path out of string "%shown%" for column "%shown%":"%shown) str c msg instance CanRename DynColumn FieldName where (Right cd) @@ fn = Right (cd @@ fn) -- TODO better error handling x @@ _ = x instance forall s. (s ~ String) => CanRename DynColumn s where -- An error could happen when making a path out of a string. (Right cd) @@ str = case fieldName (T.pack str) of Right fp -> Right $ cd @@ fp Left msg -> -- The syntax check here is pretty lenient, so it fails, it has -- some good reasons. We stop here. tryError $ sformat ("Could not make a field path out of string "%shown%" for column "%shown%":"%shown) str cd msg -- TODO better error handling x @@ _ = x instance forall loc a s. (s ~ String) => CanRename (ComputeNode loc a) s where -- There is no need to update the id, as this field is not involved -- in the calculation of the id. -- TODO: make this fail immediately? If the name is wrong, it is -- harder to figure out what is happening. (@@) cn name = cn { _cnName = Just nn } where nn = NodeName . T.pack $ name instance forall loc a s. (s ~ String) => CanRename (Try (ComputeNode loc a)) s where (Right n) @@ str = Right (n @@ str) (Left n) @@ _ = Left n