{-# LANGUAGE OverloadedStrings, TemplateHaskell, DeriveDataTypeable, ScopedTypeVariables, FlexibleInstances, MultiParamTypeClasses #-}moduleDatabase.Cypher(Cypher,entity_data,entity_id,Entity,CypherResult(..),LuceneQuery,runCypher,forkCypher,cypher,cypherGetNode,cypherCreate,cypherGet,cypherSet,luceneEncode,withCypherManager,CypherException(..),DBInfo(..),Hostname,Port,CypherVal(..),CypherVals(..),CypherCol(..),CypherCols(..),CypherMaybe(..),CypherUnit(..))whereimportDatabase.Cypher.LuceneimportData.AesonimportData.Aeson.THimportData.Aeson.TypesimportNetwork.HTTP.ConduitimportNetwork.HTTP.TypesimportData.ConduitimportData.TypeableimportData.Text(Text)importControl.Exceptionhiding(try,throwIO)importControl.Concurrent.MVarimportControl.ApplicativeimportControl.MonadimportData.MonoidimportControl.Monad.IO.ClassimportqualifiedData.ByteStringasSimportqualifiedData.ByteString.LazyasLimportData.Text.Lazy.Encoding(encodeUtf8)importqualifiedData.HashMap.StrictasHimportData.Text.Lazy.BuilderimportData.Aeson.EncodeimportData.List(elemIndices)importControl.Monad.Trans.ResourceimportControl.Monad.BaseimportControl.Monad.Parallel(Parallel(..),Fork(..),parallelIO)-- | Information about your neo4j configuration needed to make requests over the REST api.dataDBInfo=DBInfo{cypher_hostname::Hostname,cypher_port::Port}deriving(Show,Eq)typeHostname=S.ByteStringtypePort=Int$(deriveJSON(drop7)''DBInfo)-- | All interaction with Neo4j is done through the Cypher monad. Use 'cypher' to add a query to the monad.newtypeCyphera=Cypher{uncypher::((DBInfo,Manager)->ResourceTIOa)}-- | Raw result data returned by Neo4j. Only use this if you care about column headers.dataCypherResulta=CypherResult{rescolumns::[Text],resdata::a}deriving(Show,Eq)-- | A single result returned by Neo4j.newtypeCypherVala=CypherValaderiving(Eq,Show)-- | A single column returned by Neo4j.newtypeCypherCola=CypherColaderiving(Eq,Show)-- | Columns returned by Neo4j.newtypeCypherColsa=CypherColsaderiving(Eq,Show)-- | Values returned by Neo4j.newtypeCypherValsa=CypherVals[a]deriving(Eq,Show)-- | Possibly a value returned by Neo4jdataCypherMaybea=CypherJusta|CypherNothingderiving(Eq,Show)-- | No value returned from Neo4jdataCypherUnit=CypherUnitderiving(Show)dataCypherRequest=CypherRequest{req_query::Text,req_params::Value}deriving(Show,Eq)-- | A neo4j node or edgedataEntitya=Entity{entity_id::String,-- ^ The Neo4j node or relationship identity_properties::String,entity_data::a-- ^ The Haskell datatype stored in the Neo4j node or relationship}deriving(Show)instanceEq(Entitya)wherea==b=entity_ida==entity_idbinstanceOrd(Entitya)wherecompareab=compare(entity_ida)(entity_idb)instanceFromJSONa=>FromJSON(Entitya)whereparseJSON(Objectv)=Entity<$>v.:"self"<*>v.:"properties"<*>v.:"data"parseJSON_=memptyinstanceToJSON(Entitya)wheretoJSONa=toJSON(readx::Int)where(_,_:x)=splitAt(last(elemIndices'/'(entity_ida)))(entity_ida)$(deriveJSON(drop3)''CypherResult)$(deriveJSON(drop4)''CypherRequest)-- | An error in handling a Cypher query, either in communicating with the server or parsing the resultdataCypherException=CypherServerExceptionStatusResponseHeadersL.ByteString|CypherClientParseExceptionS.ByteStringderiving(Show,Typeable)instanceExceptionCypherExceptionthrowClientParsebs=throw$CypherClientParseException$S.concat$L.toChunksbsinstanceMonadCypherwherereturna=Cypher(const(returna))(Cyphercmd)>>=f=Cypher$\con->doa<-cmdconuncypher(fa)coninstanceMonadIOCypherwhereliftIOf=Cypher$const(liftIOf)instanceFromJSONa=>FromJSON(CypherVala)whereparseJSONx=do(CypherResult_[[d]])<-parseJSONxreturn$CypherValdinstanceFromJSONa=>FromJSON(CypherCola)whereparseJSONx=do(CypherResult_[d])<-parseJSONxreturn$CypherColdinstanceFromJSONa=>FromJSON(CypherColsa)whereparseJSONx=do(CypherResult_d)<-parseJSONxreturn$CypherColsdinstanceFromJSONa=>FromJSON(CypherValsa)whereparseJSONx=do(CypherResult_d)<-parseJSONxliftMCypherVals(mapMsafeHeadd)instanceFromJSONa=>FromJSON(CypherMaybea)whereparseJSONx=do(CypherResult_ds)<-parseJSONxcasedsof[[d]]->return$CypherJustd_->returnCypherNothinginstanceFromJSONCypherUnitwhereparseJSON_=returnCypherUnitsafeHead::[a]->ParserasafeHead[a]=returnasafeHead_=mzero-- | Perform a cypher querycypher::FromJSONa=>Text->Value->Cypheracyphertxtparams=Cypher$\(DBInfohp,m)->doletreq=def{host=h,port=p,path="db/data/cypher",requestBody=RequestBodyLBS(encode$CypherRequesttxtparams),requestHeaders=headerAccept"application/json":headerContentType"application/json":requestHeadersdef,method="POST",checkStatus=(\__->Nothing)}r<-httpLbsreqmletsci=statusCode(responseStatusr)if200<=sci&&sci<300then(casedecode(responseBodyr)ofNothing->throwClientParse(responseBodyr)Justx->returnx)elsethrow$CypherServerException(responseStatusr)(responseHeadersr)(responseBodyr)-- | Create a cypher nodecypherCreate::(ToJSONa,FromJSONb)=>a->CypherbcypherCreateobj=Cypher$\(DBInfohp,m)->doletreq=def{host=h,port=p,path="db/data/node",requestBody=RequestBodyLBS(encodeobj),requestHeaders=headerAccept"application/json":headerContentType"application/json":requestHeadersdef,method="POST",checkStatus=(\__->Nothing)}r<-httpLbsreqmletsci=statusCode(responseStatusr)if200<=sci&&sci<300then(casedecode(responseBodyr)ofNothing->throwClientParse(responseBodyr)Justx->returnx)elsethrow$CypherServerException(responseStatusr)(responseHeadersr)(responseBodyr)-- | Get a cypher nodecypherGetNode::FromJSONb=>Entityb->Cypher(Entityb)cypherGetNodee=Cypher$\(DBInfohp,m)->doreq<-liftIO$parseUrl(entity_ide)letreq'=req{host=h,port=p,requestHeaders=headerAccept"application/json":headerContentType"application/json":requestHeadersdef,method="GET",checkStatus=(\__->Nothing)}r<-httpLbsreqmletsci=statusCode(responseStatusr)if200<=sci&&sci<300then(casedecode(responseBodyr)ofNothing->throwClientParse(responseBodyr)Justx->returnx)elsethrow$CypherServerException(responseStatusr)(responseHeadersr)(responseBodyr)-- | Set cypher properties. This currently cannot be done through cypher queries.cypherSet::(ToJSONa,ToJSONa1)=>(Entitya)->a1->Cypher()cypherSeteobj=Cypher$\(DBInfohp,m)->doletObjecto1=toJSON(entity_datae)letObjecto2=toJSONobjletbody=RequestBodyLBS$encodeUtf8$toLazyText$fromValue$Object(o2`H.union`o1)req<-liftIO$parseUrl(entity_propertiese)letreq'=req{host=h,port=p,requestBody=body,requestHeaders=headerAccept"application/json":headerContentType"application/json":requestHeadersdef,method="PUT",checkStatus=(\__->Nothing)}r<-httpLbsreq'mletsci=statusCode(responseStatusr)if200<=sci&&sci<300thenreturn()else(lete=CypherServerException(responseStatusr)(responseHeadersr)(responseBodyr)inthrowe)-- | Get the nodes matching the given lucene querycypherGet::(ToJSONa1,FromJSONa)=>a1->CypheracypherGetlc=cypher"start a = node:node_auto_index({lc}) return a"$object["lc".=lc]-- | Get the http connection manager for a Cypher monadwithCypherManager::(Manager->ResourceTIOa)->CypherawithCypherManagerf=Cypher(\(_,m)->fm)-- | Execute some number of cypher queriesrunCypher::Cyphera->DBInfo->Manager->IOarunCyphercdbim=runResourceT$douncypherc(dbi,m)-- | Execute a request in a separate threadforkCypher::Cypher()->Cypher()forkCypher(Cyphercmd)=Cypher(\d->resourceForkIO(cmdd)>>return())instanceForkCypherwhereforkExec(Cypherc)=Cypher$\d->doc'<-forkExec(cd)return$Cypher(constc')instanceParallelCypherwherebindM2=parallelIOinstanceMonadBase(ResourceTIO)CypherwhereliftBase=Cypher.constinstanceFunctorCypherwherefmapg(Cypherf)=Cypher$\d->doarg<-fdreturn$garginstanceApplicativeCypherwherepure=Cypher.const.returnCypherf<*>Cypherx=Cypher$\d->dofunc<-fdarg<-xdreturn$funcarg