This chapter shows some programing tips and examples of programing algorithms that users faces comonly when programing in JS-Script.

1 SQL Performance

1.1 Do not check for null variables in SQL

Usualy, programer tend to bias trying to include programing logic into SQL Statement.

For example, we want to execute two same statement but with two filtering conditions, depending on a variable value. In code below, (even it's an incorrect syntax), programer try to retrieve all systables rows if TABNAME is null and only one row if systables is informed (not null)

Copy
<script>
    const TABNAME = null;

    return Ax.db.executeQuery(`
        <select>
            <columns>
                tabid, tabname
            </columns>
            <from table='systables/>
            <where>
                tabname = ? OR ? IS NULL
            </where>
        </select>`, TABNAME, TABNAME);
</script>

Previous statement is an incorrect SQL syntax and also sending to DB engine a "non necessary" work for both optimizer and runner threads.

This kind of syntax can be resolved in runtime by the JS program easily with proper programing:

Copy
<script>
    const TABNAME = null;
    //const TABNAME = 'systables';

    var m_sqlwhere = "1=1";
    var m_params = [];
    if (TABNAME != null) {
        m_sqlwhere = "tabname = ?";
        m_params.push(TABNAME);
    }
    return Ax.db.executeQuery(`
            <select>
                <columns>tabid, tabname</columns>
                <from table='systables'/>
                <where>
                    ${m_sqlwhere}
                </where>
            </select>`, m_params);
 </script>

1.2 Do not use SQL statement to remove WHERE condition

A similar case to previous one, is to use variable values to change SQL conditions dynamicaly on the DB server

In next example, we use SQL Syntax to try to remove "tabname = ?" condition if variable x is equal to XYZ:

Copy
<script>
    const x = "ABC";
    return Ax.db.executeQuery(`SELECT tabid FROM systables where tabname = ? OR "${x}" = "XYZ"`, 'systables');
</script>

This is an unrecommended way of resolving this problem because you're introducing a lot of complexity to SQL Optimizer. If you want to change SQL Statement dynamicaly, do it in runtime:

Copy
<script>
    const x = "ABC";
    var a_params = [];
    var m_sqlwhere = "";
    
    if (x != "XYZ") {
        m_sqlwhere = "where tabname = ?";
        a_params.push("systables");
    }
    return Ax.db.executeQuery(`SELECT tabid FROM systables ${m_sqlwhere}`, a_params);
</script>

1.3 Avoid 'Can not re-use statement while cursor open' error

Trying to open two ResultSets from same statement code, results in a 'Can not re-use statement while cursor open' exception.

Usualy, this error is caused by trying to reopen an unclosed ResultSet and this is a programming error

Next, code demonstrating proper use of resultset close method:

Copy
<script>
var rs1 = Ax.db.executeQuery(`SELECT FIRST 10 tabname FROM systables`);

for (var sys1 of rs1) {
    console.log(sys1.tabname);
    
    var rs2 = Ax.db.executeQuery(`SELECT tabname FROM systables`);
    for (var sys2 of rs2) {
        console.log("ROW=" + rs2.getRow() + " TABNAME=" + sys2.tabname);
        if (rs2.getRow() == 3) {
            console.log("Breaking resultset iteration. Should close resultset before exit.");
            rs2.close();
            break;
        }
    }
    continue;
    console.log("ESTE MENSAJE NUNCA DEBERIA APARECER ==========")
}
</script>

So, be carefull with exit command inside a ResultSet iteration as you should close the ResultSet explicitely before exit. 'continue' statement doesn't has this problem, as the resultset is fully consumed, even if some parts of code are not executed.

2 Using an IDE

Typescript declarations files ( *.d.ts ) provide type definitions for Javascript/Typescript code. This declaration can be used by Code Editors (IDE) to to provide "code completion".The following link contains the types defintions for the Ax library used in server-side JS

Ax type declarations

2.1 Visual Studio Code

Adding code completion with Visual Studio Code is straightforward, just place the definitions file inside the same directory as your JS file.

To enable semantic cheking of Javascript, the flag "Check JS" should be enabled. Just Type "Check JS" in the preferences search input box and it will show up.

2.2 Atom

To add typescheking with Atom editor, you need to install the ide-typescript extensions:

  • Go to Preferences in menu and a Settings tab will open in the editor
  • Press the "+ Install" button and search for ide-typescript in the search bar
  • After ide-typescript box opens, press the Install button.
  • Follow same procedure for atom-ide-ui package.

In addition, nodejs should be installed. Visit the previous link and donwload the installable

You can enable syntax completion file by file by placing the following line at the top of your JS file to activate Axional JS Library extension. You will need also to save the file as typescript ( .ts extension)

Copy
/// <reference path="./global.d.ts" />
new Ax.barcode.PDF417("AA").setErrorLevel()

2.3 Sublime

To add typescheking with Sublime editor, you need to install the TypeScript-Sublime plugin:

  • Go to Preferences/Package control
  • Write "Install Package" and press enter. A new input will show up
  • Type "TypeScript" and press enter to install de package.

In addition, nodejs should be installed. Visit the previous link and donwload the installable

You can enable syntax completion file by file by placing the following line at the top of your JS file to activate Axional JS Library extension.

Copy
/// <reference path="./global.d.ts" />
new Ax.barcode.PDF417("AA").setErrorLevel()

3 Java interoperability

Nashorn and GraalJS include JavaScript language execution runtime and allows interoperability with Java code.

3.1 Using Java Objects from Javascript

Java objects can be passed without loosing any type information on the javascript side. Since the script runs natively on the JVM we can utilize the full power of the Java API. That is, all public methods from java objects can be invoked from javascript.

In addition, java arrays, list and maps can be accessed as if they were javascript objects with some limitations as detailed in the following table

Arrays and Lists
Code Java class Nashorn Graal
.length Array
List
for of loop Array
List
for each loop Array
List
Array.isArray Array
List
arra[index] Array
List
push() Array
List
maps
Code Nashorn Graal
map.key / map['key']
map['key'] = 'A' / map.key = 'A'
delete map.key
Object.keys() (empty map)

3.2 Return types from Ax

As a rule of thumb, values returned by Ax library methods are pure java objects. No conversion is performed on returned values

3.3 Helpers

The static class Class contains serveral methods to inspect the values being holded in js variables.

Class.describe(o) Show the java class and it's methods
Class.isJavaMap(o) Whether the object is an instance of a java Map
Class.isJavaList(o) Whether the object is an instance of a java List
Class.isJavaArray(o) Whether the object is an instance of a java Map
Class.isScriptArray(o) Whether the object is a native JS array
Class.isScriptObject(o) Whether the object is a native JS object

3.4 Passing variables to catalogued functions

3.5 Result of a js execution

When the flow of execution "exits" the javascript context, the returned value by the root script will be converted to a Java type.

For instance, consider a script A tahts calls script B . The value returned from script B will not be converted to Java when the execution of B is finished. On the other hand, the result returned by script A will be converted to java because it's the script that initiated the js execution

Execution flow

Loading...

The following table explains how js objects are converted into java objects

JS type Engine Java type
{a.1} Nashorn java.util.Map<String,Object>
Graal java.util.Map<String,Object>
['a', 1] Nashorn java.util.List<Object>
Graal java.util.List<Object>
new Date() Nashorn java.util.List<Object>
Graal java.util.Date
Number Nashorn BigDecimal / Integer / Double
Graal BigDecimal / Integer / Double
Boolean Nashorn Boolean
Graal Boolean
new Map() Nashorn java.util.Map<String,Object>
Graal java.util.Map<String,Object>