import("system.translate"); import("system.util"); import("Util_lib"); import("system.vars"); import("system.result"); import("system.db"); import("Attribute_lib"); import("Sql_lib"); var idvalues = vars.exists("$local.idvalues") ? vars.get("$local.idvalues") : null; var getTree = !idvalues && vars.getString("$param.GetTree_param") == "true"; var loadFullAttributeName = vars.getString("$param.DisplaySimpleName_param") != "true"; var typeWhitelist, typeBlacklist; if (vars.getString("$param.GetTheme_param") == "true") typeWhitelist = [$AttributeTypes.THEME.toString()]; else typeBlacklist = [$AttributeTypes.THEME.toString()]; var loadEmptyAttributes = vars.getString("$param.ShowEmpty_param") == "true"; var filteredAttributeIds = vars.exists("$param.FilteredAttributeIds_param") && vars.get("$param.FilteredAttributeIds_param"); if (filteredAttributeIds) filteredAttributeIds = JSON.parse(filteredAttributeIds); var objectRowId = vars.get("$param.ObjectRowId_param"); var objectType = vars.get("$param.ObjectType_param"); var attributeQueryMaker = { defaultQueryFields : [ "AB_ATTRIBUTERELATIONID", "AB_ATTRIBUTE.AB_ATTRIBUTEID", "AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID", "AB_ATTRIBUTE.ATTRIBUTE_TYPE", "AB_ATTRIBUTE.ATTRIBUTE_NAME", "AB_ATTRIBUTE.DROPDOWNDEFINITION", "COMBOVAL.ATTRIBUTE_NAME", "AB_ATTRIBUTERELATION.DATE_NEW", "AB_ATTRIBUTERELATION.USER_NEW", "AB_ATTRIBUTERELATION.DATE_EDIT", "AB_ATTRIBUTERELATION.USER_EDIT", "AB_ATTRIBUTE.DROPDOWNFILTER" ], valueQueryFields : AttributeTypeUtil.getAllDatabaseFields(), getConditionForIdValues : function (pIdValues, pLoadEmptyAttributes) { var idCondition = newWhere(); if (pLoadEmptyAttributes) { pIdValues.forEach(function (id) { var [attributeRelationId, attributeId] = JSON.parse(id); idCondition.or("AB_ATTRIBUTERELATION.AB_ATTRIBUTERELATIONID", attributeRelationId); idCondition.or(newWhere("AB_ATTRIBUTERELATION.AB_ATTRIBUTERELATIONID is null") .and("AB_ATTRIBUTE.AB_ATTRIBUTEID", attributeId)); }); } else idCondition.andIfSet("AB_ATTRIBUTERELATION.AB_ATTRIBUTERELATIONID", pIdValues, SqlBuilder.IN()); return idCondition; }, getConditionForLinkedObject : function (pObjectType, pLoadEmptyAttributes, pAttributeIds, pTypeBlacklist, pTypeWhitelist) { var attributeCondition = newWhereIfSet("AB_ATTRIBUTE.ATTRIBUTE_TYPE", pTypeBlacklist, SqlBuilder.NOT_IN()); attributeCondition.andIfSet("AB_ATTRIBUTE.ATTRIBUTE_TYPE", pTypeWhitelist, SqlBuilder.IN()); if (pLoadEmptyAttributes) attributeCondition.andIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", AttributeUtil.getPossibleAttributes(pObjectType), SqlBuilder.IN()); if (pAttributeIds) { let attributeChildren = AttributeUtil.getAllChildren(pAttributeIds); let attributeIdCondition = newWhere(); if (attributeChildren.length > 0) { attributeIdCondition.and("AB_ATTRIBUTE.AB_ATTRIBUTEID", attributeChildren, SqlBuilder.IN()) attributeIdCondition.and("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.COMBOVALUE, SqlBuilder.NOT_EQUAL()); } // return nothing if filteredAttributeIds is an empty array. (--> and 1=2) if (!attributeIdCondition.hasCondition()) return null; attributeCondition.and(attributeIdCondition); } return attributeCondition; }, getAttributeQuery : function (pIdValues, pObjectRowId, pObjectType, pLoadEmptyAttributes, pAttributeIds, pTypeBlacklist, pTypeWhitelist) { var attributeQuery = newSelect(this.defaultQueryFields.concat(this.valueQueryFields)) .from("AB_ATTRIBUTE") .orderBy("AB_ATTRIBUTE.SORTING asc"); if (pIdValues) attributeQuery.where(this.getConditionForIdValues(pIdValues, pLoadEmptyAttributes)); else if (pObjectRowId) { let condition = this.getConditionForLinkedObject(pObjectType, pLoadEmptyAttributes, pAttributeIds, pTypeBlacklist, pTypeWhitelist); if (condition === null) return null; attributeQuery.where(condition); } var attributeRelationCond = newWhere("AB_ATTRIBUTERELATION.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID"); //condition for the joined values (for AttributeRelation) if (!pIdValues && pObjectRowId) { attributeRelationCond.and("AB_ATTRIBUTERELATION.OBJECT_ROWID", pObjectRowId); attributeRelationCond.andIfSet("AB_ATTRIBUTERELATION.OBJECT_TYPE", pObjectType); } if (pLoadEmptyAttributes) attributeQuery.leftJoin("AB_ATTRIBUTERELATION", attributeRelationCond); else attributeQuery.join("AB_ATTRIBUTERELATION", attributeRelationCond); attributeQuery.leftJoin("AB_ATTRIBUTE", "COMBOVAL.AB_ATTRIBUTEID = " + $AttributeTypes.COMBO.databaseField, "COMBOVAL"); return attributeQuery; } } var attributeQuery = attributeQueryMaker.getAttributeQuery(idvalues, objectRowId, objectType, loadEmptyAttributes, filteredAttributeIds, typeBlacklist, typeWhitelist); var attributeRelations = attributeQuery != null ? attributeQuery.table(false) : []; //Builds an object containing the minimal counts of the attributes, this is required for //checking if an attribute is used not often enough or just often enough. When this is the case, //deletion of this attributeRelation will be prohibited. var minCountInsurance = { minCounts : {}, usageCounts : {}, loadMinCounts : function (pObjectType) { var minUsages = newSelect("AB_ATTRIBUTE_ID, MIN_COUNT") .from("AB_ATTRIBUTEUSAGE") .whereIfSet("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID", Object.keys(this.usageCounts), SqlBuilder.IN()) .and("AB_ATTRIBUTEUSAGE.OBJECT_TYPE", pObjectType) .table(true); minUsages.forEach(function ([attributeId, minCount]) { this.minCounts[attributeId] = minCount; }, this); }, incrUsageCount : function (pAttributeId) { if (pAttributeId in this.usageCounts) this.usageCounts[pAttributeId]++; else this.usageCounts[pAttributeId] = 1; }, attributeNotDeletable : function (pAttributeId) { return this.minCounts[pAttributeId] >= this.usageCounts[pAttributeId]; } }; attributeRelations = attributeRelations.map(function (row) { var [attrRelId, attrId, attrParentId, attrType, attrName, dropDownDef, comboViewVal, dateNew, userNew, dateEdit, userEdit, dropDownFilter] = row; attrName = translate.text(attrName); attrType = attrType.trim(); if (!getTree && loadFullAttributeName && attrParentId) { let parentName = AttributeUtil.getFullAttributeName(attrParentId); attrName = (parentName ? parentName + " / " : "") + attrName; } var value = row[AttributeTypeUtil.getTypeColumnIndex(attrType) + attributeQueryMaker.defaultQueryFields.length]; var viewValue; if (attrType == $AttributeTypes.COMBO) viewValue = translate.text(comboViewVal); else viewValue = AttributeTypeUtil.getAttributeViewValue(attrType, value, dropDownDef); minCountInsurance.incrUsageCount(attrId); //if loadEmptyAttributes is true, the id is contains the attributeRelation id and the attribute id. //in case there is no attributeRelation, a random id is used return [ loadEmptyAttributes ? JSON.stringify([attrRelId || util.getNewUUID(), attrId]) : attrRelId, attrRelId, attrParentId, value, viewValue, attrId, attrName, "", //protected attrType.trim(), dateNew, userNew, dateEdit, userEdit, value, viewValue, dropDownDef, dropDownFilter ]; }); minCountInsurance.loadMinCounts(objectType); attributeRelations.forEach(function (attributeRelation) { var attrId = attributeRelation[4]; if (minCountInsurance.attributeNotDeletable(attrId)) attributeRelation[7] = "true"; }); if (getTree) attributeRelations = _buildAttributeTree(attributeRelations); result.object(attributeRelations); /* * loads the parents for a tree */ function _buildAttributeTree (pAttrRelations) { //object of attribute ids to avoid duplicates (more than one attribute can have the same parent) var attrCatalog = {}; var parentAttributes = []; _fetchParentAttributes(pAttrRelations.map(function (row) {return row[2]}), parentAttributes); return TreeUtils.sortArrayForTree(parentAttributes, 0, 2).concat(pAttrRelations); /* * recursive function that loads all superordinate attributes for the tree */ function _fetchParentAttributes (pAttributeIds, pParentAttributes) { var attributeCond = newSelect("AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME") .from("AB_ATTRIBUTE") .where() var nextIds = []; pAttributeIds.forEach(function (id) { if (!(id in this)) attributeCond.orIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", id); }, attrCatalog); attributeCond.table(true) .forEach(function ([attrId, parentId, attrName]) { this[attrId] = true; //make entry in attrCatalog to avoid duplicates if (parentId) nextIds.push(parentId); pParentAttributes.push([ attrId, "", parentId, "", "", "", //0-5 translate.text(attrName), //translate attribute name "true", //7 "", "", "", "", "", "", "", "", "" //8-16 ]); }, attrCatalog); if (nextIds.length) _fetchParentAttributes(nextIds, pParentAttributes); } }