树结构的转换

时间:2015-05-21 09:48:21

标签: javascript algorithm

我正在处理QueryBuilder JavaScript库(https://github.com/mistic100/jQuery-QueryBuilder/issues/59)的问题。

目标是从SQL语句填充构建器。为此,我使用https://github.com/forward/sql-parser将WHERE子句转换为AST。

现在我的问题是我需要将这个AST(这是一种二叉树)转换为QueryBuilder的内部格式(我不知道技术名称)。但我很蠢,我找不到一个有效的算法。

所以我在这里找到一个擅长这个的人!我只需要主算法来转换数据结构,转换值和运算符格式不会有问题。

注意:

  • 深度不受限制
  • 组条件(当然)仅为AND和OR
  • 虽然规则的顺序并不重要,但应该保留

输入SQL是(测试用例):

name LIKE "Mistic%" 
AND price BETWEEN 100 AND 200 
AND (
  category IN(1,2)
  OR parent <= 0
) 
AND id is not null

这是SQL Parser的输出:

{
  left: {
    left: {
      left: {
        left: {
          value: 'name'
        },
        operation: 'LIKE',
        right: {
          value: 'Mistic%'
        },
      },
      operation: 'AND',
      right: {
        left: {
          value: 'price'
        },
        operation: 'BETWEEN',
        right: {
          value: [
            {
              value: 100
            },
            {
              value: 200
            }
          ]
        }
      }
    },
    operation: 'AND',
    right: {
      left: {
        left: {
          value: 'category'
        },
        operation: 'IN',
        right: {
          value: [
            {
              value: 1
            },
            {
              value: 2
            }
          ]
        }
      },
      operation: 'OR',
      right: {
        left: {
          value: 'parent'
        },
        operation: '<=',
        right: {
          value: 0
        }
      }
    }
  },
  operation: 'AND',
  right: {
    left: {
      value: 'id'
    },
    operation: 'is not',
    right: {
      value: null
    }
  }
}

这是我需要的数据结构:

{
  condition: 'AND',
  rules: [
    {
      id: 'name',
      operator: 'like',
      value: 'Mistic%'
    },
    {
      id: 'price',
      operator: 'between',
      value: [100, 200]
    },
    {
      condition: 'OR',
      rules: [
        {
          id: 'category',
          operator: 'in',
          value: [1, 2]
        },
        {
          id: 'parent',
          operator: 'less_or_equal',
          value: 0
        }
      ]
    },
    {
      id: 'id',
      operator: 'not_null',
      value: null
    }
  ]
}

1 个答案:

答案 0 :(得分:1)

我想我得到了它,这是伪代码:

var out = {
  condition: null
  rules: []
}
var curr = out

function flatten(node, level)
  if node.operation = 'AND' or node.operation = 'OR' then
    if level > 0 and curr.condition != node.operation then
      curr.rules.push({
        condition: null
        rules: []
      })
      curr = curr.rules.end()
    end if

    curr.condition = node.operation

    level++;

    var next = curr
    flatten(node.right, level)

    curr = next
    flatten(node.left, level)
  else
    curr.rules.push({
      id: node.left.value
      operator: node.operation
      value: node.right.value
    })
  end if
end function

flatten(parsed, 0)

当操作符在AND和OR之间切换时,它是一个自调用递归函数创建子组,而在展平左侧和右侧部分时,在右子组中使用一点点技巧。