Skip to content
Snippets Groups Projects
process.js 22.45 KiB
import("system.util");
import("system.datetime");
import("system.translate");
import("system.neon");
import("system.vars");
import("system.db");
import("Sql_lib");
import("Keyword_lib");

/**
 * Provides functions for the work with attributes, like
 * listing the available attributes for a context.
 * Don't instanciate this!
 * 
 * @class
 */
function AttributeUtil () {}

/**
 * Gives an array of all available attributes for a context. This is used in the possibleItems
 * process for the attribute id in AttributeRelation
 * 
 * @param {String} pObjectType the object type (= context)
 * @param {boolean} [pIncludeGroups=false]
 * @param {String[]} [pFilteredAttributeIds=[]] Whitleist of attribute ids
 * 
 * @return {String[]} array of attributeIds
 */
AttributeUtil.getPossibleAttributes = function (pObjectType, pIncludeGroups, pFilteredAttributeIds)
{
    if (pObjectType == null)
        return [];
    
    var attrSql = "select AB_ATTRIBUTEID from AB_ATTRIBUTE"
        + " join AB_ATTRIBUTEUSAGE  on AB_ATTRIBUTEID = AB_ATTRIBUTE_ID";
    attrCond = SqlCondition.begin()
        .andPrepare("AB_ATTRIBUTEUSAGE.OBJECT_TYPE", pObjectType)
        .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.COMBOVALUE, "# <> ?")
        .and("ATTRIBUTE_ACTIVE = 1");
        
    if (pFilteredAttributeIds != undefined && pFilteredAttributeIds.length > 0)
    {
        var filteredIdsCondition = new SqlCondition();

        pFilteredAttributeIds.forEach(function(id) 
        {
            this.orPrepare("AB_ATTRIBUTE.AB_ATTRIBUTEID", id);
        }, filteredIdsCondition);

        attrCond.andSqlCondition(filteredIdsCondition);
    }

//    if (!pIncludeGroups)
//        attrCond.and("ATTRIBUTE_TYPE != '" + $AttributeTypes.GROUP + "'");
    
    var attributes = db.array(db.COLUMN, attrCond.buildSql(attrSql));
    
    return attributes;
}

/**
 * returns the name of an attribute with all parent attribute names
 * 
 * @param {String} pAttributeId the id of the attribute
 * @param {Boolean} [pSimpleName=false] Use only the name of the attribute and not the names of the parents.
 * 
 * @return {String} the name of the attribute
 */
AttributeUtil.getFullAttributeName = function (pAttributeId, pSimpleName) 
{
    if (pSimpleName == undefined)
        pSimpleName = false;
    
    if (!pAttributeId)
        return "";
    var attributeNames = [];
    var attribute;
    var idType = SqlUtils.getSingleColumnType("AB_ATTRIBUTE.AB_ATTRIBUTEID");
    do {
        attribute = db.array(db.ROW, SqlCondition.begin()
            .andPrepare("AB_ATTRIBUTE.AB_ATTRIBUTEID", pAttributeId, "# = ?", idType)
            .buildSql("select ATTRIBUTE_NAME, ATTRIBUTE_PARENT_ID from AB_ATTRIBUTE")
        );
        if (attribute.length > 0)
        {
            attributeNames.push(attribute[0]);
                pAttributeId = attribute[1];
        }
        else
            pAttributeId = "";
    } while (pAttributeId && !pSimpleName);
    
    return attributeNames.reverse().join(" / ");
}

/**
 * returns the name of an attribute
 * 
 * @param {String} pAttributeId the id of the attribute
 * 
 * @return {String} the name of the attribute
 */
AttributeUtil.getSimpleAttributeName = function (pAttributeId) 
{
    var attributeName = db.cell(SqlCondition.begin()
        .andPrepare("AB_ATTRIBUTE.AB_ATTRIBUTEID", pAttributeId)
        .buildSql("select ATTRIBUTE_NAME from AB_ATTRIBUTE")
    );

    return attributeName;
}

/**
 * returns the ids of all subordinated attributes of an attribute
 * 
 * @param {String} pAttributeId the id of the attribute
 * 
 * @result {String[]} array with the ids of every subordinated attribute
 */
AttributeUtil.getAllChildren = function (pAttributeId)
{
    var childIds = [];
    var attributes= [pAttributeId];
    while (attributes.length > 0)
    {
        attributes = db.array(db.COLUMN, SqlCondition.begin()
            .and("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID in ('" + attributes.join("','") + "')")
            .buildSql("select AB_ATTRIBUTEID from AB_ATTRIBUTE")
        );
        if (attributes.length > 0)
            childIds = childIds.concat(attributes);
    }
    return childIds;
}

/**
 * checks if an attribute has attribute relations
 * 
 * @param {String} pAttributeId the id of the attribute
 * 
 * @result {boolean} true if it has relations
 */
AttributeUtil.hasRelations = function (pAttributeId)
{
    if (!pAttributeId)
        return false;
    return db.cell(SqlCondition.begin()
        .andPrepare("AB_ATTRIBUTE.AB_ATTRIBUTEID", pAttributeId)
        .buildSql(
            "select exists ("
            +    "select AB_ATTRIBUTERELATIONID from AB_ATTRIBUTERELATION "
            +    "where AB_ATTRIBUTE_ID = AB_ATTRIBUTEID"
            + ") from AB_ATTRIBUTE", "1=2"
        )
    ) == "true";
}

/*********************************************************************************************************************/

/**
 * Provides functions for the work with attributeRelations, getting the value of an attributeRelation for an object.
 * Don't instanciate this!
 * 
 * @class
 */
function AttributeRelationUtils () {}

/**
 * gets the value of an attributeRelation for one dataset (e. g. a person)
 * 
 * @param {String} pAttributeId attribute-id
 * @param {String} pObjectRowId row-id of the dataset
 * @param {String} [pObjectType=null] object-type
 * 
 * @return {String|null} the value of the attribute
 */
AttributeRelationUtils.getAttribute = function (pAttributeId, pObjectRowId, pObjectType)
{
    var attrCond = SqlCondition.begin()
        .andPrepare("AB_ATTRIBUTERELATION.AB_ATTRIBUTE_ID", pAttributeId)
        .andPrepare("AB_ATTRIBUTERELATION.OBJECT_ROWID", pObjectRowId);
    if (pObjectType != null)
        attrCond.andPrepare("AB_ATTRIBUTERELATION.OBJECT_TYPE", pAttributeId);
    
    var attributeSql = attrCond.buildSql("select ATTRIBUTE_TYPE, " + AttributeTypeUtil.getAllDatabaseFields().join(", ")
        + " from AB_ATTRIBUTERELATION join AB_ATTRIBUTE on AB_ATTRIBUTE_ID = AB_ATTRIBUTEID");
    var attributeValues = db.array(db.ROW, attributeSql);
    if (attributeValues.length == 0)
        return null;
    
    var valueIndex = AttributeTypeUtil.getTypeColumnIndex(attributeValues[0]) + 1;
    return attributeValues[valueIndex];
}

/**
 * gets all attributes for a dataset
 * 
 * @param {String} pObjectRowId object rowid
 * @param {String} [pObjectType=null] object-type
 * @param {String} [pResolveNames=false] if true the full attribute names are used instead of the ids
 * @param {String} [pGetUID=false] include the attributeRelation id
 * 
 * @return {String[][]} two-dimensional array a row is [attributeId|attributeName, value] or if pGetUID is true, [attriuteRelationId, attributeId|attributeName, value]
 */
AttributeRelationUtils.getAllAttributes = function (pObjectRowId, pObjectType, pResolveNames, pGetUID)
{
    var attrCond = SqlCondition.begin()
        .andPrepare("AB_ATTRIBUTERELATION.OBJECT_ROWID", pObjectRowId);
    if (pObjectType != null)
        attrCond.andPrepare("AB_ATTRIBUTERELATION.OBJECT_TYPE", pObjectType);
    
    var attributeSql = attrCond.buildSql("select AB_ATTRIBUTERELATIONID, AB_ATTRIBUTE_ID, AB_ATTRIBUTE.ATTRIBUTE_TYPE, AB_ATTRIBUTE.KEYWORD_CONTAINER, COMBOVAL.ATTRIBUTE_NAME, " 
        + AttributeTypeUtil.getAllDatabaseFields().join(", ")
        + " from AB_ATTRIBUTERELATION join AB_ATTRIBUTE on AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID"
        + " left join AB_ATTRIBUTE COMBOVAL on " + $AttributeTypes.COMBO.databaseField + " = COMBOVAL.AB_ATTRIBUTEID");
    
    var attributeNameMap = {};
    var attributeValues = db.table(attributeSql).map(function (row) 
    {
        let attribute = row[1];
        if (pResolveNames)
        {
            if (!(attribute in attributeNameMap))
                attributeNameMap[attribute] = AttributeUtil.getFullAttributeName(attribute);
            attribute = attributeNameMap[attribute];
        }
        let value;
        if (row[2].trim() == $AttributeTypes.COMBO)
            value = row[4];
        else
        {
            value = row[AttributeTypeUtil.getTypeColumnIndex(row[2]) + 5];
            value = AttributeTypeUtil.getAttributeViewValue(row[2].trim(), value, row[3]);
        }
        if (pGetUID)
            return [row[0], attribute, value];
        return [attribute, value];
    });
    
    return attributeValues;
}

AttributeRelationUtils.getAttributes = function ()
{
    //TODO: implement maybe
}

/**
 * sets the value of an attribute for one dataset (e. g. a person)
 */
AttributeRelationUtils.setAttribute = function ()
{
    //TODO: implement
}

/*********************************************************************************************************************/

/**
 * This is used in the AttributeRelation enitiy to make the work with attributes there
 * easier. You probaly won't need this for anything else.
 * 
 * @param {String} pAttrId the id of the attribute
 * 
 * @class
 */
function AttributeHandler (pAttrId)   //TODO: find out if this class is necessary, maybe there is a more elegant solution, this could also be static
{
    this.attributeId = pAttrId;
    this._attributeType = null;
}

/**
 * Returns a new AttributeHandler for the given Attribute
 */
AttributeHandler.begin = function (pAttrId)
{
    return new AttributeHandler(pAttrId);
}

/**
 * gets the type of the attribute by the attributeId, after the first call the value
 * is stored so that the sql selection is done only once
 * 
 * @return {String} attribute type
 */
AttributeHandler.prototype.getAttributeType = function () //TODO: maybe the type should be an own field in the entity instead of getting the type from the attribute id
{
    if (this._attributeType == null && this.attributeId != null)
    {
        var attrTypeSelect = "select ATTRIBUTE_TYPE from AB_ATTRIBUTE";
        attrTypeSelect = SqlCondition.begin()
            .andPrepare("AB_ATTRIBUTE.AB_ATTRIBUTEID", this.attributeId)
            .buildSql(attrTypeSelect);
        this._attributeType = db.cell(attrTypeSelect).trim();
    }
    return this._attributeType;
}

/**
 * returns the field that belongs to the type of the attribute
 * 
 * @return {String} attribute field
 */
AttributeHandler.prototype.getAttributeField = function ()
{
    return AttributeTypeUtil.getEntityField(this.getAttributeType());
}

/**
 * returns the content type that belongs to the type of the attribute
 * 
 * @return {String} attribute field
 */
AttributeHandler.prototype.getAttributeContentType = function ()
{
    return AttributeTypeUtil.getContentType(this.getAttributeType());
}

/**
 * Sets the value to the AttributeField and also return s the value again.
 * 
 * @param pValue the value
 * 
 * @return {Any} the value
 */
AttributeHandler.prototype.setAttributeValue = function (pValue)
{
    var field = "$field." + this.getAttributeField();
    if (field != null && vars.exists(field))
        neon.setFieldValue(field, pValue)
    return pValue;
}

/**
 * Object for the enumeration and management of all attribute types.
 * This Object is only for the general definition of attribute types and for getting
 * data about every type, anything that has to do with a specific attribute (= the function requires an attribute id)
 * should be done in AttributeUtils.
 * The values for each type are:
 * 
 * keyword = the key of the corresponding keyword
 * contentType = the value that is returned in the contentType process for the attribute
 * databaseField = the database field that holds values of attributes with the type
 * entityField = the field in the AttributeRelation enity that holds the value of the attribute for that type
 * 
 * The display name is controlled by the keyword 'AttributeType'
 */
function $AttributeTypes () {}

$AttributeTypes.TEXT = { 
    toString : function () {return this.keyword},
    keyword : "TEXT",
    contentType : "TEXT", 
    databaseField : "CHAR_VALUE", 
    entityField : "CHAR_VALUE"
};
$AttributeTypes.DATE = {
    toString : function () {return this.keyword},
    keyword : "DATE",
    contentType : "DATE", 
    databaseField : "DATE_VALUE", 
    entityField : "DATE_VALUE",
    getViewValue : function (pValue)
        {
            return datetime.toDate(pValue, translate.text("dd.MM.yyyy"));
        }
};
$AttributeTypes.NUMBER = {
    toString : function () {return this.keyword},
    keyword : "NUMBER",
    contentType : "NUMBER", 
    databaseField : "NUMBER_VALUE", 
    entityField : "NUMBER_VALUE"
};
$AttributeTypes.BOOLEAN = {
    toString : function () {return this.keyword},
    keyword : "BOOLEAN",
    contentType : "BOOLEAN", 
    databaseField : "INT_VALUE", 
    entityField : "INT_VALUE",
    getViewValue : function (pValue)
        {
            return pValue == "1" ? translate.text("Yes") : translate.text("No");
        }
};
$AttributeTypes.COMBO = {
    toString : function () {return this.keyword},
    keyword : "COMBO",
    contentType : "UNKNOWN",
    databaseField : "ID_VALUE", 
    entityField : "ID_VALUE"
};
$AttributeTypes.COMBOVALUE = {
    toString : function () {return this.keyword},
    keyword : "COMBOVALUE",
    contentType : null, 
    databaseField : null, 
    entityField : null
};
$AttributeTypes.GROUP = {
    toString : function () {return this.keyword},
    keyword : "GROUP",
    contentType : null, 
    databaseField : null, 
    entityField : null
};
$AttributeTypes.KEYWORD = {
    toString : function () {return this.keyword},
    keyword : "KEYWORD",
    contentType : "UNKNOWN", 
    databaseField : "ID_VALUE", 
    entityField : "ID_VALUE",
    getViewValue : function (pValue, pKeyword)
        {
            return KeywordUtils.getViewValue(pKeyword, pValue);
        }
};


function AttributeTypeUtil () {}

/**
 * returns the required contentType for the given attribute type
 * 
 * @param {String} pAttributeType the attribute type 
 *                  (use the values of the AttributeTypes object, e. g. AttributeTypes.TEXT)
 * @return {String} the contentType for the attribute
 */
AttributeTypeUtil.getContentType = function (pAttributeType)
{
    if (pAttributeType in $AttributeTypes)
        return $AttributeTypes[pAttributeType].contentType;
    return null;
}

/**
 * returns the entity field for the given attribute type that holds the value of the attribute
 * 
 * @param {String} pAttributeType the attribute type 
 *                  (use the values of the AttributeTypes object, e. g. AttributeTypes.TEXT)
 * @return {String} the field for the attribute
 */
AttributeTypeUtil.getEntityField = function (pAttributeType)
{
    if (pAttributeType in $AttributeTypes)
        return $AttributeTypes[pAttributeType].entityField;
    return null;
}

/**
 * returns the database field for the given attribute type that holds the value of the attribute
 * 
 * @param {String} pAttributeType the attribute type 
 *                  (use the values of the AttributeTypes object, e. g. AttributeTypes.TEXT)
 * @return {String} the database field for the attribute
 */
AttributeTypeUtil.getDatabaseField = function (pAttributeType)
{
    if (pAttributeType in $AttributeTypes)
        return $AttributeTypes[pAttributeType].databaseField;
    return null;
}

AttributeTypeUtil.getAttributeViewValue = function (pAttributeType, pValue, pKeyword)
{
    if (pAttributeType in $AttributeTypes && "getViewValue" in $AttributeTypes[pAttributeType])
        return $AttributeTypes[pAttributeType].getViewValue(pValue, pKeyword);
    return pValue;
}

AttributeTypeUtil._initTypeColumnData = function ()
{
    columns = [];
    typeColumnMap = {};
    for (let type in $AttributeTypes)
    {
        type = $AttributeTypes[type];
        if (type.databaseField)
        {
            var typeKey = type.toString();
            var colIndex = columns.indexOf(type.databaseField);
            if (colIndex == -1)
            {
                colIndex = columns.length;
                columns.push(type.databaseField);
            }
            typeColumnMap[typeKey] = colIndex;
        }
    }
    this._allDBColumns = columns;
    this._typeColumnMap = typeColumnMap;
}

AttributeTypeUtil.getAllDatabaseFields = function ()
{
    if (this._allDBColumns == undefined)
        AttributeTypeUtil._initTypeColumnData();
    return this._allDBColumns;
}

AttributeTypeUtil.getTypeColumnIndex = function (pAttributeType)
{
    if (this._typeColumnMap == undefined)
        AttributeTypeUtil._initTypeColumnData();
    return this._typeColumnMap[pAttributeType.trim()];
}

/*********************************************************************************************************************/

/**
 * Functions for AttributeUsages.
 * Do not instanciate this!
 * 
 * @class
 */
function AttributeUsageUtil () {}

/**
 * Creates AttributeUsages for all subordinate attributes of an attribute.
 * This is required when an usage is added to a superordinate attribute.
 * 
 * @param {String} pAttributeId the id of the superordinate attribute
 * @param {String} pObjectType the context
 */
AttributeUsageUtil.insertChildrenUsages = function (pAttributeId, pObjectType)
{
    var table = "AB_ATTRIBUTEUSAGE";
    var columns = ["AB_ATTRIBUTEUSAGEID", "AB_ATTRIBUTE_ID", "OBJECT_TYPE"];
    var types = db.getColumnTypes(table, columns);
    
    var sqlSelect = "select AB_ATTRIBUTEID, "
            + " exists (select AB_ATTRIBUTEUSAGEID from AB_ATTRIBUTEUSAGE where AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID and OBJECT_TYPE = '" 
            + pObjectType + "') from AB_ATTRIBUTE";
    
    var inserts = [];
    _addInserts(pAttributeId, pObjectType);
    db.inserts(inserts);
    
    function _addInserts (pAttributeId, pObjectType)
    {
        var condition = SqlCondition.begin()
            .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.COMBOVALUE, "# != ?")
            .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID", pAttributeId);
        var attributes = db.table(condition.buildSql(sqlSelect));
        
        attributes.forEach(function (row)
        {
            if (row[1] != "true")
            {
                let values = [util.getNewUUID(), row[0], pObjectType];
                inserts.push([table, columns, types, values]);
            }
            _addInserts(row[0], pObjectType);
        });
    }
}

/**
 * Updates AttributeUsages for all subordinate attributes of an attribute.
 * This is required when an usage of a superordinate attribute is changed.
 * 
 * @param {String} pAttributeId the id of the superordinate attribute
 * @param {String} pOldObjectType ye olde context
 * @param {String} pNewObjectType the new context
 */
AttributeUsageUtil.updateChildrenUsages = function (pAttributeId, pOldObjectType, pNewObjectType)
{
    if (!pNewObjectType)
        return;
    
    var table = "AB_ATTRIBUTEUSAGE";
    
    var sqlSelect = "select AB_ATTRIBUTEID, AB_ATTRIBUTEUSAGEID, "
        + " exists (select AB_ATTRIBUTEUSAGEID from AB_ATTRIBUTEUSAGE where AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID and OBJECT_TYPE = '" 
        + pNewObjectType + "')"
        + " from AB_ATTRIBUTE left join AB_ATTRIBUTEUSAGE on AB_ATTRIBUTEID = AB_ATTRIBUTE_ID and OBJECT_TYPE = '" + pOldObjectType + "'";
    
    var updateCond = SqlCondition.begin();
    
    //it is possible that the new objectType is already in a subordinate attribute 
    //and an update could cause a duplicate entry so one has to be deleted
    var deleteCond = SqlCondition.begin();
    
    _addUpdateIds(pAttributeId, pOldObjectType);
        
    if (updateCond.isSet())
        db.updateData(table, ["OBJECT_TYPE"], null, [pNewObjectType], updateCond.build("1=2"));
    if (deleteCond.isSet())
        db.deleteData(table, deleteCond.build("1=2"));
    
    function _addUpdateIds (pAttributeId)
    {
        var condition = SqlCondition.begin()
            .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.COMBOVALUE, "# != ?")
            .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID", pAttributeId);
        var attributes = db.table(condition.buildSql(sqlSelect));
        
        attributes.forEach(function (row)
        {
            if (row[1] && row[2] == "true")
                deleteCond.orPrepare("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTEUSAGEID", row[1]);
            else if (row[1])
                updateCond.orPrepare("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTEUSAGEID", row[1]);
            _addUpdateIds(row[0]);
        });
    }
}

/**
 * Deletes AttributeUsages for all subordinate attributes of an attribute.
 * This is required when an usage is removed from a superordinate attribute.
 * 
 * @param {String} pAttributeId the id of the superordinate attribute
 * @param {String} pObjectType the context
 */
AttributeUsageUtil.deleteChildrenUsages = function (pAttributeId, pObjectType)
{
    var table = "AB_ATTRIBUTEUSAGE";
    
    var sqlSelect = "select AB_ATTRIBUTEID, AB_ATTRIBUTEUSAGEID "
        + " from AB_ATTRIBUTE left join AB_ATTRIBUTEUSAGE on AB_ATTRIBUTEID = AB_ATTRIBUTE_ID and OBJECT_TYPE = '" + pObjectType + "'";
    
    var deleteCond = SqlCondition.begin();
    _addDeleteIds(pAttributeId, pObjectType);
    if (deleteCond.isSet())
        db.deleteData(table, deleteCond.build("1=2"));
    
    function _addDeleteIds (pAttributeId)
    {
        var condition = SqlCondition.begin()
            .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.COMBOVALUE, "# != ?")
            .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID", pAttributeId);
        var attributes = db.table(condition.buildSql(sqlSelect));
        
        attributes.forEach(function (row)
        {
            if (row[1])
                deleteCond.orPrepare("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTEUSAGEID", row[1])
            _addDeleteIds(row[0]);
        });
    }
}

/**
 * Deletes duplicate attribute usages.
 * 
 * @param {String} [pAttributeId=null] attribute id, if omitted, all duplicates will be deleted 
 */
AttributeUsageUtil.removeDuplicates = function (pAttributeId)
{
    var condition = SqlCondition.begin()
        .and("exists (select AB_ATTRIBUTEUSAGEID from AB_ATTRIBUTEUSAGE AU where AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AU.AB_ATTRIBUTE_ID "
            + "and AB_ATTRIBUTEUSAGE.OBJECT_TYPE = AU.OBJECT_TYPE and AB_ATTRIBUTEUSAGE.AB_ATTRIBUTEUSAGEID != AU.AB_ATTRIBUTEUSAGEID)");
    if (pAttributeId)
        condition.andPrepare("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID", pAttributeId);
    
    var duplicates = db.table(condition.buildSql("select AB_ATTRIBUTEUSAGEID, AB_ATTRIBUTE_ID, OBJECT_TYPE from AB_ATTRIBUTEUSAGE"));
    var usageObj = {};
    var deleteCond = SqlCondition.begin();
    
    duplicates.forEach(function (row)
    {
        if (!(row[1] in this))
            this[row[1]] = {};
        if (row[2] in this[row[1]])
            deleteCond.orPrepare("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTEUSAGEID", row[0]);
        this[row[1]][row[2]] = true;
    }, usageObj);
    if (deleteCond.isSet())
        db.deleteData("AB_ATTRIBUTEUSAGE", deleteCond.build("1=2"));
}