美文网首页
可视化查询

可视化查询

作者: 大乔是个美少女 | 来源:发表于2019-06-06 09:26 被阅读0次

    1. 数据结构的设计

    实现sql语句数据结构存储。精巧的地方在于对于andor条件逻辑的设计。
    当然最后实现的时候还是有一些差别,哈哈哈。

        Column = {
            distinct: true,
            aggr_func: 'sum',
            name: 'col1', # func(col) sum/count/avg/distinct # db.tb
            id: 12344,
            alias: 'a', # 重命名
            table: Table()
        }
        Table = {
            id: 234,
            name: "table.name",
            alias: 't'
        }
        Condition = {
            op: {
                name: 'eq',
                value: '='
            }
            value: [
                # type: condition,column,expr 
                # 如果type是condition,表示and,or类型,value内的对象都是condition类型。
                {
                    type: 'column',
                    col: Column()
                },
                {
                    type: 'expr',
                    value: '20170291'
                }
                ...
            ]
        }
        # 单条查询语句,支持mysql,hive语法
        # union 链接多个select
        json = [{
            select: [Column(),..],
            from: [Table(),..] # db.tb
            join: [{
                type: 'left join'
                table: Table()
                on: Condition()
            }],
            where: Condition(),
            group_by: [Column(),..]
            having:Condition(),
            order_by: [{
                col: Column(),
                sort: 'desc'
            }]
            limit: 10,
        }]
    

    2. 从脏检查到观察者模式

    1. angularjs到vue项目的迁移
      vue项目越来越火,组件化的趋势越来越明显。大而全的angularjs,慢慢被新的技术替代。
      我们老的项目想迁移到vue上进行开发。
      ngvue 一个 directive 封装vue功能,使得angularjs可以使用vue。
    vue-component(v-props="ng" name="QueryVisualComponent")
    
    QueryVisualComponent = Vue.component('query-visual-component', {
        props: ['ng']
        data: ->
            return {
                info: null
                columns: null
            }
    
        template: '#query-visual-component-template'
    })
    MetronicApp.value('QueryVisualComponent', QueryVisualComponent)
    
    1. 处理angularjs,vue通信
      将angularjs依赖注入的方法都打包放在vue中也可以使用,$stateprops生成this会循环引用,栈溢出。
      全局变量整存整取。方便在vue中使用$http依赖请求数据。(当然也可以引入axios)
    g.utils.setDependencies($state.current.controller, arguments, {ctrl: @})
    @ng = g.utils.dependencies
    setDependencies: (controller_name, args, extra) ->
        g.utils.dependencies = extra ? {}
        for i in MetronicApp._invokeQueue
            if i[0] == '$controllerProvider'
                if i[2][0] == controller_name
                    for dependency, index in i[2][1].slice(0, -1)
                        g.utils.dependencies[dependency] = args[index]
                    break
    

    3. 页面功能设计与开发

    因为有审批流开发的基础,想当然的设计成了流程图。
    最后参照了navicat。


    可视化

    实际开发过程中,问题很多,宛若红军当年两万五千里长征,还好现在算是到达了延安,哈哈哈。

    如何在svg上生成没有问题的node节点?

    1.使用了svg forignObject 元素 https://github.com/memloom-development/svg.foreignobject.js
    2.vue compile extend (获取vue元素的dom结构)

          #vue compile extend
            visual_header = Header(world, snippet, table_id)
            VisualHeader = Vue.extend(visual_header)
            h_comp = new VisualHeader().$mount()
    
            @header = world.svg.foreignObject()
                .addClass('visual-header-object')
                .appendChild(h_comp.$el, {className: 'visual-header-box flex'})
    

    3.mac foreignObject 内部元素不能有滚动条,overflow: auto 超过高度或者宽度后,dom占位位置正确,实际显示偏移。
    4.node draggable会影响点击事件触发。双击响应,手动focus。

               .on('beforedrag', (e) ->
                    # 只能拖拽节点标题
                    dom = $(e.detail.event.target)
                    inHeader = dom.add(dom.parent()).hasClass('visual-header')
                    if not inHeader
                        e.preventDefault()
                        e.detail.event.stopPropagation()
                )
    

    5.vuex全局数据交互。
    6.右下边栏拖拽node页面大小。

                .on('mousedown', (e) =>
                    box = $("foreignObject[id='table_#{table_id}']")
                    if not e?
                        e = window.event
                    y = e.clientY
                    box_y = box.height()
                    document.onmousemove = (e) =>
                        box_height = e.clientY - y + box_y
                        box.css('height', Math.max(100, box_height) + "px")
                        @bottombar.move(0, Math.max(100, box_height) - 5)
                        @rightbar.height(Math.max(100, box_height) + 27)
                    document.onmouseup = ->
                        document.onmousemove = null
                )
    

    7.存储还原ViewBox缩放比例,存储还原画布节点线条,保证切换还原配置正常。

        setViewBox: (viewbox) ->
            if viewbox?
                @svg.viewbox(viewbox)
                @svg.zoom(viewbox.zoom)
            else
                @svg.viewbox(0, 0, $('#world').width(), $('#world').height())
    
    1. 滚轮缩放事件处理。
           .on('wheel', (e) ->
                if (navigator.userAgent.toLowerCase().indexOf('se 2.x') > -1)
                    w_dom = $(e.target).parents('.visual-node-box')[0]
                else
                    w_dom = $(e.target).parents('.visual-node-object')[0]
                if w_dom?
                    y = w_dom.scrollTop
                    w_dom.scrollTop = y + e.deltaY
            ).on('panEnd', (e) =>
                @saveViewBox()
            ).on( 'zoom', (e) =>
                # 找到点击的坐标,获取坐标位置dom元素,判断parents
                p = @translatePosFromSvgToBrowser(e.detail.focus.x, e.detail.focus.y)
                dom = document.elementFromPoint(p.x, p.y)
                if $(dom).parents('.visual-node-object').length
                    e.preventDefault()
                else
                    @saveViewBox()
    
            )
    

    9.画线。
    10.右键线条,节点菜单处理。
    11.删除表删除条件。

            count: 1
            sql: {
                '1':{
                    columns: [],
                    from: [],
                    join: {},
                    where: null,
                    limit: 10,
                    where_sql: ''
                    join_sql: {}
                    add_item: []
                    max_select: -1,
                    max_order_by: -1,
                    max_group_by: -1,
                    max_from: -1
                }
            }
            columns_dict: {}
            table_dict: {}
            checkedCol: {}
        }
    

    select、from、where、join、group by、order by、limit

    1.select(distinct、计算方法、别名)

    2.from与join 语句结合
    从无向图到有向图处理join语句。
    join规则有方向,控制join条件一定放在key大的那个table上。(这样不会产生环,之前无向图时,需要先判断环,再分组……)

    3.处理最后一个逗号问题(这里的确和上面设计的数据结构不一致,哈哈哈。)
    找到key的最大值,记录不显示最大值的逗号。

    4.where jqueryBuilder 处理and or 条件和sql展示。
    1.处理where条件有字段和值两种情况,需要select框支持输入和筛选两种功能。(selectize)
    2.处理默认字段和值两种不同。用@001@#{G_AUTO_COL_INDEX}@002@进行标记。
    3.处理in,not null, is_empty 特殊情况。

                  $('#where-builder').queryBuilder(options)
                    .on('afterUpdateRuleOperator.queryBuilder', (e, rule) ->
                        if ["is_empty", "is_not_empty", "is_null", "is_not_null"].indexOf(rule.operator.type) > -1
                            $("##{rule.id} .selectize-control").hide()
                    )
    
            getSQL: ->
                @where_sql = $('#where-builder').queryBuilder('getSQL')
                if @where_sql
                    # 变量替换@001@#{G_AUTO_COL_INDEX}@002@为alias+name
                    @where_sql.sql = @where_sql.sql.replace(/'@001@(\w+)@002@'/g, '@001@$1@002@')
                    @where_sql.sql = @where_sql.sql.replace( /@001@(\w+)@002@/g,
                        (col) ->
                            if store.state.columns_dict[col].table.alias
                                return "#{store.state.columns_dict[col].table.alias}.#{store.state.columns_dict[col].name}"
                            else
                                return "#{store.state.columns_dict[col].table.name}.#{store.state.columns_dict[col].name}"
                        )
                    @where_sql.sql = @where_sql.sql.replace(/IN\('(.*)'\)/g,
                        (col) ->
                            values = col.replace(/IN\('(.*)'\)/g, '$1').split(',')
                            v = ''
                            v = ("\'#{c}\'" for c in values).join(',')
                            v = "IN(#{v})"
                            return v
                        )
    

    5.记录join条件。
    join条件针对两个表之间进行配置,将条件存放在两个表中ID大的表上。展现是合并。

    4. 数据组装

    columns + from + join + where + group by + order by + limit
    1.别名的处理
    2.where语句拼装
    3.join语句拼装

    相关文章

      网友评论

          本文标题:可视化查询

          本文链接:https://www.haomeiwen.com/subject/feqyxctx.html