3

Function parameters - which types are possible

I've found this old post 

https://ninox.com/en/forum/technical-help-5ab8fe445fe2b42b7dd39ee7/types-of-parameters-for-a-private-function-5c0962c08d9fa6683abafc7d

And not really any docs on the topic.

Any changes on this?

Being able to call a function with parameters record, records, arrays, JSON - without workarounds is requested.

 

Thx 

Jesper

46 replies

null
    • Ninox developper
    • Jacques_TUR
    • 2 yrs ago
    • Reported - view

    The possible types for a function are : 

    • text 
    • number
    • date
    • datetime
    • time
    • timeinterval
    • appointment
    • boolean
    • html
    • color
    • icon
    • email
    • phone
    • location
    • file
    • user
    • any

    with user type, you could call with single user or array of user : 

    function myFunction(myUser : user) do
        userName(myUser)
    end;
    myFunction(user())
    

    or 

    function myFunction(myUsers : user) do
        join(for u in myUsers do
            userFullName(u)
        end, ", ")
    end;
    myFunction(users())
    

     

    With the any type you can call with a JSON variable :

    function myFunction(a : any) do
        capitalize(text(a.firsName)) + " " + upper(text(a.lastName))
    end;
    myFunction({
            firsName: "Jacques",
            lastName: "TUR"
        })
    

    You can also call with array of JSON variable :

    function myFunction(t : any) do
        "// recover the array from JSON array";
        "// and return the array filtred and sorted";
        var c := for i in t.table do
                i
            end;
        c[lastName like "T"] order by this.firstName
    end;
    "//call with array of JSON";
    myFunction({
            table: (select Customer).[{
                    firstName: 'First Name',
                    lastName: 'Last Name'
                }]
        })
    

    And, of course, call with table result :

    function myFunction(t : any) do
        "// constructs an array of records identical to the one obtained with the Select function";
        "// the ID number is gotten by keeping only the number part in order to call the Record function";
        var c := for i in t.table do
                record(Customer,number(extractx(text(i), "\d.*")))
            end;
        c.('First Name' + c.'Last Name')
    end;
    myFunction({
            table: select Customer
        })
    
    • Sean
    • 2 yrs ago
    • Reported - view

    Wow, thanks Jacques! I think Ninox still has some work to do with their documentation. 😄

    • Sean
    • 1 yr ago
    • Reported - view

    Jacques TUR In the last example, do you know of a way to substitute the actual table name in the record() function? Otherwise, you might as well just use the select statement in the function definition. Thx

      • Ninox developper
      • Jacques_TUR
      • 1 yr ago
      • Reported - view

      Sean I'm not sure I understand your question. Can you tell me what you would like to achieve?

      • Sean
      • 1 yr ago
      • Reported - view

      Hi Jacques, In the record() function you use Customer for the table name. To me, that seems to be hard coding the function. Do you know if there is a way to use a variable there?

      • Ninox developper
      • Jacques_TUR
      • 1 yr ago
      • Reported - view

      Sean something like that ?

      function myFunction(tableName : text,fieldName : text,filter : text) do
          var c := eval("select " + tableName + " where " + fieldName + " like " + filter, this);
          c
      end;
      myFunction("Customer", "'First name'", "A")

      • Sean
      • 1 yr ago
      • Reported - view

      Jacques TUR I don't think that will work in a global context. I get...

      "Keyword not defined in this context: this at line 2, column 90"

      when I use it in the Console. I tried using t.caption since that is where the table name is stored in the database schema, but it doesn't return anything. I'm going to be out of touch for a while.

      • Ninox developper
      • Jacques_TUR
      • 1 yr ago
      • Reported - view

      Sean yes, of course "this" does not exist in the console. You have to replace it with another record number, like "first(select Customer)".

      • Sean
      • 1 yr ago
      • Reported - view

      Jacques TUR That’s not what what I am asking about.

      • Ninox developper
      • Jacques_TUR
      • 1 yr ago
      • Reported - view

      Sean Sorry, I misunderstood. Can you send me your code?

      • Sean
      • 1 yr ago
      • Reported - view

      Jacques TUR 

      • Ninox partner
      • RoSoft_Steven.1
      • 1 yr ago
      • Reported - view

      Sean 

      I think it can be done with the eval() function (Haven’t try it though).

      let code:= “record(“+ FieldContainingYourTablename+”,number(extractx(text(i),””\d.*””)))”;

      eval(code,this)

      Steven

      • Sean
      • 1 yr ago
      • Reported - view

      RoSoft_Steven 

      I don't think "this" can be used in a "Global function". If you get it to work let me know.

      • Ninox developper
      • Jacques_TUR
      • 1 yr ago
      • Reported - view

      Sean In NinoxScript, it is not possible to pass a table as a parameter to a function, nor a record (you can pass an array that would be the result of a Select with the any type). However, a function can return any type, including tables and records.
      The only way I know of, in NinoxScript, is to pass the table name as a string, and then use the Eval function. Unfortunately, Eval returns a variable of type Any, which in our case will be a table with all the ID numbers of the table passed in as parameters.
      In addition, the Eval function asks for a record number to know the execution environment of the code. If the code does not use the environment variables it can be passed any record from any table in the database.
      So, for a global function that would return a table variable from the table name, here is what I propose:

      function getTable(tableName : text) do
          var arrayOfID := eval("select " + tableName, first(select Invoice));

      end;
       

      • John_Halls
      • 1 yr ago
      • Reported - view

      Sean What does the second parameter in eval() do? I've only ever seen and used "this"

      Regards John  

      • Sean
      • 1 yr ago
      • Reported - view

      Jacques TUR Maybe something is getting crossed in translation, but yes, you can pass a table object or a record object as an argument to a user defined function. Your example uses a table object. Here is an example with a record object...

      Same, but defined in "Global functions"...

      I will look at your code further tomorrow. I'm winding down after driving 600 miles today so I'm a little beat.

      • Sean
      • 1 yr ago
      • Reported - view

      John Halls first() and last() functions also return a Ninox Id (nid) like "this" does. I tried variations of what I thought they were returning (record Id, table letter + record Id, etc), but those did not work. If anyone can figure out how to spoof the nid then we’ll be able to use eval in a global context without committing to a specific table.

      • Sean
      • 1 yr ago
      • Reported - view

      Sean Disregard that last part. I believe first() or last() will accomplish that goal. I haven’t had my coffee yet this morning.

       

      Even though you are committing to a table when you use first(), it doesn’t have to be the table name being passed as an argument to the UDF.

      • Ninox developper
      • Jacques_TUR
      • 1 yr ago
      • Reported - view

      John Halls 

      The variable "This" corresponds to the current record (RID) when Eval is called from a form function. You can replace it with any Ninox function that returns a RID (one record) like First, Last, Record...

      This allows the Eval function to know which record we are talking about in the code,
      This is called the runtime environment. For example Eval("this.First Name'", first(Customer)) returns the value of the First Name field of the first record in the Customer table.

      • John_Halls
      • 1 yr ago
      • Reported - view

      Jacques TUR Thank you Jacques. There will be plenty of places for that beauty in my code from now on. 

    • Sean
    • 1 yr ago
    • Reported - view

    So this looks like a bust. It would be nice to be able to either pass the table name as an argument or somehow get "this" to work in a global context. I tried to use a number instead of using the first() function in place of "this", but no joy even though first(select table) = 1 returns true. Using a function like first() commits you to a table just like record().

     

    While you can pass a table or record object to a user defined function, if you are going to use the record() function then you have already committed to using a specific table and there is no point in passing it as an argument. This code produces the same output.

     

    function myFunction() do
        for rec in select Customer do
            rec.('First Name' + " " + 'Last Name')
        end;
    end;
    myFunction()
    

     

    If you don't need to modify any of the data and want the flexibility of a user defined function to generate output it make sense to pass a table or record object as an argument, but you will need to include the fields you want to pass, e.g., table: (select Customer).('First Name' + " " + 'Last Name').

    • Sean
    • 1 yr ago
    • Reported - view

    I did get eval() to work in a "Global function". It's not perfect, but it works. Even though I assign the result of the eval() in a variable, I can't use dot notation to access the fields. I have to include the dot notated field in the eval string. Thanks Jacques TUR  for your help.

     

    function myEvalFunction(table : text,rec : number) do
        let myEvalString := "record(" + table + "," + rec + ").Name";
        let myEval := eval(myEvalString, first(select Truck));
        myEvalString + "
    " + myEval
    end
    

    Note, the first() function uses a different table than the passed table argument.

    • Sean
    • 1 yr ago
    • Reported - view

    One more note, I can't use the result of the eval() to assign a new value to the field, e.g., record(Vendor, 4).Name := newName. This is possible otherwise.

    • Sean
    • 1 yr ago
    • Reported - view

    I thought I had it figured out... I didn't eval the entire string, but then I got this disappointing message after I updated my code which pretty much drops a stinky dump on my project...

     

    function evalFunction(table : text,rec : number,name : text) do
        let getName := "record(" + table + "," + rec + ").Name";
        let curName := eval(getName, first(select Truck));
        let setName := "record(" + table + "," + rec + ").Name := """ + name + """";
        let newName := eval(setName, first(select Truck));
        curName + "
    " + newName
    end
    
    • Ninox developper
    • Jacques_TUR
    • 1 yr ago
    • Reported - view
    Sean said:
    Maybe something is getting crossed in translation, but yes, you can pass a table object or a record object as an argument to a user defined function

    No, it's not a NID (table) or RID (record) variable but just an Any variable. This is very different. Similarly, the Eval function returns a variable of type Any, not of type NID or RID. That's why you can't use the result as a normal Select.

    The Select function returns an NID type (try: debugValueInfo(select Customer) in console )
    The Record function returns an RID type (try: debugValueInfo(record(Customer,1)) in console ).
    And now try this in the console:

    var a :={table : select Customer,
    rec : record(Customer,1)};
    debugValueInfo(a.table);


    When calling a function with a JSON parameter, Ninox transforms the NID into Any.

Content aside

  • 3 Likes
  • 1 yr agoLast active
  • 46Replies
  • 1535Views
  • 9 Following