jueves, 17 de septiembre de 2015

Purely SAP HANA with Haskell

This post was originally posted on Purely SAP HANA with Haskell.


Haskell is a general-purpose purely functional programming language with non-strict semantics and strong static typing.


What does that means? Nothing…just that Haskell is the most pure programming language around…which means that there are not and cannot be side effects…like Haskellers like to say…”If it compiles…it will always work”…

There’s an XKCD cartoon that nicely resumes what Haskell is about -;)


Well…I will run it -:P What I love about Haskell is that it really makes you forget everything you learned before…once assigned, a variable can’t never change its value…recursion is a must…printing on the terminal is considered impure, but there’s of course a work around it…everything is a function…forget about Classes and Objects…pattern matching is your best friend…and so many more cool things -;)

So…no example or demonstration would be complete if we didn’t hook it up with SAP HANA, right? So…let’s go and do it -;)

First, we need to create a Calculation View and call it “FLIGHTS_BY_CARRIER”. It will be composed of two tables, SCARR and SFLIGHT.

First, we need to create a Join object and link the table by MANDT and CARRID. From here select the following fields as output MANDT, CARRID, CARRNAME, PRICE and CURRENCY.

Then create an Aggregation object selecting the fields CARRNAME, PRICE (As Aggregated Column) and CURRENCY. Filter the CURRENCY field by ‘USD’.

Then create a Projection object and select only PRICE and CARRNAME.

On the Semantics object make sure to select “CROSS CLIENT” as the Default Client.


Now, switch to the SAP HANA Development View and create a new repository. Call it “Flights”.

Create a new “XS Engine” project and call it “Flights” as well. Link it to the “Flights” repository.

Create an empty “.xsapp” file.

Create a file called “.xsaccess” with the following code.

.xsaccess
{
          "exposed" : true,
          "authentication" : [ { "method" : "Basic" } ]
}

Finally create a file called “flights.xsodata” with the following code

flights.xsodata
service {
          "Blag/FLIGHTS_BY_CARRIER.calculationview" as "FLIGHTS" keys 
                                                        generate local "Id";
}

Activate your project and launch it on your browser, you should see something like this…


The SAP HANA part is done…so we can move into the Haskell part…

On a terminal session type this…

cabal update
cabal install --j --disable-tests wreq
In later versions of wreq, lens and aeson are already included…but just in case…
cabal install lens
cabal install aeson

To code for Haskell I use one of the most awesome editors I have ever found…Geany. It comes almost pre-configured to handle a lot of programming languages, so you will be ready to code for Haskell.

Basically you only need to press the “Run or view the current file”, last image that shows some engines…which basically will bring up GHCi which is the Glasgow Haskell Compiler Interactive.


With that, we should be more than ready to start coding -:) Copy and paste the following code…

Haskell_HANA.hs
{-# LANGUAGE OverloadedStrings #-}
import Network.Wreq
import Control.Lens
import Data.Aeson
import Data.Aeson.Lens
import Data.Aeson.Types
import Data.Text
import Data.Vector
import Prelude as P
import qualified Data.ByteString.Lazy as B

get_info :: B.ByteString -> Text -> Text -> Text -> Text -> Int -> Int -> String
get_info json d results carrname price len ctr
 | ctr < len = unpack(json ^. key d . key results . nth ctr . key carrname . _String) P.++ 
               ": " P.++ unpack(json ^. key d . key results . nth ctr . key price . _String) P.++ "\n" 
               P.++ get_info json d results carrname price len (ctr+1)
 | ctr >= len = []

main :: IO ()
main = do
 let d = pack "d"
 let results = pack "results"
 let carrname = pack "CARRNAME"
 let price = pack "PRICE"
 let opts = defaults & auth ?~ basicAuth "SYSTEM" "YourPassword"
 r <- getWith opts "http://YourHANAServer:8000/Flights/flights.xsodata/FLIGHTS?$format=json"
 let json = r ^. responseBody
 let results_array = json ^. key d . key results . _Array
 let len = Data.Vector.length results_array
 putStr $ get_info json d results carrname price len 0

Save your file and press the “Run or view the current file” button.


You will need to use the format “:l name_of_your_file” to load it into memory and then you can just call the main function to execute it -;)

I have to say…Haskell is not an easy language…and pulling out this blog wasn’t an easy task either…I need to do a lot of research…but gladly the Wreq and Aeson packages are simply awesome!

Greetings,

Blag.
Development Expert.