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
    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.

      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR I'm not sure why you quoted me and then talk about something different than what I was referring to.

      You said...

      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.

      ...which is demonstrably false and I believe a response to my comment...

      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.

      You pass arguments and define parameters by the way.

       

      Good information on Ninox Id's. I haven't use the debugValueInfo() function yet.

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

    I discovered that it was possible to pass a record as a parameter to a function. To do so, you just have to put the name of the table instead of the data type (node : Customer).

    function myRecord(node : Customer) do
        var name := node.'First Name' + " " + node.'Last Name';
        name
    end;
    myRecord(first(select Customer))
    

    I don't know what we'll be able to do with it yet, but I'm sure we'll find 😂

    • Sean
    • 2 yrs ago
    • Reported - view

    I toyed around with this...

    ...and came to the facepalm realization that formatJSON and parseJSON will accomplish the same thing and is a little tidier.

    function myFunction(tbl : text) do
        let myTable := parseJSON(tbl);
        alert("Record count:  " + count(myTable) + "
    Name1:  " + item(myTable, 0).Name + "
    Name2:  " + item(myTable, 1).Name)
    end;
    myFunction(formatJSON((select Vendor)[text(State) = "AR"].[{
                Name: Name,
                Address: Address
            }]))
    

    Unfortunately, the data is readonly when used in a function this way.

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

      Sean With Native JS, you can pass a table to a function and turn it into a table in the function. It's a bit like passing the table directly to the function:

      function calculateNID( strNID : text) do
          // Convert an array of strings to NID (table).
          var table := #{:nid(Customer) return strNID.split(',')}#;
      
          // Use the table as if it came from a select.
          alert("Record count : "+ count(table)+"
      "+table.("Name : "+'First Name'+"
      "));
      end;
      
      // Call the function with the filtered table as a string
      calculateNID( string(select Customer where 'First Name' like "S" ))
      

      Perhaps this can help you write data into the function ?

      And yes, with the JSON format, we can already do a lot of very interesting things.

      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR 😎I’ll check it out. Do you have an example that shows the data being modified and saved to the table?

      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR I don't know how modifying data inside a function and storing that modified data is going to be possible unless Ninox makes it possible. To execute file IO with JavaScript would require something like Node.js' File System module to work on IO locally. There would be a different requirement to work with the cloud version. I can make file IO work inside of VS Code, but not with Ninox.

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

      Sean Two things : 

      1 - I modified the code, because I was using an array as a comma separated string that was then reconstituted into an array. The problem is that if there was any data in the array that contained a comma, then it would have been taken as a separator as well. This would have distorted the array. This is very unlikely, but it's best to get into good habits from the start.
      So now I use formatJSON to pass the select Customer...

      2 - The array is handled like any other Ninox array. The data modification is done exactly as if we had written "table := select Curstomer where ...". 

      Here is an example that illustrates these two points:

      function calculateNID( strNID : text) do
          #{// conversion of the string in Ninox table}#;
          var table := #{:nid(Customer)
              return JSON.parse(strNID)}#;
      
          #{// data modification}#;
          for i in table do
              i.'Full name' := i.'First Name' + i.'Last Name';
          end;
      end;
      
      #{// Call the function using JSON formatting}#;
      calculateNID( formatJSON(select Customer where 'First Name' like "S" ))
      

       Does this answer your question?

      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR I get the spinning "working on it" visual in the middle of the screen. I've attached the database.

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

      Sean With your test application, I was able to fix a bug that leaves Ninox in waiting mode and add the possibility to put code in a global function. Until then I had not tried it and I had forgotten to get the values passed in parameter. It is now done.

      It work fine now, Thanks👍

      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR That is fantastic! Thank you!  😃

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

      Sean In the end, it is not very interesting, because it is possible to do the same thing in pure Ninox white 2 lines 🙄 :

      function calculateNID( strNID : text ) do
          var arrayOfNID := split((strNID), ",");
          select Customer where (var id := this.id; count(arrayOfNID[=id])>0);
      end;
      
      calculateNID(string(select Customer where 'First Name' like "s"))
      
      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR  Wow, it's amazing you can figure out how to do it, but you can't see the difference between the two. You've just hard hard-coded the table name in the Ninox version 🙄

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

      Sean I don't understand what you mean? In both cases the number of the table is hardcoded in the function :

      ----------------

      Code 1 :

      function calculateNID( strNID : text) do
          var table := #{:nid(Customer)
              return JSON.parse(strNID)}#;
          for i in table do
              i.'Full name' := i.'First Name' + i.'Last Name';
          end;
      end;
      calculateNID( formatJSON(select Customer where 'First Name' like "S"))

       

      code 2 :

      function calculateNID( strNID : text ) do
          var arrayOfNID := split((strNID), ",");
          var table := select Customer where (var id := this.id; count(arrayOfNID[=id])>0);
          for i in table do
              i.'Full name' := i.'First Name' + i.'Last Name';
          end;
      end;   

      calculateNID(string(select Customer where 'First Name' like "s"))

      ----------------

      The advantage of these functions is that they handle pre-filtered records, but no matter what, they always know the name of the table in advance.

      If you want a function that retrieves records from a table without knowing the name of the table, then you have to make another code. And I think it's only possible to do that with NativeJS.

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

      Jacques TUR In fact, to manipulate a table without knowing it in advance, you have to use javascript only. Ninox being a pre-compiled language, it needs to know in advance the nature of the variables it manipulates. It is therefore impossible to manipulate a table in a Ninox function without knowing its name in advance.

      On the other hand, with javascript (NativeJS) there is no problem because it is an interpreted language. But then, the risks of error, and therefore the development time, are more important.

      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR Sorry  for the late reply, but I just finished my work day.

      I can't even get your "Ninox" version of the function to work so that I could compare the results.

      What I am able to do is create a table named Buyer with the same fields as Customer and with some additional fields so the Buyer table is not exactly the same as the Customer table. I can then use the same function to concatenate the First Name and Last Name fields of the Buyer table and not change the name in the function to Buyer. I pass Buyer as an argument when I call the function. I could create many tables with the same field names and use that one function to modify them. You can't do that when you directly use the select statement in the function body. That would be hard coded.

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

      Sean Yes, I understood a little what you wanted to do, but unfortunately with the function in NativeJS it's not possible either because the name of the table is also hard coded. 

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

      Jacques TUR I just did the test with the database you sent me. I added First, Last and Full name fields to the Vendor table. Then called the function with some records of this table. The function runs, but it changes the wrong fields. This is because the function is stored in the "system" form, i.e. using the table and field IDs and not their names:

      ((function calculateNID2(strNID : text) do
      (
          #{// conversion of the string in Ninox table}#;
          (var table := #{:nid(Customer)
                          return JSON.parse(strNID)}#;
              (#{// data modification}#;
              (for i in table do
                  (i.(C := (i.A+i.B)))
              end)
              )
          )
      )
      end);
      calculateNID2(formatJSON((select B where (length(O) > 0)))))
      

      In this form, we can see that in the for loop, it is i.C that is updated. But if the ID of the field whose ID is C can be different from one table to another.
      The IDs of the fields and tables are visible when we retrieve the database structure via the API. 

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

      Sean 

      Sean This solution does what you want : 

      function ModifyTable(table : text,recs : text) do
          "creation of Ninox code in the form of a character string that will modify the correct table.
          Here, the function testx is used to check if the record ID is in the list of IDs (recs) passed in parameter.
          This is finally the simplest solution. It could also be used in the previous examples.";
          var fn := ---
      (select { table } where (var id := this.id; testx("{ recs }", id+"\b"))).('Full Name' := 'First Name' + " " + 'Last Name')
      ---;
          "
          compilation and evluation of the code.
          Here the Eval function cannot be used, because it does not allow table modification.
          fireEvalGlobal is the equivalent of the Exec function of the API.
          Using the API would also be another solution to avoid using JavaScript";
          var err := #{return exUtilsNx.fireEvalGlobal(fn)}#;
          "
          Displays the cause in case of execution error";
          if err then alert(err) end
      end;
      ModifyTable("Vendor", string(select Vendor where 'First Name'))
      • Sean
      • 2 yrs ago
      • Reported - view

      Jacques TUR Thank you for this. I’ve got a full day ahead of me and will try it out as soon as I can.

    • support.1
    • 2 yrs ago
    • Reported - view

    Hi, fairly new to Ninox and now in the process of "tidying" up a database which has become a bit untidy in terms of number of fields and duplication, this thread sort of fits with what I am trying to achieve but I can't seem to make it work my aim is to have a master table and 2 child tables (soon to add a third) and for the master to pull the data from the child tables. What I have ended up with is 3 functions which I would ideally like as a single function and the key is to pass the table name & required fields into the select statement.

    So what I have is this 

    Formula P1

    let t := this;
    let SELFIL := (select table2 where 'order-id' = t.'Channel reference');
    SELFIL;
    SELFIL.'product-name'

    Formula P2

    let t := this;
    let SELFIL := (select table3 where 'Order Number' = t.'Channel reference');
    SELFIL;
    SELFIL.'Product Name'

    Formula Product Name

    if P1 = "" then P2 else P1 end

    Sorry if this is basic but I am not a coder

    Thanks in advance

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

      support Hello, 

      I think there are many possible answers. But before that, could you create a new post about it? This post is about what kind of parameters it is possible to pass to a function and to help future Ninox users, it is better if it stays on this topic.

Content aside

  • 3 Likes
  • 2 yrs agoLast active
  • 46Replies
  • 1818Views
  • 10 Following