Skip to content
Snippets Groups Projects
how to write JDito code.adoc 8.21 KiB

How to wirte JDito code

1. basics

  • Keep everything english. Every title, caption, messages, comments, etc. should be english. Add german translation to the languages if necessary.

  • in JavaScript-Strings use " instead of ' - even if its only 1 character. ' is for SQL (within JS-Strings)

  • Parameters should start with p.

2. code structure

2.1. vars and others (var, let)

  • avoid let as much as possible because you cannot debug these variables

2.2. brackets

  • { are placed on a new line

Example:

for (i = 0, i < dataLen; i++)
{
    //code here
}

myArray.forEach(function(pItem)
{
    // Do something
});

2.3. loops

nested loops should be defined with replicated indexer variables. Therefore it’s easy to see in which level of the counter you are. Even better would be a good and describing name.

Example:

for (i = 0, i < dataLen; i++)
{
    for (ii = 0, ii < dataLen[i].length; ii++)
    {
        //code...
    }
}

for (row = 0, row < dataLen; row++)
{
    for (col = 0, col < dataLen[row].length; col++)
    {
        //code...
    }
}

3. Functions - overview of different "types"

This sections covers how to define different "types" of functions in libraries.

3.1. by using static methods

This will be mostly utility functions where there is no need to instantiate an object. You’ll need this probably the most time.

→ Static object with static functions.

Definition:

/**
 * provides static methods for validation of communication data
 * do not create an instance of this
 * @static
 * @class
 */
function CommValidationUtil(){}(1)

/**
 * returns a blueprint for validation extensions; these extensions are needed for validating comm data and can be passed to other functions
 * @return {object} a object with properties that have a specific default value; normally you want to overwrite that value
 */
CommValidationUtil.getExtensionsBlueprint = function() (2)
{
    return {
        countryCode: null
    };
}
1 the function-object that keeps everything together - this function should never be actually called (no direct call, no indirect call)
2 an actual function that can be called

And how to use it:

import("Comm_lib");

var additionals = CommValidationUtil.getExtensionsBlueprint();

3.2. by creating an object with functions

You may want to hold data and create objects where methods share that data.

Here is an example for an object that can be created:

/**
 * object that provides featrues for a single keyword attribute; initalizes itself on creation with a specific keyword-attribute
 *
 * @param {String} pContainerName specifies the type of the keyword and therefore the list elements;
 *                                  e.g. "COUNTRY"; use an entry of the $KeywordRegistry here
 * @param {String} pAttributeName the name of the keyword attribute that shall be initalized
 * @param {String} [pDefault=undefined] the default value -> Does not throw an error, if default value exists.
 *
 * @class
 */
function KeywordAttribute(pContainerName, pAttributeName, pDefault)
{
    this.container = pContainerName;
    this.attribute = pAttributeName;
    this.defaultValue = pDefault;

    var keywordAttrData = newSelect("AB_KEYWORD_ATTRIBUTE.AB_KEYWORD_ATTRIBUTEID, AB_KEYWORD_ATTRIBUTE.KIND")
        .from("AB_KEYWORD_ATTRIBUTE")
        .where("AB_KEYWORD_ATTRIBUTE.CONTAINER", pContainerName)
        .and("AB_KEYWORD_ATTRIBUTE.NAME", pAttributeName)
        .arrayRow();

    if (keywordAttrData.length > 0)
    {
        this.id = keywordAttrData[0];
        this.type = keywordAttrData[1];
        this.dbField = this.type.trim();
    }
    else if(pDefault == undefined)
    {
        throw new Error(translate.withArguments("no keyword attribute \"%0\" found in keyword container \"%1\"", [this.attribute, this.container]));
    }
}

/**
 * get the value for a specific keyId.
 * Error if the keyword container does not have the attribute at all (you can check this with .exists())
 * Error if the attribute does not exist at the provided keyId and you have not specified a default
 *
 * @param {String} pKeyId the keyId
 *
 * @return {String} the loaded value (or the default)
 */
KeywordAttribute.prototype.getValue = function(pKeyId)
{
    if (this.exists())
    {
        var attrValue = newSelect(this.dbField)
            .from("AB_KEYWORD_ENTRY")
            .join("AB_KEYWORD_ATTRIBUTERELATION", "AB_KEYWORD_ENTRY.AB_KEYWORD_ENTRYID = AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ENTRY_ID")
            .where("AB_KEYWORD_ENTRY.CONTAINER", this.container)
            .and("AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ATTRIBUTE_ID", this.id)
            .and("AB_KEYWORD_ENTRY.KEYID", pKeyId)
            .cell();

        if (attrValue)
            return attrValue;

        if (this.defaultValue)
            return this.defaultValue;

        throw new Error(translate.withArguments("no keyword attribute \"%0\" found in keyword \"%1\" from container \"%2\"", [this.attribute, pKeyId, this.container]));
    }
    else if (this.defaultValue == undefined)
        throw new Error(translate.withArguments("no keyword attribute \"%0\" found in keyword container \"%1\"", [this.attribute, this.container]));
    else
        return this.defaultValue;
}

/**
 * get a SqlBuilder object for this keyword attribute. You can easily add additional conditions to it.
 *
 * @return {SqlBuilder} a SqlBuilder which contains a select for the entry-id's, joins to entry and attribute
 *                      and conditions for the container and the attribute-name.
 */
KeywordAttribute.prototype.getSqlBuilderSelect = function()
{
    return newSelect("AB_KEYWORD_ATTRIBUTERELATION.AB_KEYWORD_ENTRY_ID")
        .from("AB_KEYWORD_ATTRIBUTERELATION")
        .join("AB_KEYWORD_ENTRY", "AB_KEYWORD_ENTRYID = AB_KEYWORD_ENTRY_ID", "attrEntry")
        .join("AB_KEYWORD_ATTRIBUTE", "AB_KEYWORD_ATTRIBUTEID = AB_KEYWORD_ATTRIBUTE_ID")
        .where(["AB_KEYWORD_ENTRY", "CONTAINER", "attrEntry"], this.container)
        .and("AB_KEYWORD_ATTRIBUTE.NAME", this.attribute)
}

/**
 * check if the Container can have the attribute.
 * @return {Boolean} true if it exists, false if not
 */
KeywordAttribute.prototype.exists = function()
{
    return this.id != undefined && this.type != undefined && this.dbField != undefined;
}

3.3. private functions

Private functions would be possible but make everything much more complicate. So just start your functions / methods name with a _ if you need private methods.

-→ do not use functions which start with a _ outside of the class!

Add @ignore to the comment of those functions to prevent showing them in the generated jsdoc.

4. JS-Doc

1 JS-Doc comment: http://usejsdoc.org/
2 jsdoc-blocks have to start with /** otherwise JSDoc cannot generate a documentation
3 use the correct form for optional/required parameters: http://usejsdoc.org/tags-param.html Optional parameter: [alias=the current alias] Required parameter: alias Classes: @class
/**
 * Description...
 * ...
 *
 * @param {String} [pAlias=the current alias] the database alias where the condition shall be executed later (important for column types of preparedStatements)
 * @example Here is an example
 * @class
 */
function SqlCondition(pAlias)
{
...
}
1 examples are useful on more complex functions
2 constructor function; init properties (do not set functions ("methods") here!)
3 add functions ("methods") to the prototype, they are available through the prototype chain

And how to use it (normally you’d want to use preparedStatements but for the sake of an easy example it’s a bit shorter here) See also HowToSqlConditionLib.adoc for a full documentation.

import("system.vars");
import("system.result");
import("Sql_lib");
import("Comm_lib");

var cond = new SqlCondition();

var mediumIds = CommExtensions.getContextualMediumIds();
if (mediumIds.length > 0)
    cond.and("COMM.MEDIUM_ID in (" + mediumIds.join(", ") + ")");

var idVal = vars.get("$local.idvalue");
if (uids.length > 0)
    cond.and("COMM.COMMID = '" + idVal + "' ");

result.string(cond.toString("COMM.OPTIONAL = 't'"));