martes, 29 de septiembre de 2015

SAP HANA on the OCaml hump

This post was originally posted on SAP HANA on the OCaml hump.


OCaml is an industrial strength programming language supporting functional, imperative and object-oriented styles.



Sounds nice, right? OCaml is the next step of the Caml programming language.

Having learning other functional programming languages like Haskell and Erlang, OCaml was the next obvious choice for me…so I decided to start learning it…not an easy task for sure…but really fun and enlighten.

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.xodata
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 OCaml part…

For first timers, OPAM (the package manager for OCaml can be tricky and sometimes frustrating), so let’s make your lives easier by following this single easy steps…on a terminal session type this…

opam init
eval `opam config env`
opam switch 4.01.0
eval `opam config env`
opam install core utop core_extended async uri yojson cohttp lwt ezjsonm

It will take a while but by installing all the required packages in a single command, prevents errors from happening.

To code for OCaml 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, but just to make sure, here’s how I configure it to work with OCaml.

First, create a file and save it as OCaml_HANA.ml

Then, click on the “Choose more build actions” button


The little half arrow on the right of the brown brick looking button. This will open the following screen


On Compile put the following

corebuild -pkg yojson,cohttp.async,cohttp.lwt,lwt,ezjsonm "%e.native"

And on Execute put

“./%e.native”

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

OCaml_HANA.ml
open Core.Std
open Yojson.Basic.Util
open Ezjsonm

let get_definition_from_json json =
 let json = Ezjsonm.from_string(json) in
 let json = Ezjsonm.(find json ["d";"results"]) in
 let json = Ezjsonm.to_string(json) in
 let json = Yojson.Basic.from_string(json) in
 let json = Yojson.Basic.Util.to_list json in
 let carrname = Yojson.Basic.Util.filter_member "CARRNAME" json in
 let carrname = Yojson.Basic.Util.filter_string carrname in
 let price = Yojson.Basic.Util.filter_member "PRICE" json in
 let price = Yojson.Basic.Util.filter_string price in
 printf "Reading SAP HANA from OCaml\n\n";
 for i = 0 to List.length(carrname) - 1 do
  printf "%s: %s\n" (List.nth_exn carrname i) (List.nth_exn price i)
done

let fetch uri =
 let cred = Cohttp.Auth.string_of_credential(`Basic("SYSTEM", "YourPassword")) in
 let headers = Cohttp.Header.init() in 
 let headers = Cohttp.Header.add headers "Authorization" cred in
 let open Lwt in
 Cohttp_lwt_unix.Client.get ~headers:headers uri 
 >>= fun (_,body) ->
 Cohttp_lwt_body.to_string_list body
 >>= fun strings ->
 return(get_definition_from_json (String.concat strings))  

let () =
  let hana_uri = Uri.of_string "http://YourServer:8000/Flights/flights.xsodata
                                /FLIGHTS?$format=json"
  in Lwt_main.run (fetch hana_uri)

Save your file, press the “Compile the current file” button. The first on the previous images which shows a triangle with an arrow and a ball (all in nice 3D) and then press the “Run or view the current file” button. Last one on the previous image which shows two engines.


You will notice that it comes pretty fast…

Now…something funny about my code…and that might be because of two simple reasons…

• I’m still learning OCaml
• The documentation for external packages is almost non-existent (Actually, I need to browse the GitHub source codes in order to achieve most of the code)

So…the funny thing is that I’m using two different JSON libraries to actually read the ODATA generated by SAP HANA…by using only one I couldn’t manage to get the information that I needed…so using both and extracting pieces from here and there I actually got what I wanted…not so fun when you are doing it…but in the end there a big reward on finally being able to compile it and get the desired output -;)

Greetings,

Blag.
Development Culture.

No hay comentarios: