Uploaded image for project: 'Couchbase Server'
  1. Couchbase Server
  2. MB-35851

Allow local variable in N1QL Javascript functions

    XMLWordPrintable

Details

    • Improvement
    • Status: Closed
    • Minor
    • Resolution: Done
    • 6.5.0
    • feature-backlog
    • query
    • Any

    Description

      Functions in N1QL currently don't allow local variables (nor do they support a return statement) for example implementing a Haversin function (for the distance in Km between two lon/lat pairs has to be implemented as an inline as follows:

      CREATE FUNCTION getDistanceFromLatLonInKm(lon1, lat1, lon2, lat2) {
        6371 * 2 * atan2(sqrt(
          (
            sin(((lat2-lat1) * (3.14159265359/180))/2) * 
            sin(((lat2-lat1) * (3.14159265359/180))/2) +
            cos((3.14159265359/180)*(lat1)) * cos((3.14159265359/180)*(lat2)) *
            sin(((lon2-lon1) * (3.14159265359/180))/2) * 
            sin(((lon2-lon1) * (3.14159265359/180))/2)
          )
       
        ), sqrt(1-
          (
            sin(((lat2-lat1) * (3.14159265359/180))/2) * 
            sin(((lat2-lat1) * (3.14159265359/180))/2) +
            cos((3.14159265359/180)*(lat1)) * cos((3.14159265359/180)*(lat2)) *
            sin(((lon2-lon1) * (3.14159265359/180))/2) * 
            sin(((lon2-lon1) * (3.14159265359/180))/2)
          )
        ))
      };

       

      Where the actual function I modeled it from would be much more readable and faster (due to eliminating repetitive calculations) using local variables and a return statement if such syntax were supported in a N1QL Javascript function

      CREATE FUNCTION function getDistanceFromLatLonInKm(lon1, lat1, lon2, lat2) {
        var PI = 3.14159265359
        var deg2rad = PI/180;
        var R = 6371; // Radius of the earth in km
        var dLat = deg2rad*(lat2-lat1);
        var dLon = deg2rad*(lon2-lon1);
        var a =
          sin(dLat/2) * sin(dLat/2) +
          cos(deg2rad*(lat1)) * cos(deg2rad*(lat2)) *
          sin(dLon/2) * sin(dLon/2)
          ;
        var c = 2 * atan2(sqrt(a), sqrt(1-a));
        var d = R * c; // Distance in km
        return d;
      };

      Oddly Eventing allows the user to use local variables as such it seems somewhat inconsistent between the two domains

       

       

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          Correct.  Right now, INLINE function is a N1QL expression/statement.  

          The workaround for this is to write a JavaScript function, which has way more flexibility

          keshav Keshav Murthy added a comment - Correct.  Right now, INLINE function is a N1QL expression/statement.   The workaround for this is to write a JavaScript function, which has way more flexibility
          jon.strabala Jon Strabala added a comment -

          I am not sure, but since Javascript in Eventing supports local variables right now, I am hopeful that this might be hanging fruit.

          jon.strabala Jon Strabala added a comment - I am not sure, but since Javascript in Eventing supports local variables right now, I am hopeful that this might be hanging fruit.
          marco.greco Marco Greco added a comment -

          Jon Strabala I think you are mixing up languages.
          You show an example of a INLINE function yet you ask for javascript function behaviour.
          Inline functions are only made of one N1QL expression, and that's it.
          Think of them as a named Common Table Expression.

          Javascript functions, on the other hand, do allow for the whole of the javascript syntax supported by the V8 runner, including local variables, returns, etc.
          There's nothing to be implemented here - it's already available.

          If you are asking for a N1QL function that has local variables and return statements, that's not a low hanging fruit.
          It requires a whole host of new parser rules, a new host of algebra types, and a completely new language runner.
          I would like to eventually implement a N1QL procedure language, but this is a large effort, and javascript has been preferred instead.

          I would suggest you check the 6.5 beta documentation for
          functions, check in particular external functions and how to create javascript functions and satisfy yourself that in fact javascript already does all that you want.
          The example in the docs does in fact use local variables and return.
          Unless I hear from you otherwise in the very near future, I am going to close this as already implemented.

          marco.greco Marco Greco added a comment - Jon Strabala I think you are mixing up languages. You show an example of a INLINE function yet you ask for javascript function behaviour. Inline functions are only made of one N1QL expression, and that's it. Think of them as a named Common Table Expression. Javascript functions, on the other hand, do allow for the whole of the javascript syntax supported by the V8 runner, including local variables, returns, etc. There's nothing to be implemented here - it's already available. If you are asking for a N1QL function that has local variables and return statements, that's not a low hanging fruit. It requires a whole host of new parser rules, a new host of algebra types, and a completely new language runner. I would like to eventually implement a N1QL procedure language, but this is a large effort, and javascript has been preferred instead. I would suggest you check the 6.5 beta documentation for functions , check in particular external functions and how to create javascript functions and satisfy yourself that in fact javascript already does all that you want. The example in the docs does in fact use local variables and return. Unless I hear from you otherwise in the very near future, I am going to close this as already implemented.
          jon.strabala Jon Strabala added a comment - - edited

          Marco - thanks the detailed explanation, by all means close it as implement. 

          My issue was mostly that implementing complex inline functions become somewhat hard to follow without intermediate local variables. 

          Only one small comment limited javascript is supported in Eventing so perhaps some of that work might be portable if Javascript was chosen as a first class procedure language.

           

          jon.strabala Jon Strabala added a comment - - edited Marco - thanks the detailed explanation, by all means close it as implement.  My issue was mostly that implementing complex inline functions become somewhat hard to follow without intermediate local variables.  Only one small comment limited javascript is supported in Eventing so perhaps some of that work might be portable if Javascript was chosen as a first class procedure language.  
          marco.greco Marco Greco added a comment -

          N1QL supports javascript functions exactly as eventing does.
          They both control and use a pool of external V8 runner processes to which they pass function call requests and from which read results.
          They literally use the same infrastructure and are developed by the same team.
          I really don't understand what you think should be ported, because, again, it's all available to both services.

          marco.greco Marco Greco added a comment - N1QL supports javascript functions exactly as eventing does. They both control and use a pool of external V8 runner processes to which they pass function call requests and from which read results. They literally use the same infrastructure and are developed by the same team. I really don't understand what you think should be ported, because, again, it's all available to both services.

          People

            keshav Keshav Murthy
            jon.strabala Jon Strabala
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes

                PagerDuty