Example #1
0
    def get(self):
        args = self.parse_args([{
            'name': 'dashboard',
            'required': True,
            'location': 'args'
        }, {
            'name': 'chart',
            'required': True,
            'location': 'args'
        }])

        dbmeta = DBMeta(self.user_id)
        dashboard = dbmeta.dashboard('id', name=args['dashboard']).single()
        chart = dbmeta.chart(dashboard_id=dashboard.id,
                             name=args['chart']).single()
        ds = dbmeta.datasource(id=chart.ds_id).single()
        connector = Connector(user_id=self.user_id,
                              type=ds.type,
                              db=ds.name,
                              **ds.params)
        query = Query.load(chart.query, connector)

        result = query.execute()
        fields = [_['name'] for _ in chart.y_fields if _]
        data = chart_data(result, chart.x_fields, fields)
        self.response(ds_id=ds.id,
                      table=chart.table,
                      type=chart.type,
                      sql=query.sql,
                      xFields=chart.x_fields,
                      yFields=chart.y_fields,
                      **data)
Example #2
0
 def vtables(self):
     from model import DBMeta
     user_id = self.kwargs.get('user_id')
     ds_name = self.kwargs.get('db')
     if not user_id or not ds_name:
         return {}
     dbmeta = DBMeta(user_id)
     datasource = dbmeta.datasource(name=ds_name).single()
     vtables = dbmeta.vtable(ds_id=datasource.id).all()
     return [(tb.name, tb.query) for tb in vtables]
Example #3
0
    def post(self):
        args = self.parse_args([
            {
                'name': 'name',
                'required': True,
                'location': 'body'
            },
            {
                'name': 'ds_id',
                'required': True,
                'location': 'body'
            },
            {
                'name': 'rules',
                'required': True,
                'location': 'body'
            },
            {
                'name': 'type',
                'required': True,
                'location': 'body',
                'default': 'join'
            },
        ])

        self.meta = DBMeta(self.user_id)

        if args['type'] == 'join':
            table_json = self.join_table()
        else:
            table_json = self.aggr_table()
        if not table_json:
            return

        if self.meta.vtable(name=args['name']).first():
            self.response(409, u'已存在名字为 %s 的合表' % args['name'])
            return

        ds = self.meta.datasource(id=args['ds_id']).single()
        connector = Connector(user_id=self.user_id,
                              type=ds.type,
                              db=ds.name,
                              **ds.params)
        engine = Engine(connector)
        if args['name'] in engine.tables():
            self.response(409, u'原始库中已存在表(%s)' % args['name'])
            return

        vtb = self.meta.vtable(ds_id=args['ds_id'],
                               name=args['name'],
                               query=table_json)
        vtb.insert()
        self.meta.commit()
        self.response(message='success')
        del self.meta
Example #4
0
    def delete(self):
        args = self.parse_args([{
            'name': 'name',
            'required': True,
            'location': 'args'
        }])

        db = DBMeta(self.user_id)
        ds = db.dashboard(name=args['name'])
        ds.delete()
        db.commit()
        self.response(message='success')
Example #5
0
    def post(self):
        args = self.parse_args([{
            'name': 'name',
            'required': True,
            'location': 'body'
        }])

        db = DBMeta(self.user_id)
        ds = db.dashboard(name=args['name'])
        if ds.first():
            self.response(409, u'已存在名字为 %s 的仪表盘' % args['name'])
            return

        ds.insert()
        db.commit()
        self.response(message='success')
Example #6
0
    def post(self):
        args = self.parse_args([{
            'name': 'names',
            'required': True,
            'location': 'body'
        }])

        dbmeta = DBMeta(self.user_id)
        for name in args['names']:
            dsbd = dbmeta.dashboard(name=name)
            dashboard = dsbd.first()
            if dashboard:
                continue
            dsbd.insert()
        dbmeta.commit()
        self.response(message='success')
Example #7
0
    def get(self):
        args = self.parse_args([{
            'name': 'ds_id',
            'required': True,
            'location': 'args'
        }, {
            'name': 'table',
            'required': True,
            'location': 'args'
        }, {
            'name': 'filters',
            'required': False,
            'location': 'args',
            'cast': json.loads,
            'defalt': '[]'
        }, {
            'name': 'xFields',
            'required': False,
            'location': 'args',
            'cast': json.loads,
            'defalt': '[]'
        }, {
            'name': 'yFields',
            'required': False,
            'location': 'args',
            'cast': json.loads,
            'defalt': '[]'
        }])

        self.dbmeta = DBMeta(self.user_id)
        ds = self.dbmeta.datasource(id=args['ds_id']).single()
        connector = Connector(user_id=self.user_id,
                              type=ds.type,
                              db=ds.name,
                              **ds.params)

        query = self.query
        self.logger.info('%s' % query.json())
        query.deepbind(connector)
        result = query.execute()
        self.response(sql=query.sql,
                      data=result.json_data,
                      schema=result.schema,
                      columns=result.columns)
        del self.dbmeta
Example #8
0
    def get(self):
        args = self.parse_args([{
            'name': 'dashboard',
            'required': True,
            'location': 'args'
        }])

        dbmeta = DBMeta(self.user_id)
        dashboard = dbmeta.dashboard(name=args['dashboard']).first()
        if not dashboard:
            self.response(404, message='不存在的仪表盘')
            return

        charts = dbmeta.chart('name', dashboard_id=dashboard.id).all()
        self.response(**{
            'total': len(charts),
            'charts': [c.name for c in charts]
        })
Example #9
0
    def post(self):
        args = self.parse_args([{
            'name': 'username',
            'required': True,
            'location': 'body'
        }, {
            'name': 'password',
            'required': True,
            'location': 'body'
        }])

        try:
            db = DBMeta()
            user = db.user(**args).auth()
        except Exception, e:
            self.logger.warn(e, exc_info=True)
            self.response(401, 'Auth failed!')
            return
Example #10
0
    def get(self):
        args = self.parse_args([{
            'name': 'pageno',
            'required': False,
            'location': 'args'
        }, {
            'name': 'pagesize',
            'required': False,
            'location': 'args'
        }, {
            'name': 'name',
            'required': False,
            'location': 'args'
        }])

        dbmeta = DBMeta(self.user_id)

        kwargs = {}
        if args.get('name'):
            kwargs['name'] = args['name']

        datasources = dbmeta.datasource(**kwargs).all()

        result = []
        for ds in datasources:
            item = {
                'id': ds.id,
                'name': ds.name,
                'ctime': ds.ctime,
                'utime': ds.utime,
                'type': ds.type.upper()
            }
            connector = Connector(type=ds.type.upper(),
                                  user_id=self.user_id,
                                  db=ds.name,
                                  **ds.params)
            if isinstance(connector, ODOConnector):
                engine = Engine(connector)
                ds.params['filelist'] = engine.tables()
            item.update(ds.params)
            result.append(item)

        self.response(**{"total": len(result), "datasources": result})
Example #11
0
    def delete(self):
        args = self.parse_args([
            {
                'name': 'ids',
                'required': True,
                'location': 'args',
                'cast': json.loads
            },
        ])

        db = DBMeta(self.user_id)
        for ds_id in args['ids']:
            ds = db.datasource(id=ds_id)
            datasource = ds.single()
            if datasource.type in FILEMETA:
                pass
            ds.delete()
        db.commit()
        self.response(message='success')
Example #12
0
 def delete(self):
     args = self.parse_args([
         {'name': 'dashboard', 'required': True, 'location': 'args'},
         {'name': 'chart', 'required': True, 'location': 'args'}
     ])
     dbmeta = DBMeta(self.user_id)
     dsbd = dbmeta.dashboard('id', name=args['dashboard']).single()
     dbmeta.chart(name=args['chart'], dashboard_id=dsbd.id).delete()
     dbmeta.commit()
     self.response(message='success')
Example #13
0
    def post(self):
        args = self.parse_args([
            {'name': 'name', 'required': True, 'location': 'body'},
            {'name': 'type', 'required': True, 'location': 'body'},
            {'name': 'params', 'required': True, 'location': 'body'}
        ])

        args['params'] = params(args['type'], **args['params'])
        db = DBMeta(self.user_id)
        dss = db.datasource(name=args['name']).all()
        if dss:
            self.response(409, message='已存在名称为 %s 的数据源' % args['name'])
            return

        if not args['params'].get('filelist'):
            connector = Connector(args['type'], db=args['name'], **args['params'])
            databases = Engine(connector).databases()
            if args['name'] not in databases:
                self.response(412, u'数据库中不存在 %s 库'  % args['name'])
                return

        ds = db.datasource(**args)
        ds.insert()
        db.commit()
        self.response(message='success')
Example #14
0
    def get(self):
        args = self.parse_args([{
            'name': 'ds_id',
            'required': True,
            'location': 'args',
            'cast': int
        }, {
            'name': 'tables',
            'required': False,
            'location': 'args',
            'cast': json.loads
        }])
        tables = args.get('tables')
        db = DBMeta(self.user_id)
        ds = db.datasource(id=args['ds_id']).single()
        connector = Connector(user_id=self.user_id,
                              type=ds.type,
                              db=ds.name,
                              **ds.params)
        engine = Engine(connector)

        dbmeta = DBMeta(self.user_id)
        vtables = dbmeta.vtable(ds_id=args['ds_id']).all()
        all_table = engine.tables() + [_.name for _ in vtables]
        result = [{
            'name': _,
            'schema': [_['name'] for _ in engine.schema(_)]
        } for _ in all_table if not tables or _ in tables]

        self.response(**{'total': len(result), 'schema': result})
Example #15
0
    def get(self):
        args = self.parse_args([
            {'name': 'ds_id', 'required': True, 'location': 'args', 'cast': int},
            {'name': 'table', 'required': True, 'location': 'args'},
            {'name': 'xFields', 'required': True, 'location': 'args', 'cast': json.loads},
            {'name': 'yFields', 'required': True, 'location': 'args', 'cast': json.loads},
            {'name': 'filters', 'required': False, 'location': 'args', 'cast': json.loads, 'defalt': '[]'},
            {'name': 'type', 'required': True, 'location': 'args'}
        ])

        self.dbmeta = DBMeta(self.user_id)
        ds = self.dbmeta.datasource(id=args['ds_id']).single()
        connector = Connector(user_id=self.user_id, type=ds.type, db=ds.name, **ds.params)

        query = self.query
        self.logger.info('%s' % query.json())
        query.deepbind(connector)
        result = query.execute()

        fields = [_['name'][0] for _ in self.args['yFields'] if _['name']]
        self.response(sql=query.sql, **chart_data(result, args['xFields'], fields))
        del self.dbmeta
Example #16
0
    def put(self):
        args = self.parse_args([
            {'name': 'name', 'required': True, 'location': 'body'},
            {'name': 'dashboard', 'required': True, 'location': 'body'},
            {'name': 'ds_id', 'required': True, 'location': 'body', 'cast': int},
            {'name': 'table', 'required': True, 'location': 'body'},
            {'name': 'xFields', 'required': True, 'location': 'body'},
            {'name': 'yFields', 'required': True, 'location': 'body'},
            {'name': 'type', 'required': True, 'location': 'body'}
        ])

        self.dbmeta = DBMeta(self.user_id)
        query = self.query.json()

        dashboard = self.dbmeta.dashboard('id', name=args['dashboard']).single()
        y_fields = [{'name': _['name'][0], 'aggr_func': _['name'][1]} for _ in self.args['yFields'] if _['name']]
        chart = self.dbmeta.chart(name=args['name'], dashboard_id=dashboard.id)
        chart.update(
            ds_id=args['ds_id'], table=args['table'], query=query,
            x_fields=args['xFields'], y_fields=y_fields, type=args['type']
        )
        self.dbmeta.commit()
        self.response(message='success')
Example #17
0
    def delete(self):
        args = self.parse_args([
            {'name': 'id', 'required': True, 'location': 'args'}
        ])

        db = DBMeta(self.user_id)
        db.datasource(id=args['id']).delete()
        db.commit()
        self.response(message='success')
Example #18
0
    def post(self):
        args = self.parse_args([
            {'name': 'name', 'required': True, 'location': 'body'},
            {'name': 'dashboards', 'required': True, 'location': 'body'},
            {'name': 'ds_id', 'required': True, 'location': 'body', 'cast': int},
            {'name': 'table', 'required': True, 'location': 'body'},
            {'name': 'xFields', 'required': True, 'location': 'body'},
            {'name': 'yFields', 'required': True, 'location': 'body'},
            {'name': 'type', 'required': True, 'location': 'body'}
        ])
        self.dbmeta = DBMeta(self.user_id)
        query = self.query.json()

        y_fields = [{'name': _['name'][0], 'aggr_func': _['name'][1]} for _ in self.args['yFields'] if _['name']]

        dsbd = self.dbmeta.dashboard('id', 'name')
        dsbds = dsbd.filter(dsbd.column('name').in_(args['dashboards'])).all()
        dsbds = {_.id: _.name for _ in dsbds}
        for dsid, dsbdname in dsbds.items():
            ret = self.dbmeta.chart('dashboard_id', name=args['name'], dashboard_id_id=dsid).all()
            if ret:
                self.response(412, message=u'仪表盘 %s 中已存在名字为 %s 的图表' % (dsbdname, args['name']))
                return

        chart = self.dbmeta.chart(name=args['name'], ds_id=args['ds_id'], table=args['table'], query=query,
                                  x_fields=args['xFields'], y_fields=y_fields, type=args['type'])
        for dashboard in args['dashboards']:
            dashboard = self.dbmeta.dashboard(name=dashboard).first()
            if not dashboard:
                continue
            chart.dashboard_id = dashboard.id
        chart.insert()

        self.dbmeta.commit()
        self.response(message='success')
        del self.dbmeta
Example #19
0
    def post(self):
        args = self.parse_args([{
            'name': 'username',
            'required': True,
            'location': 'body'
        }, {
            'name': 'password',
            'required': True,
            'location': 'body'
        }])

        reg = re.match(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$',
                       args['username'])
        if not reg:
            self.response(400, '邮箱格式有误')
            return

        try:
            db = DBMeta()
            db.user(**args).insert()
        except Exception, e:
            self.logger.warn(e, exc_info=True)
            self.response(409, '用户已存在')
            return
Example #20
0
    def put(self):
        args = self.parse_args([
            {'name': 'id', 'required': True, 'location': 'body'},
            {'name': 'name', 'required': True, 'location': 'body'},
            {'name': 'type', 'required': True, 'location': 'body'},
            {'name': 'params', 'required': True, 'location': 'body'}
        ])

        args['params'] = params(args['type'], **args['params'])
        db = DBMeta(self.user_id)
        db.datasource(id=args['id']).update(**args)
        db.commit()
        self.response(message='success')
Example #21
0
 def get(self):
     dbmeta = DBMeta(self.user_id)
     dashboards = dbmeta.dashboard('id', 'name').all()
     result = [{'id': db.id, 'name': db.name} for db in dashboards]
     self.response(**{'total': len(result), 'dashboards': result})
Example #22
0
    def auth(self):
        from model import DBMeta
        if self.request.path == '/api/login':
            return
        try:
            user = self.get_cookie('user')
        except Exception, e:
            self.logger.error(e, exc_info=True)
            raise UnAuthentication()

        if not user:
            raise UnAuthentication()
        if time.time() - user.get('access', 0) > 60 * 60 * 24:
            raise AuthExpire()
        try:
            db = DBMeta()
            db = db.user(**user).auth()
            self.user_id = db['id']
        except Exception:
            raise UnAuthentication()

    def data_received(self, chunk):
        pass


class UnAuthentication(HTTPError):
    def __init__(self):
        super(UnAuthentication, self).__init__(401, 'Auth failed!')


class AuthExpire(HTTPError):
Example #23
0
class AggrPreviewHandler(BaseHandler):
    def get(self):
        args = self.parse_args([{
            'name': 'ds_id',
            'required': True,
            'location': 'args'
        }, {
            'name': 'table',
            'required': True,
            'location': 'args'
        }, {
            'name': 'filters',
            'required': False,
            'location': 'args',
            'cast': json.loads,
            'defalt': '[]'
        }, {
            'name': 'xFields',
            'required': False,
            'location': 'args',
            'cast': json.loads,
            'defalt': '[]'
        }, {
            'name': 'yFields',
            'required': False,
            'location': 'args',
            'cast': json.loads,
            'defalt': '[]'
        }])

        self.dbmeta = DBMeta(self.user_id)
        ds = self.dbmeta.datasource(id=args['ds_id']).single()
        connector = Connector(user_id=self.user_id,
                              type=ds.type,
                              db=ds.name,
                              **ds.params)

        query = self.query
        self.logger.info('%s' % query.json())
        query.deepbind(connector)
        result = query.execute()
        self.response(sql=query.sql,
                      data=result.json_data,
                      schema=result.schema,
                      columns=result.columns)
        del self.dbmeta

    @property
    def where(self):
        wheres = []
        for condition in self.args.get('filters', []):
            if not condition['name'] or not condition['operator']:
                continue
            name = condition['name']
            operator = condition['operator']
            if condition.get('value_type', 'value') == 'value':
                value = condition['value']
            else:
                value = Text(condition['value'])
            c = Condition(Column(name), operator, value)
            wheres.append(c.json())
        return wheres

    @property
    def table(self):
        chart = self.dbmeta.vtable(name=self.args['table'],
                                   ds_id=self.args['ds_id']).first()
        if chart:
            return chart.query
        return Table(self.args['table']).json()

    @property
    def columns(self):
        fields = [_['name'] for _ in self.args['yFields'] if _['name']]
        result = [function(func_name, name) for name, func_name in fields]
        group_by = self.group_by
        if group_by:
            return group_by + result
        if not result:
            return []
        return result

    @property
    def group_by(self):
        if not self.args['xFields']:
            return None
        return [Column(_).json() for _ in self.args['xFields']]

    @property
    def query(self):
        table = self.table
        if table['type'] == 'table':
            return Query(table=self.table,
                         columns=self.columns,
                         where=self.where,
                         group_by=self.group_by,
                         limit=10)
        else:
            query = Query.load(self.table)
            name = self.args['table']
            query.alias(name)
            return Query(table=name,
                         columns=self.columns,
                         where=self.where,
                         group_by=self.group_by,
                         limit=10).bind(query)
Example #24
0
    def get(self):
        args = self.parse_args([{
            'name': 'ds_id',
            'required': True,
            'location': 'args'
        }, {
            'name': 'tables',
            'required': True,
            'location': 'args',
            'cast': json.loads
        }, {
            'name': 'rules',
            'required': False,
            'location': 'args',
            'cast': json.loads
        }])

        result = []
        rules = args['rules']
        tables = args['tables']
        dbmeta = DBMeta(self.user_id)
        ds = dbmeta.datasource(id=args['ds_id']).single()
        connector = Connector(user_id=self.user_id,
                              type=ds.type,
                              db=ds.name,
                              **ds.params)
        engine = Engine(connector)
        wheres = parse_where(rules)

        vtables = dbmeta.vtable(ds_id=self.args['ds_id']).all()
        vtables = [(tb.name, tb.query) for tb in vtables]
        for tablenames, clause in wheres.items():
            columns = []
            for name in tablenames:
                columns += [
                    Column(name, _['name']).label('%s.%s' % (name, _['name']))
                    for _ in engine.schema(name)
                ]
            table_json = Table(*columns).select_from(*tablenames).where(
                *clause).json()
            q = Query(table=table_json, limit=10)
            q.bind(connector)
            ret = q.execute()
            result.append({
                'data': ret.json_data,
                'sql': q.sql,
                'columns': ret.columns,
                'names': tablenames
            })

        keys = sum(wheres.keys(), ())

        tables = [(_, dict(vtables).get(_, _)) for _ in tables
                  if _ not in keys]
        for name, tb in tables:
            q = get_query(tb, 10)
            q.bind(connector)
            ret = q.execute()
            result.append({
                'data': ret.json_data,
                'columns': ret.columns,
                'names': [name],
                'schema': ret.schema
            })
        self.response(total=len(result), tables=result)
Example #25
0
class TableHandler(BaseHandler):
    def post(self):
        args = self.parse_args([
            {
                'name': 'name',
                'required': True,
                'location': 'body'
            },
            {
                'name': 'ds_id',
                'required': True,
                'location': 'body'
            },
            {
                'name': 'rules',
                'required': True,
                'location': 'body'
            },
            {
                'name': 'type',
                'required': True,
                'location': 'body',
                'default': 'join'
            },
        ])

        self.meta = DBMeta(self.user_id)

        if args['type'] == 'join':
            table_json = self.join_table()
        else:
            table_json = self.aggr_table()
        if not table_json:
            return

        if self.meta.vtable(name=args['name']).first():
            self.response(409, u'已存在名字为 %s 的合表' % args['name'])
            return

        ds = self.meta.datasource(id=args['ds_id']).single()
        connector = Connector(user_id=self.user_id,
                              type=ds.type,
                              db=ds.name,
                              **ds.params)
        engine = Engine(connector)
        if args['name'] in engine.tables():
            self.response(409, u'原始库中已存在表(%s)' % args['name'])
            return

        vtb = self.meta.vtable(ds_id=args['ds_id'],
                               name=args['name'],
                               query=table_json)
        vtb.insert()
        self.meta.commit()
        self.response(message='success')
        del self.meta

    def join_table(self):
        wheres = parse_where(self.args['rules'])

        ds = self.meta.datasource(id=self.args['ds_id']).single()
        engine = Engine(
            Connector(user_id=self.user_id,
                      type=ds.type,
                      db=ds.name,
                      **ds.params))
        if len(wheres) != 1:
            self.response(422, '需要最终合成一张表')
            return

        tablenames, clause = wheres.items()[0]
        columns = []
        vtables = self.meta.vtable(ds_id=self.args['ds_id']).all()
        vtables = {tb.name: tb.query for tb in vtables}
        for name in tablenames:
            columns += [
                Column(name, _['name']).label('%s.%s' % (name, _['name']))
                for _ in self.schema(engine, vtables, name)
            ]
        return Table(*columns).select_from(*tablenames).where(*clause).json()

    def aggr_table(self):
        rule = self.args['rules']
        table = rule['table']
        return Query(table=table,
                     columns=self.columns,
                     where=self.where,
                     group_by=self.group_by,
                     order_by=None,
                     limit=None).json()

    def schema(self, engine, vtables, name):
        if name in engine.tables():
            return engine.schema(name)
        return [{
            'name': (_.alias or _.value)
        } for _ in get_query(vtables[name]).columns]

    @property
    def where(self):
        wheres = []
        filters = self.args['rules'].get('filters', [])
        for condition in filters:
            if not condition['name'] or not condition['operator']:
                continue
            name = condition['name']
            operator = condition['operator']
            value = condition['value']
            c = Condition(Column(name), operator, value)
            wheres.append(c.json())
        return wheres

    @property
    def columns(self):
        y_fields = self.args['rules']['y_fields']
        fields = [_['name'] for _ in y_fields if _['name']]
        result = [function(func_name, name) for name, func_name in fields]
        group_by = self.group_by
        if group_by:
            return group_by + result
        if not result:
            return []
        return result

    @property
    def group_by(self):
        x_fields = self.args['rules']['x_fields']
        if not x_fields:
            return None
        return [Column(_).json() for _ in x_fields]
Example #26
0
class ChartHandler(BaseHandler):
    def get(self):
        args = self.parse_args([
            {'name': 'ds_id', 'required': True, 'location': 'args', 'cast': int},
            {'name': 'table', 'required': True, 'location': 'args'},
            {'name': 'xFields', 'required': True, 'location': 'args', 'cast': json.loads},
            {'name': 'yFields', 'required': True, 'location': 'args', 'cast': json.loads},
            {'name': 'filters', 'required': False, 'location': 'args', 'cast': json.loads, 'defalt': '[]'},
            {'name': 'type', 'required': True, 'location': 'args'}
        ])

        self.dbmeta = DBMeta(self.user_id)
        ds = self.dbmeta.datasource(id=args['ds_id']).single()
        connector = Connector(user_id=self.user_id, type=ds.type, db=ds.name, **ds.params)

        query = self.query
        self.logger.info('%s' % query.json())
        query.deepbind(connector)
        result = query.execute()

        fields = [_['name'][0] for _ in self.args['yFields'] if _['name']]
        self.response(sql=query.sql, **chart_data(result, args['xFields'], fields))
        del self.dbmeta

    def post(self):
        args = self.parse_args([
            {'name': 'name', 'required': True, 'location': 'body'},
            {'name': 'dashboards', 'required': True, 'location': 'body'},
            {'name': 'ds_id', 'required': True, 'location': 'body', 'cast': int},
            {'name': 'table', 'required': True, 'location': 'body'},
            {'name': 'xFields', 'required': True, 'location': 'body'},
            {'name': 'yFields', 'required': True, 'location': 'body'},
            {'name': 'type', 'required': True, 'location': 'body'}
        ])
        self.dbmeta = DBMeta(self.user_id)
        query = self.query.json()

        y_fields = [{'name': _['name'][0], 'aggr_func': _['name'][1]} for _ in self.args['yFields'] if _['name']]

        dsbd = self.dbmeta.dashboard('id', 'name')
        dsbds = dsbd.filter(dsbd.column('name').in_(args['dashboards'])).all()
        dsbds = {_.id: _.name for _ in dsbds}
        for dsid, dsbdname in dsbds.items():
            ret = self.dbmeta.chart('dashboard_id', name=args['name'], dashboard_id_id=dsid).all()
            if ret:
                self.response(412, message=u'仪表盘 %s 中已存在名字为 %s 的图表' % (dsbdname, args['name']))
                return

        chart = self.dbmeta.chart(name=args['name'], ds_id=args['ds_id'], table=args['table'], query=query,
                                  x_fields=args['xFields'], y_fields=y_fields, type=args['type'])
        for dashboard in args['dashboards']:
            dashboard = self.dbmeta.dashboard(name=dashboard).first()
            if not dashboard:
                continue
            chart.dashboard_id = dashboard.id
        chart.insert()

        self.dbmeta.commit()
        self.response(message='success')
        del self.dbmeta

    def delete(self):
        args = self.parse_args([
            {'name': 'dashboard', 'required': True, 'location': 'args'},
            {'name': 'chart', 'required': True, 'location': 'args'}
        ])
        dbmeta = DBMeta(self.user_id)
        dsbd = dbmeta.dashboard('id', name=args['dashboard']).single()
        dbmeta.chart(name=args['chart'], dashboard_id=dsbd.id).delete()
        dbmeta.commit()
        self.response(message='success')

    def put(self):
        args = self.parse_args([
            {'name': 'name', 'required': True, 'location': 'body'},
            {'name': 'dashboard', 'required': True, 'location': 'body'},
            {'name': 'ds_id', 'required': True, 'location': 'body', 'cast': int},
            {'name': 'table', 'required': True, 'location': 'body'},
            {'name': 'xFields', 'required': True, 'location': 'body'},
            {'name': 'yFields', 'required': True, 'location': 'body'},
            {'name': 'type', 'required': True, 'location': 'body'}
        ])

        self.dbmeta = DBMeta(self.user_id)
        query = self.query.json()

        dashboard = self.dbmeta.dashboard('id', name=args['dashboard']).single()
        y_fields = [{'name': _['name'][0], 'aggr_func': _['name'][1]} for _ in self.args['yFields'] if _['name']]
        chart = self.dbmeta.chart(name=args['name'], dashboard_id=dashboard.id)
        chart.update(
            ds_id=args['ds_id'], table=args['table'], query=query,
            x_fields=args['xFields'], y_fields=y_fields, type=args['type']
        )
        self.dbmeta.commit()
        self.response(message='success')

    @property
    def where(self):
        wheres = []
        for condition in self.args.get('filters', []):
            if not condition['name'] or not condition['operator']:
                continue
            name = condition['name']
            operator = condition['operator']
            if condition.get('value_type', 'value') == 'value':
                value = condition['value']
            else:
                value = Text(condition['value'])
            c = Condition(Column(name), operator, value)
            wheres.append(c.json())
        return wheres

    @property
    def table(self):
        chart = self.dbmeta.vtable(name=self.args['table'], ds_id=self.args['ds_id']).first()
        if chart:
            return chart.query
        return Table(self.args['table']).json()

    @property
    def columns(self):
        fields = [_['name'] for _ in self.args['yFields'] if _['name']]
        result = [function(func_name, name) for name, func_name in fields]
        group_by = self.group_by
        if group_by:
            return group_by+result
        return result

    @property
    def group_by(self):
        if not self.args['xFields']:
            return None
        return [Column(_).json() for _ in self.args['xFields']]

    @property
    def query(self):
        table = self.table
        if table['type'] == 'table':
            return Query(table=self.table, columns=self.columns, where=self.where, group_by=self.group_by, limit=500)
        else:
            query = Query.load(self.table)
            name = self.args['table']
            query.alias(name)
            return Query(table=name, columns=self.columns, where=self.where,
                         group_by=self.group_by, limit=500).bind(query)