From 183d770483f073a8b4c3e11027cf3c6b1597d7d5 Mon Sep 17 00:00:00 2001 From: Joan Sanchez Date: Tue, 1 Oct 2019 15:09:55 +0200 Subject: [PATCH] first changes --- db/changes/10091-iberflora/00-department.sql | 73 +++++++++++++++ .../00-department_calcTree.sql | 37 ++++++++ .../00-department_calcTreeRec.sql | 75 ++++++++++++++++ .../10091-iberflora/00-department_doCalc.sql | 35 ++++++++ .../00-department_getLeaves.sql | 84 +++++++++++++++++ front/core/components/treeview/child.html | 13 +-- front/core/components/treeview/child.js | 12 ++- front/core/components/treeview/index.js | 15 +++- .../back/methods/department/getLeaves.js | 89 ++++++------------- modules/worker/front/department/index.html | 21 ++--- modules/worker/front/department/index.js | 1 - 11 files changed, 372 insertions(+), 83 deletions(-) create mode 100644 db/changes/10091-iberflora/00-department.sql create mode 100644 db/changes/10091-iberflora/00-department_calcTree.sql create mode 100644 db/changes/10091-iberflora/00-department_calcTreeRec.sql create mode 100644 db/changes/10091-iberflora/00-department_doCalc.sql create mode 100644 db/changes/10091-iberflora/00-department_getLeaves.sql diff --git a/db/changes/10091-iberflora/00-department.sql b/db/changes/10091-iberflora/00-department.sql new file mode 100644 index 000000000..f1d1776e9 --- /dev/null +++ b/db/changes/10091-iberflora/00-department.sql @@ -0,0 +1,73 @@ +ALTER TABLE `vn2008`.`department` +ADD COLUMN `parentFk` INT UNSIGNED NULL AFTER `sons`, +ADD COLUMN `path` VARCHAR(255) NULL AFTER `parentFk`, +CHANGE COLUMN `sons` `sons` DECIMAL(10,0) NOT NULL DEFAULT '0' ; + +USE `vn`; +CREATE + OR REPLACE ALGORITHM = UNDEFINED + DEFINER = `root`@`%` + SQL SECURITY DEFINER +VIEW `department` AS + SELECT + `b`.`department_id` AS `id`, + `b`.`name` AS `name`, + `b`.`production` AS `isProduction`, + `b`.`parentFk` AS `parentFk`, + `b`.`path` AS `path`, + `b`.`lft` AS `lft`, + `b`.`rgt` AS `rgt`, + `b`.`isSelected` AS `isSelected`, + `b`.`depth` AS `depth`, + `b`.`sons` AS `sons` + FROM + `vn2008`.`department` `b`; + +DROP TRIGGER IF EXISTS `vn2008`.`department_AFTER_DELETE`; + +DELIMITER $$ +USE `vn2008`$$ +CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_AFTER_DELETE` + AFTER DELETE ON `department` FOR EACH ROW +BEGIN + UPDATE vn.department_recalc SET isChanged = TRUE; +END$$ +DELIMITER ; + +DROP TRIGGER IF EXISTS `vn2008`.`department_BEFORE_INSERT`; + +DELIMITER $$ +USE `vn2008`$$ +CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_BEFORE_INSERT` + BEFORE INSERT ON `department` FOR EACH ROW +BEGIN + UPDATE vn.department_recalc SET isChanged = TRUE; +END$$ +DELIMITER ; + +DROP TRIGGER IF EXISTS `vn2008`.`department_AFTER_UPDATE`; + +DELIMITER $$ +USE `vn2008`$$ +CREATE DEFINER = CURRENT_USER TRIGGER `vn2008`.`department_AFTER_UPDATE` + AFTER UPDATE ON `department` FOR EACH ROW +BEGIN + IF !(OLD.parentFk <=> NEW.parentFk) THEN + UPDATE vn.department_recalc SET isChanged = TRUE; + END IF; +END$$ +DELIMITER ; + +CREATE TABLE `vn`.`department_recalc` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `isChanged` TINYINT(4) NOT NULL, + PRIMARY KEY (`id`)); + +INSERT INTO `vn`.`department_recalc` (`id`, `isChanged`) VALUES ('1', '0'); + + +ALTER TABLE `vn2008`.`department` +CHANGE COLUMN `lft` `lft` INT(11) NULL , +CHANGE COLUMN `rgt` `rgt` INT(11) NULL ; + +UPDATE vn.department SET lft = NULL, rgt = NULL; diff --git a/db/changes/10091-iberflora/00-department_calcTree.sql b/db/changes/10091-iberflora/00-department_calcTree.sql new file mode 100644 index 000000000..5f518d2e2 --- /dev/null +++ b/db/changes/10091-iberflora/00-department_calcTree.sql @@ -0,0 +1,37 @@ +USE `vn`; +DROP procedure IF EXISTS `department_calcTree`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `department_calcTree`() +BEGIN +/** + * Calculates the #path, #lft, #rgt, #sons and #depth columns of + * the #department table. To build the tree, it uses the #parentFk + * column. + */ + DECLARE vIndex INT DEFAULT 0; + DECLARE vSons INT; + + DROP TEMPORARY TABLE IF EXISTS tNestedTree; + CREATE TEMPORARY TABLE tNestedTree + SELECT id, path, lft, rgt, depth, sons + FROM department LIMIT 0; + + SET max_sp_recursion_depth = 5; + CALL department_calcTreeRec(NULL, '/', 0, vIndex, vSons); + SET max_sp_recursion_depth = 0; + + UPDATE department z + JOIN tNestedTree t ON t.id = z.id + SET z.path = t.path, + z.lft = t.lft, + z.rgt = t.rgt, + z.depth = t.depth, + z.sons = t.sons; + + DROP TEMPORARY TABLE tNestedTree; +END$$ + +DELIMITER ; + diff --git a/db/changes/10091-iberflora/00-department_calcTreeRec.sql b/db/changes/10091-iberflora/00-department_calcTreeRec.sql new file mode 100644 index 000000000..1f24270e2 --- /dev/null +++ b/db/changes/10091-iberflora/00-department_calcTreeRec.sql @@ -0,0 +1,75 @@ +USE `vn`; +DROP procedure IF EXISTS `department_calcTreeRec`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `department_calcTreeRec`( + vSelf INT, + vPath VARCHAR(255), + vDepth INT, + INOUT vIndex INT, + OUT vSons INT +) +BEGIN +/** + * Calculates and sets the #path, #lft, #rgt, #sons and #depth + * columns for all children of the passed node. Once calculated + * the last node rgt index and the number of sons are returned. + * To update it's children, this procedure calls itself recursively + * for each one. + * + * @vSelf The node identifier + * @vPath The initial path + * @vDepth The initial depth + * @vIndex The initial lft index + * @vSons The number of direct sons + */ + DECLARE vChildFk INT; + DECLARE vLft INT; + DECLARE vMySons INT; + DECLARE vDone BOOL; + DECLARE vChildren CURSOR FOR + SELECT id FROM department + WHERE (vSelf IS NULL AND parentFk IS NULL) + OR (vSelf IS NOT NULL AND parentFk = vSelf); + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; + + SET vSons = 0; + + OPEN vChildren; + myLoop: LOOP + SET vDone = FALSE; + FETCH vChildren INTO vChildFk; + + IF vDone THEN + LEAVE myLoop; + END IF; + + SET vIndex = vIndex + 1; + SET vLft = vIndex; + SET vSons = vSons + 1; + + CALL department_calcTreeRec( + vChildFk, + CONCAT(vPath, vChildFk, '/'), + vDepth + 1, + vIndex, + vMySons + ); + + SET vIndex = vIndex + 1; + + INSERT INTO tNestedTree + SET id = vChildFk, + path = vPath, + lft = vLft, + rgt = vIndex, + depth = vDepth, + sons = vMySons; + END LOOP; + CLOSE vChildren; +END$$ + +DELIMITER ; + diff --git a/db/changes/10091-iberflora/00-department_doCalc.sql b/db/changes/10091-iberflora/00-department_doCalc.sql new file mode 100644 index 000000000..ba5c16c48 --- /dev/null +++ b/db/changes/10091-iberflora/00-department_doCalc.sql @@ -0,0 +1,35 @@ +USE `vn`; +DROP procedure IF EXISTS `department_doCalc`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `department_doCalc`() +proc: BEGIN +/** + * Recalculates the department tree. + */ + DECLARE vIsChanged BOOL; + + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION + BEGIN + DO RELEASE_LOCK('vn.department_doCalc'); + RESIGNAL; + END; + + IF !GET_LOCK('vn.department_doCalc', 0) THEN + LEAVE proc; + END IF; + + SELECT isChanged INTO vIsChanged + FROM department_recalc; + + IF vIsChanged THEN + UPDATE department_recalc SET isChanged = FALSE; + CALL vn.department_calcTree; + END IF; + + DO RELEASE_LOCK('vn.department_doCalc'); +END$$ + +DELIMITER ; + diff --git a/db/changes/10091-iberflora/00-department_getLeaves.sql b/db/changes/10091-iberflora/00-department_getLeaves.sql new file mode 100644 index 000000000..436f67dbf --- /dev/null +++ b/db/changes/10091-iberflora/00-department_getLeaves.sql @@ -0,0 +1,84 @@ +USE `vn`; +DROP procedure IF EXISTS `department_getLeaves`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `department_getLeaves`( + vParentFk INT, + vSearch VARCHAR(255) +) +BEGIN + DECLARE vIsNumber BOOL; + DECLARE vIsSearch BOOL DEFAULT vSearch IS NOT NULL AND vSearch != ''; + + DROP TEMPORARY TABLE IF EXISTS tNodes; + CREATE TEMPORARY TABLE tNodes + (UNIQUE (id)) + ENGINE = MEMORY + SELECT id FROM department LIMIT 0; + + IF vIsSearch THEN + SET vIsNumber = vSearch REGEXP '^[0-9]+$'; + + INSERT INTO tNodes + SELECT id FROM department + WHERE (vIsNumber AND `name` = vSearch) + OR (!vIsNumber AND `name` LIKE CONCAT('%', vSearch, '%')) + LIMIT 1000; + END IF; + + IF vParentFk IS NULL THEN + DROP TEMPORARY TABLE IF EXISTS tChilds; + CREATE TEMPORARY TABLE tChilds + ENGINE = MEMORY + SELECT id FROM tNodes; + + DROP TEMPORARY TABLE IF EXISTS tParents; + CREATE TEMPORARY TABLE tParents + ENGINE = MEMORY + SELECT id FROM department LIMIT 0; + + myLoop: LOOP + DELETE FROM tParents; + INSERT INTO tParents + SELECT parentFk id + FROM department g + JOIN tChilds c ON c.id = g.id + WHERE g.parentFk IS NOT NULL; + + INSERT IGNORE INTO tNodes + SELECT id FROM tParents; + + IF ROW_COUNT() = 0 THEN + LEAVE myLoop; + END IF; + + DELETE FROM tChilds; + INSERT INTO tChilds + SELECT id FROM tParents; + END LOOP; + + DROP TEMPORARY TABLE + tChilds, + tParents; + END IF; + + IF !vIsSearch THEN + INSERT IGNORE INTO tNodes + SELECT id FROM department + WHERE parentFk <=> vParentFk; + END IF; + + SELECT d.id, + d.`name`, + d.parentFk, + d.sons + FROM department d + JOIN tNodes n ON n.id = d.id + ORDER BY depth, `name`; + + DROP TEMPORARY TABLE tNodes; +END$$ + +DELIMITER ; + diff --git a/front/core/components/treeview/child.html b/front/core/components/treeview/child.html index bb0bcb569..2cf930f3d 100644 --- a/front/core/components/treeview/child.html +++ b/front/core/components/treeview/child.html @@ -14,7 +14,8 @@ icon="keyboard_arrow_down" translate-attr="{title: 'Toggle'}"> - + - - + --> -
  • -
  • + --> \ No newline at end of file diff --git a/front/core/components/treeview/child.js b/front/core/components/treeview/child.js index 4441963f0..b1d377a83 100644 --- a/front/core/components/treeview/child.js +++ b/front/core/components/treeview/child.js @@ -2,9 +2,14 @@ import ngModule from '../../module'; import Component from '../../lib/component'; class Controller extends Component { - constructor($element, $scope) { + constructor($element, $scope, $transclude) { super($element, $scope); this.$scope = $scope; + this.$transclude = $transclude; + + $transclude($scope.$parent, tClone => { + this.element.querySelector('.tplItem').appendChild(tClone[0]); + }, null, 'tplItem'); } toggle(event, item) { @@ -35,6 +40,8 @@ class Controller extends Component { } } +Controller.$inject = ['$element', '$scope', '$transclude']; + ngModule.component('vnTreeviewChild', { template: require('./child.html'), controller: Controller, @@ -50,6 +57,9 @@ ngModule.component('vnTreeviewChild', { aclRole: ' { + this.element.querySelector('vn-treeview-child').appendChild(tClone[0]); + // Object.assign(scope, option); + // li.appendChild(clone[0]); + // this.scopes[i] = scope; + }, null, 'tplItem'); } $onInit() { @@ -76,7 +84,7 @@ export default class Treeview extends Component { } } -Treeview.$inject = ['$element', '$scope']; +Treeview.$inject = ['$element', '$scope', '$transclude']; ngModule.component('vnTreeview', { template: require('./index.html'), @@ -90,5 +98,8 @@ ngModule.component('vnTreeview', { draggable: ' { Self.remoteMethod('getLeaves', { - description: 'Returns the first shipped and landed possible for params', + description: 'Returns the nodes for a department', accepts: [{ arg: 'parentFk', type: 'Number', - default: 1, - required: false, - }, - { - arg: 'filter', - type: 'Object', - description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', - http: {source: 'query'} + description: 'Get the children of the specified father', + }, { + arg: 'search', + type: 'String', + description: 'Filter nodes whose name starts with', }], returns: { type: ['object'], @@ -26,61 +20,30 @@ module.exports = Self => { } }); - Self.getLeaves = async(parentFk = 1, filter) => { - let conn = Self.dataSource.connector; - let stmt = new ParameterizedSQL( - `SELECT - child.id, - child.name, - child.lft, - child.rgt, - child.depth, - child.sons - FROM department parent - JOIN department child ON child.lft > parent.lft - AND child.rgt < parent.rgt - AND child.depth = parent.depth + 1 - WHERE parent.id = ?`, [parentFk]); + Self.getLeaves = async(parentFk = null, search) => { + let [res] = await Self.rawSql( + `CALL department_getLeaves(?, ?)`, + [parentFk, search] + ); - // Get nodes from depth greather than Origin - stmt.merge(conn.makeSuffix(filter)); - - const nodes = await Self.rawStmt(stmt); - - if (nodes.length == 0) - return nodes; - - // Get parent nodes - const minorDepth = nodes.reduce((a, b) => { - return b < a ? b : a; - }).depth; - - const parentNodes = nodes.filter(element => { - return element.depth === minorDepth; - }); - const leaves = Object.assign([], parentNodes); - - nestLeaves(leaves); - - function nestLeaves(elements) { - elements.forEach(element => { - let childs = Object.assign([], getLeaves(element)); - if (childs.length > 0) { - element.childs = childs; - nestLeaves(element.childs); - } - }); + let map = new Map(); + for (let node of res) { + if (!map.has(node.parentFk)) + map.set(node.parentFk, []); + map.get(node.parentFk).push(node); } - function getLeaves(parent) { - let elements = nodes.filter(element => { - return element.lft > parent.lft && element.rgt < parent.rgt - && element.depth === parent.depth + 1; - }); - - return elements; + function setLeaves(nodes) { + if (!nodes) return; + for (let node of nodes) { + node.childs = map.get(node.id); + setLeaves(node.childs); + } } - return leaves; + let leaves = map.get(parentFk); + setLeaves(leaves); + + return leaves || []; }; }; diff --git a/modules/worker/front/department/index.html b/modules/worker/front/department/index.html index 6cf2cd063..dfdb9bcfc 100644 --- a/modules/worker/front/department/index.html +++ b/modules/worker/front/department/index.html @@ -1,25 +1,26 @@ - -
    -
    +
    + + icons="$ctrl.icons"> + + test + -
    - - + + + + +