Something went wrong on our end
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"));
}