import("system.logging"); import("Context_lib"); import("system.translate"); import("Util_lib"); import("JditoFilter_lib"); import("KeywordRegistry_basic"); import("Keyword_lib"); import("system.db"); import("system.vars"); import("system.result"); import("Sql_lib"); import("Attribute_lib"); var childId = vars.get("$param.ChildId_param"); var childType = vars.get("$param.ChildType_param"); var objectType = vars.get("$param.ObjectType_param"); var filteredIds = vars.get("$param.FilteredAttributeIds_param") ? JSON.parse(vars.getString("$param.FilteredAttributeIds_param")) : null var attributeCountObj = vars.get("$param.AttributeCount_param") ? JSON.parse(vars.getString("$param.AttributeCount_param")) : null; var displaySimpleName = Utils.toBoolean(vars.get("$param.DisplaySimpleName_param")); var themeObjectRowId = vars.get("$param.ThemeObjectRowId_param"); var parentId = vars.get("$param.ParentId_param"); var includeParentRecord = Utils.toBoolean(vars.get("$param.IncludeParentRecord_param")); var onlyFirstLevelChildren = Utils.toBoolean(vars.get("$param.GetOnlyFirstLevelChildren_param")); var fetchUsages = false; var translateName = false; var condition = newWhere(); if (vars.exists("$local.idvalues") && vars.get("$local.idvalues")) { condition.andIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", vars.get("$local.idvalues"), SqlBuilder.IN()); fetchUsages = true; } else if (childId) //if a childId is given, it is the lookup for selecting the superordinate attribute { condition.and("AB_ATTRIBUTE.ATTRIBUTE_TYPE", AttributeTypeUtil.getGroupTypes(childType), SqlBuilder.IN()); //filter out the child and all children of the child, because an attribute can't have itself or a subordinate attribute as parent condition.andIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", [childId].concat(AttributeUtil.getAllChildren(childId)), SqlBuilder.NOT_IN()); } else if (objectType) //if there's an objectType, it comes from the AttributeRelation entity (lookup for the attribute selection) { translateName = true; var ids = AttributeUtil.getPossibleAttributes(objectType, true, filteredIds, attributeCountObj); if (Utils.isEmpty(ids)) condition.noResult(); else condition.and("AB_ATTRIBUTE.AB_ATTRIBUTEID", ids, SqlBuilder.IN()) .and("AB_ATTRIBUTE.ATTRIBUTE_TYPE", AttributeTypes.THEME(), !themeObjectRowId ? SqlBuilder.NOT_EQUAL() : undefined); } else if (parentId) { if (onlyFirstLevelChildren) condition.and("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID", parentId); else { condition.andIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", AttributeUtil.getAllChildren(parentId), SqlBuilder.IN()); translateName = true; if(includeParentRecord) condition.or("AB_ATTRIBUTE.AB_ATTRIBUTEID", parentId); } } else { fetchUsages = true; } var filterCondition = new FilterSqlTranslator(vars.get("$local.filter"), "AB_ATTRIBUTE") .addSpecialFieldConditionFn("USAGE_FILTER", function (pValue, pOperator) { var cond = newWhere(); var subSelect = newSelect("1").from("AB_ATTRIBUTEUSAGE", "attrUse").where("attrUse.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID"); switch (pOperator) { case "EQUAL": case "NOT_EQUAL": subSelect.and(["AB_ATTRIBUTEUSAGE", "OBJECT_TYPE", "attrUse"], pValue); case "ISNULL": case "ISNOTNULL": return cond.and(null, subSelect, pOperator == "NOT_EQUAL" || pOperator == "ISNULL" ? SqlBuilder.NOT_EXISTS() : SqlBuilder.EXISTS()); } return cond; }) .getSqlCondition(); condition.andIfSet(filterCondition); var usages; if (fetchUsages) //this query is only necessary in Attribute, not in AttributeRelation { var usageTbl = newSelect("AB_ATTRIBUTE_ID, OBJECT_TYPE") .from("AB_ATTRIBUTEUSAGE") .join("AB_ATTRIBUTE", "AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID") .whereIfSet(condition) .table(); usages = {}; for (let i = 0, l = usageTbl.length; i < l; i++) { let attrId = usageTbl[i][0]; if (attrId in usages) usages[attrId].push(usageTbl[i][1]); else usages[attrId] = [usageTbl[i][1]]; } } var attributes = newSelect(["AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME, ATTRIBUTE_ACTIVE, DROPDOWNDEFINITION, DROPDOWNFILTER, SORTING, ATTRIBUTE_TYPE", KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.attributeType(), "ATTRIBUTE_TYPE"), //3 "'', '', ''"]) .from("AB_ATTRIBUTE") .whereIfSet(condition) .orderBy("ATTRIBUTE_PARENT_ID, SORTING, ATTRIBUTE_NAME") .table(); var allNames = newSelect("AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME") .from("AB_ATTRIBUTE") .table(Utils.isEmpty(attributes)); var attrNameData = {}; for (let i = 0, l = allNames.length; i < l; i++) { attrNameData[allNames[i][0]] = [ allNames[i][1], translateName ? translate.text(allNames[i][2]) : allNames[i][2] ]; } var nameCache = {}; var res = _buildAttributeTable(attributes, usages); logging.log(JSON.stringify(res)); result.object(res); //sorts the records in a way that a tree can be built and adds values function _buildAttributeTable (pAttributes, pUsages) { var rows = {}; var allIds = {}; //fills the allIds object, the object is used for checking if a parent exists in the array for (let i = 0, l = pAttributes.length; i < l; i++) allIds[pAttributes[i][0]] = true; var arrayIndex = 0; do { var oldIndex = arrayIndex; pAttributes.forEach(function (row) { //item will be added if the id is not already in the object and //the parent is already added (or the parent is not in the array) if (!(row[0] in this) && (row[1] in this || !allIds[row[1]])) this[row[0]] = { data : row, index : arrayIndex++ }; }, rows); } while (oldIndex != arrayIndex); //stops the loop when no new items were added so that recursive relations between attributes don't cause an infinite loop var sortedArray = new Array(Object.keys(rows).length); for (let i in rows) { let rowData = rows[i].data; if (pUsages && rowData[7].trim() != AttributeTypes.COMBOVALUE() && i in pUsages) { rowData[9] = pUsages[i].map(function (usage) { return ContextUtils.getTitle(usage, true); }).join(", "); } rowData[10] = _getFullName(rowData[1]); //parent full name rowData[11] = _getFullName(rowData[0], displaySimpleName); rowData[12] = "dummy"; rowData[13] = false; sortedArray[rows[i].index] = rowData; } return sortedArray; /** * builds the full attribute name from the pre-loaded parent names and adds all parent names * if required */ function _getFullName (pAttributeId, pSimpleName) { if (!pAttributeId) return ""; var attrId = pAttributeId; var fullName = []; while (attrId) { let name = null; if (attrId in nameCache) { name = nameCache[attrId]; attrId = null; } else if (attrId in attrNameData) { name = attrNameData[attrId][1]; attrId = attrNameData[attrId][0]; //next parent } else attrId = null; if (name) fullName.unshift(name); if (pSimpleName) break; } fullName = fullName.join(" / "); nameCache[pAttributeId] = fullName; return fullName; } }