Skip to Content
Author's profile photo Graham Robinson

A first look at “River”

Included as part of HANA SP07, due very soon, comes “River”.

River, or River Definition Language (RDL), is a new programming paradigm that is very different from what traditional SAP developers have been used to. The antecedents of River include another “River” that was floated about 3 years ago and technology acquired by SAP from a company called Coghead.

The goal of River is that developers will not so much code exactly what an application does, but rather describe its entity relationship model, associated behaviours and other aspects at a high level and then the RDL compiler will produce suitable artefacts to implement the application on the underlying platform. Importantly the entire implementation of the application is handled by the River compiler.  Let me show you what I mean.

*Note: It is not my intention to provide an exhaustive description of how to setup your River development environment nor describe the developer workflow. This is covered in the River documentation from where I took most of my examples used in this blog.

Let’s start by defining an entity called “Actor” with three elements – name, emailAddress and age. The element “name” is the key of the entity. It is not compulsory to define an entity key (or keys). If you omit this then RDL will automatically add an element called “__ID” that becomes the key.

     entity Actor {
          key element name : String;
          element emailAddress : String;
          element age : Integer;
     }

When we activate this code it generates a number of HANA artefacts. This includes a table to hold the persisted entity data. Depending on the complexity of the entity there may be many more HANA artefacts as well.

/wp-content/uploads/2013/11/river2_329275.gif

The RDL compiler also generates the code that exposes the entity as an OData service with full CRUD – Create, Read, Update, Delete – functionality.

So I can make an OData request to the service to get a list of available entities. This shows me the Actor entity.

/wp-content/uploads/2013/11/river3_329277.gif

And I can use a HTTP POST request to create an new Actor entity by passing in this payload.

{

“name”: “Tom Cruise”,

“age”: 51,

“emailAddress”: “tom dot cruise at gmail dotcom

}

/wp-content/uploads/2013/11/river4_329278.gif

Then I can do a HTTP GET request to the Actor entity to get the complete entity set returned – all 1 of them. 😉

/wp-content/uploads/2013/11/river5_329279.gif

Now lets enhance our River application a bit to see some of the other features of RDL.

First we add a Movie and Producer entity. Here also are some examples of some options we can use when defining elements. The ‘year’ element of the Movie entity is defined as @required – so it must be supplied when you create a new instance of the Movie entity. Also the ‘cost’ element has been defined with a default value of 1 million.

entity Movie {
          key element title : String(100);
          @required element year : Integer;
          element cost : DecimalFloat default 1000000.0;
          element income : DecimalFloat;
          element producer : Association to Producer;
     }
    
     entity Producer {
          key element name : String;
          element movies : Association[0..*] to Movie via backlink producer;
     }

But most importantly you can see above how to establish associations between entities.

Because every Movie has one Producer the element ‘producer’ of the Movie entity is defined as a 1 to 1 association to a Producer entity. Similarly we define the element ‘movies’ in the Producer entity as a 0 to many association to the Movie entity set using the existing association (backlink) from the producer element of the Movie entity set. In a traditional database we would have to define foreign key relationships explicitly and when interacting with the database we would need an intimate knowledge of these relationships to be able to retrieve the relevant data. River removes the need for us to worry about this plumbing entirely.

What about many to many associations I hear you ask? Look carefully at the below code to see how this is done. First we need another entity to manage this more complex association which we will call ‘Casting’. We define elements in this entity that are one to one associations to the Movie and Actor entities. And we define the appropriate elements in the Actor and Movie entities to each other using the “via entity Casting” option.

entity Movie {
          key element title : String(100);
          @required element year : Integer;
          element cost : DecimalFloat default 1000000.0;
          element income : DecimalFloat;
          element producer : Association to Producer;
          element starring : association[0..*] to Actor via entity Casting;
     }
    
     entity Producer {
          key element name : String;
          element movies : Association[0..*] to Movie via backlink producer;
     }

     entity Actor {
          key element name : String;
          element emailAddress : String;
          element age : Integer;
          element movies : association[0..*] to Movie via entity Casting;
     }

     entity Casting {
          @required element movie : Association to Movie;
          @required element star : Association to Actor;
          element salary : DecimalFloat;
     }

Again I think it is important to point out how little code we have had to write to define what are becoming increasingly sophisticated entities and associations. This is the goal of River.

Another cool thing is that you can make a single HTTP POST call to create an entity and other entities it is associated with. For example a HTTP POST to the Movie entity with the following payload will create both the “Top Gun” Movie entity, the “Jerry Bruckheimer” Producer entity and the Casting entity that manages the many to many association between them.

{

“title”: “Top Gun”,

“year”: 1986,

“genre”: “DRAMA”,

“producer”: {

“name”: “Jerry Bruckheimer”

},

“income”: 200

}

We can also create calculated elements in entities.

     entity Actor {
          key element name : String;
          element emailAddress : String;
          element age : Integer;
          element movies : association[0..*] to Movie via entity Casting;
          element totalIncome = SELECT ONE SUM(salary) as sumOfSalary FROM Casting;
          element birthYear = 2013 - age;
     }

The ‘birthYear’ element of the Actor entity is a simple calculation example. The ‘totalIncome’ element is a little more sophisticated in that it performs a SQL statement and returns the result whenever it is addressed.

You can also define your own data types, including complex types, and use enumerators as well.

     type Genre : enum { ACTION_GENRE; COMEDY; DRAMA; FAMILY; ADVENTURE; SCI_FI; }
     type Rating : String(5) enum {
          General_Audiences = 'G';
          Parental_Guidance = 'PG';
          Parents_Strongly_Cautioned = 'PG-13';
          Restricted = 'R';
     }
     type Address {
          element city : String (20);
          element country : String(20);
     }

     entity Movie {
          key element title : String(100);
          @required element year : Integer;
          element cost : DecimalFloat default 1000000.0;
          element income : DecimalFloat;    
          element producer : association to Producer;
          element starring : association[0..*] to Actor via entity Casting;
          element rating : Rating default Rating.Restricted;
          element genre : Genre;
          element location : Address;

And you can define River views as well.

     view Blockbusters as
          SELECT TOP 10 FROM Movie {
               title,
               genre,
               income
          }
          ORDER BY
               income DESC;

Notice that SQL syntax in River can be a bit different from the standard – which you can still use as well. SAP claim the new SQL syntax is more logical and easier to read, since you first write what entity you want to query, and then which elements you want to return. Certainly it makes code completion in the editor very effective when looking up elements. It also allows you to build complex queries without having to specify complex joins. For example the following statement implicitly makes a join between the Movie and Producer entities.

SELECT FROM Movie { producer.name, SUM(income – cost) as total} GROUP BY producer.name

Now what about some business logic. You add business logic to entities through Actions. These actions can take input parameters and can return values as well.

Look at the below example where we have added the action ‘audition’ to the Movie entity.

     entity Movie {
          key element title : String(100);
          @required element year : Integer;
          element cost : DecimalFloat default 1000000.0;
          element income : DecimalFloat;    
          element producer : association to Producer;
          element starring : association[0..*] to Actor via entity Casting;
          element rating : Rating default Rating.Restricted;
          element genre : Genre;
          element location : Address;
         
          action audition(auditionStar : Actor) : String {
               let message : String = 'Dear ' + auditionStar.name +
               '. Thank you for your application for the movie ' + this.title + '. ';
               if( auditionStar.age > 50 && this.genre != Genre.DRAMA) {
                    message = message + ' Unfortunately, you did not get the part.';
               }
               else {
                    message = message +
                         ' Congratulations! You are the perfect casting for this movie.';
                    let tmpMovies = SELECT movie,salary FROM Casting
                         WHERE Casting.star = auditionStar;
                        
                    let fairOffer = SELECT ONE AVG(salary) as offer FROM tmpMovies
                         WHERE movie.genre = this.genre;
                        
                    let c : Casting =
                         Casting{movie: this, star: auditionStar,
                              salary: fairOffer.offer};
                    c.save();
               }
               return message;         
          }
     }

In the first part of the audition action it checks if the actor is right for the part based upon their age. If they are under 50 they can get any part but if they are over 50 they can only get parts from the drama genre. A message variable is built to reflect this decision that is returned when the action completes.

If the actor is accepted the second section of the audition action creates a new Casting entity. First it queries existing Casting entities for this actor and uses the results to calculate the average salary for this actor for the chosen genre. The calculated average salary is passed into the instantiation of the new Casting entity and then the save method is called to persist the new entity.

So by calling the audition action for the move ‘Top Gun’ with a HTTP POST request to…

http://river.yelcho.com.au/sap/hana/rdl/odata/v1/GrahamRobbo/RiverDemo/Movie(‘Top Gun’)/audition

…and passing in the following payload….

{

“auditionStar”: “KEY(Actor(‘Tom Cruise’))”

}

….I get the result….

{

“d”: “Dear Tom Cruise. Thank you for your application for the movie Top Gun. Congratulations! You are the perfect casting for this movie.”

}

And more importantly the new Casting entity has been created for me as well.

Again the important message here is that the developer gets to focus on what the application actually has to do rather than the minutiae of the implementation. That job is left the the RDL Compiler.

Last step to complete our application is the user interface. River does not play here – it is only for building the back-end. You can use whatever your favourite UI technology is to build the user experience on top of the OData services that the RDL compiler has built for you.

Perhaps a Fiori-style SAPUI5 experience might suit?

Assigned Tags

      33 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Christopher Solomon
      Christopher Solomon

      Nice "dip of the toes" into River. haha 😛

      Author's profile photo Graham Robinson
      Graham Robinson
      Blog Post Author

      Didn't want to go too deep and get into trouble. 😏

      Author's profile photo Raman Korrapati
      Raman Korrapati

      Thanks for sharing.

      Author's profile photo Vivek Singh Bhoj
      Vivek Singh Bhoj

      Awesome blog Graham

      Thanks for sharing

      Eagerly waiting for SPS07 release to try RDL

      Regards,

      Vivek

      Author's profile photo Ramesh Babu Srikakollu
      Ramesh Babu Srikakollu

      Good to know about the upcoming language RDL. Thanks for sharing the information.

      Regards,

      Ramesh

      Author's profile photo Former Member
      Former Member

      Hi Graham,

      Thanks for sharing the information.

      Regards,

      Krishna Chauhan

      Author's profile photo Rama Sudhakar
      Rama Sudhakar

      Hi Graham,

      nice information about RDL, but how it helps to an ABAPrs?

      Regards

      Sudhakar

      Author's profile photo Graham Robinson
      Graham Robinson
      Blog Post Author

      I'm an ABAPer. 😉

      Author's profile photo Former Member
      Former Member

      😛

      Author's profile photo Matthias Steiner
      Matthias Steiner

      Great blog Robbo - thanks for sharing!

      It's going to be interesting to hear more about it next week...

      Author's profile photo Henrique Pinto
      Henrique Pinto

      You forgot to mask the URL on the GET screenshot. 😳

      Author's profile photo Wouter Lemaire
      Wouter Lemaire

      Nice blog! Thanks for sharing!

      Kind regards,

      Wouter

      Author's profile photo Trond Stroemme
      Trond Stroemme

      Thanks for sharing! Looking forwards to trying SP07!!

      Author's profile photo Former Member
      Former Member

      Thanks Graham for the wonderful insight.... RDL seems to be interesting... will appreciate if you can provide some docs which throw light on RDL in little wide spectrum...

      Thanks

      Ankur

      Author's profile photo Former Member
      Former Member

      Hi Ankur,

      See my comments below. Also this link, might be useful as well (more of a general overview).

      Author's profile photo Former Member
      Former Member

      Feeling good and excited after reading the document of River. Thanks to Graham for posting this wonderful blog. Could you provide any additional documents and videos related to SAP River.

      Thanks,

      Vijaykrishna

      Author's profile photo Andrew Barnard
      Andrew Barnard

      Hi Robbo, It would be great if River c/would inspire the existing ABAP Persistence Services framework. Auto-generation of CRUD services and the processing of associations. Andrew 

      Author's profile photo Graham Robinson
      Graham Robinson
      Blog Post Author

      Hi Andrew - I like the way you are thinking 😉

      Author's profile photo Graham Robinson
      Graham Robinson
      Blog Post Author

      Thanks for your comments everyone - and for those of you wanting more information on River make sure you listen to Vishal's keynote at TechEd Bangalore later this week.

      Author's profile photo Trond Stroemme
      Trond Stroemme

      Hi Graham,

      you're referring to the "River documentation". Could you please post a link? Or is it still buried deep in the vaults of Walldorf... ? 🙂

      Regards,

      Trond

      Author's profile photo Graham Robinson
      Graham Robinson
      Blog Post Author

      Wait for TechEd Bangalore announcements this week.

      Author's profile photo Former Member
      Former Member

      Indeed !!!

      Author's profile photo Former Member
      Former Member

      http://scn.sap.com/docs/DOC-47587 and help.sap.com/river. Also, more content will be released right after Vishal's Bangalore keynote.

      Author's profile photo Former Member
      Former Member

      See some more here, and a here.

      Author's profile photo James Rapp
      James Rapp

      Good explanation ... I look forward to test driving this with the knowledge I've gained from Introduction to Software Development on SAP HANA from openSAP.

      Author's profile photo Marco Furlanetto
      Marco Furlanetto

      Hi Graham,

      Very interesting. It looks like Hana is incorporating ORDBMS features. I wonder if RIVER supports inheritance too?

      Thanks

      Marco

      Author's profile photo Former Member
      Former Member

      Not yet Marco, but we are considering this issue.

      Author's profile photo Former Member
      Former Member

      Hi Marco,

      Currently River does not support inheritance. We might introduce this later.

      Best,

        David

      p.s. Rafi, as always you are faster 😉

      Author's profile photo Bhagya Subbareddy
      Bhagya Subbareddy

      Very cool, Graham! Thanks for the early wisdom. Very helpful.

      Author's profile photo Shakul Jugran
      Shakul Jugran

      Its so invigorating to find ourselves in the midst of a new SAP 🙂 Thanks for sharing Graham. Maybe now that TechEd Bangalore is done, could we have a consolidated post/blog with the RDL links?

      Many thanks!

      Author's profile photo Former Member
      Former Member

      Hi Shakul,

      If you mean the official SAP River links (as opposed to independent blogs about SAP River, such as this one), then there is a list at the bottom of this post.

      Author's profile photo Shakul Jugran
      Shakul Jugran

      Thanks a lot Rafi 🙂

      Author's profile photo Thomas Schindwolf
      Thomas Schindwolf

      Nice overview with easy insights via examples - THANKS