module Grakn.Property ( Property(..) , RolePlayer , Var , Name , VarOrName , Value(..) , var , name , (.:) , rp ) where import Control.Applicative (empty) import Data.Aeson (FromJSON, FromJSONKey, FromJSONKeyFunction (FromJSONKeyText), parseJSON) import qualified Data.Aeson as Aeson import Data.Scientific (Scientific) import Data.Text (Text, unpack) import Grakn.Util (Convert (convert), commas, with) import Text.Regex.Posix ((=~)) -- |A property of a concept data Property = Isa VarOrName | NameProperty Name | Rel [RolePlayer] | Has Name (Either Value Var) -- |A variable name wildcard that will represent a concept in the results newtype Var = Var Text deriving (Eq, Ord) -- |A name of something in the graph newtype Name = Name Text deriving (Eq) -- |Something that may be a variable name or a type name data VarOrName = VarName Var | TypeName Name -- |A value of a resource data Value = ValueString Text | ValueNumber Scientific | ValueBool Bool deriving (Eq) -- |A casting, relating a role type and role player data RolePlayer = RolePlayer (Maybe VarOrName) Var -- |Create a variable var :: Text -> Var var = Var -- |Create a name of something in the graph name :: Text -> Name name = Name -- |A casting in a relation between a role type and a role player (.:) :: Convert a VarOrName => a -> Var -> RolePlayer rt .: player = RolePlayer (Just $ convert rt) player -- |A casting in a relation without a role type rp :: Var -> RolePlayer rp = RolePlayer Nothing nameRegex :: String nameRegex = "^[a-zA-Z_][a-zA-Z0-9_-]*$" instance Show Property where show (Isa varOrName) = "isa " ++ show varOrName show (NameProperty n) = "type-name " ++ show n show (Rel castings) = "(" ++ commas castings ++ ")" show (Has rt value) = "has " ++ show rt ++ " " ++ showEither value instance Show RolePlayer where show (RolePlayer roletype player) = roletype `with` ": " ++ show player instance Show Value where show (ValueString text) = show text show (ValueNumber num) = show num show (ValueBool bool) = show bool instance Show Name where show (Name text) | str =~ nameRegex = str | otherwise = show text where str = unpack text instance Show Var where show (Var v) = '$' : unpack v instance Show VarOrName where show (VarName v) = show v show (TypeName t) = show t instance Convert Var VarOrName where convert = VarName instance Convert Name VarOrName where convert = TypeName instance Convert Var RolePlayer where convert = rp instance Convert Var (Either Value Var) where convert = Right instance Convert Text (Either Value Var) where convert = Left . ValueString instance Convert Scientific (Either Value Var) where convert = Left . ValueNumber instance Convert Bool (Either Value Var) where convert = Left . ValueBool instance FromJSON Value where parseJSON (Aeson.String s) = return $ ValueString s parseJSON (Aeson.Number n) = return $ ValueNumber n parseJSON (Aeson.Bool b) = return $ ValueBool b parseJSON _ = empty instance FromJSON Name where parseJSON (Aeson.String s) = return $ name s parseJSON _ = empty instance FromJSON Var where parseJSON (Aeson.String s) = return $ var s parseJSON _ = empty instance FromJSONKey Var where fromJSONKey = FromJSONKeyText var showEither :: (Show a, Show b) => Either a b -> String showEither = either show show