• cube.js 上下文实践的一些说明


    cube.js 提供了比较多的上下问支持,SECRUITY_CONTEXT,COMPILE_CONTEXT,FILTER_PARAMS,SQL_UTILS
    但是在使用的时候可能会有好多问题,主要是原因是cube.js 对于编译的cache 以及不同context 的声明周期不一样

    SECURITY_CONTEXT 的使用

    推荐基于filter 模式使用,因为cube.js 对于schema 的编译是基于独立vm 处理的,而且就没有暴露相关的全局对象
    只暴露的,所以不能直接引用,不然会报错的
    参考几个定义

     
    const CONTEXT_SYMBOLS = {
      USER_CONTEXT: 'securityContext',
      SECURITY_CONTEXT: 'securityContext',
      FILTER_PARAMS: 'filterParams',
      SQL_UTILS: 'sqlUtils'
    };

    参考compiler 处理

    vm.runInNewContext(file.content, {
            view: (name, cube) => cubes.push(Object.assign({}, cube, { name, fileName: file.fileName })),
            cube:
              (name, cube) => (
                !cube ?
                  this.cubeFactory({ ...name, fileName: file.fileName }) :
                  cubes.push(Object.assign({}, cube, { name, fileName: file.fileName }))
              ),
            context: (name, context) => contexts.push(Object.assign({}, context, { name, fileName: file.fileName })),
            dashboardTemplate:
              (name, template) => dashboardTemplates.push(Object.assign({}, template, { name, fileName: file.fileName })),
            addExport: (obj) => {
              exports[file.fileName] = exports[file.fileName] || {};
              exports[file.fileName] = Object.assign(exports[file.fileName], obj);
            },
            setExport: (obj) => {
              exports[file.fileName] = obj;
            },
            asyncModule: (fn) => {
              asyncModules.push(fn);
            },
            require: (extensionName) => {
              if (self.extensions[extensionName]) {
                return new (self.extensions[extensionName])(this.cubeFactory, self);
              } else {
                const foundFile = self.resolveModuleFile(file, extensionName, toCompile, errorsReport);
                if (!foundFile && this.allowNodeRequire) {
                  if (extensionName.indexOf('.') === 0) {
                    extensionName = path.resolve(this.repository.localPath(), extensionName);
                  }
                  // eslint-disable-next-line global-require,import/no-dynamic-require
                  return require(extensionName);
                }
                self.compileFile(
                  foundFile,
                  errorsReport,
                  cubes,
                  exports,
                  contexts,
                  dashboardTemplates,
                  toCompile,
                  compiledFiles
                );
                exports[foundFile.fileName] = exports[foundFile.fileName] || {};
                return exports[foundFile.fileName];
              }
            },
            COMPILE_CONTEXT: R.clone(this.compileContext || {})
          }, { filename: file.fileName, timeout: 15000 });
    • 参考SECURITY_CONTEXT使用
    cube(`Orders`, {
      sql: `SELECT * FROM orders WHERE ${SECURITY_CONTEXT.email.filter('email')}`,
      dimensions: {
        date: {
          sql: `date`,
          type: `time`
        }
      }
    });
    • 一些缺点
      因为SECURITY_CONTEXT主要是checkAuth 处理的,如果需要关联扩展需要改动代码

    COMPILE_CONTEXT

    主要属于schema 编译的时候,这个问题就比较多了,主要场景还是多租户,但是因为cube.js
    编译api 的cache 以及COMPILE_CONTEXT执行一次的特性,很多时候容易出现使用问题
    比如,有可能COMPILE_CONTEXT的数据不存在,可能会造成undefined的问题

     
    const { securityContext: { total_amount,user_id,bucket } } = COMPILE_CONTEXT;
    const filter_count = total_amount
    const usercontext = SECURITY_CONTEXT
    const user_id2 = JSON.stringify(COMPILE_CONTEXT)
    cube(`demoapp`, {
        sql: ` SELECT
        *
    FROM 
        transactions AS ts
        where  total_amount  > ${filter_count}
    `,
        measures: {
            average_spend_per_customer: {
                sql: `${sum}/${count}`,
                type: `number`
            },
            count: {
                sql: `total_amount`,
                type: `count`,
            },
            sum: {
                sql: `total_amount`,
                type: `sum`,
            }
        },
        dimensions: {
            total_amount: {
                sql: `total_amount`,
                type: `number`
            },
            customer_id: {
                sql: `customer_id`,
                type: `string`
            },
            transaction_date: {
                sql: `transaction_date`,
                type: `time`,
                shown: false
            },
            event_id: {
                sql: `event_id`,
                type: `string`
            }
        }
    });

    FILTER_PARAMS

    主要是进行数据过滤的,但是也要注意使用

    • 参考格式
    FILTER_PARAMS.<CUBE_NAME>.<FILTER_NAME>.filter(expression)

    注意filter_name 是必须存在的(就是维度指标)

    总结

    如果真的需要进行数据动态过滤处理,推荐使用FILTER_PARAMS以及SECURITY_CONTEXT
    但是SECURITY_CONTEXT因为数据来源的特性,需要额外注意,一般情况(非多租户场景)不
    推荐使用COMPILE_CONTEXT
    FILTER_PARAMS 以及SECURITY_CONTEXT 的使用推荐基于filter(不然也会面临编译api cache 的问题)

    说明

    目前cube.js 还是缺少一些数据源自定义过滤的能力,官方也在计划中,最好的进行过滤还是推荐
    使用以上的几个上下文

    参考资料

    https://cube.dev/docs/cube#context-variables-filter-params

  • 相关阅读:
    申论复习路线
    项目管理小拾
    物理隔离卡,双网通用安装
    生成css sprites
    图片压缩
    css预编译 sass
    小杂记
    遮罩层和弹出层(居中)
    布局之并列登高自适应高度解决方案
    slide逻辑
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/14358955.html
Copyright © 2020-2023  润新知