cube icon indicating copy to clipboard operation
cube copied to clipboard

How can I access cube-defintions in the queryRewrite JS-function?

Open siamak-haschemi opened this issue 1 year ago • 1 comments

Problem

How can I access cube-defintions in the queryRewrite JS-function?

Details

Hi all!

We use queryRewrite to implement row-level-security (RLS). In the context of the queryRewrite function, is there a way to access the definition of our models?

Our use case is that our models have certain dimensions and joins which are subject to filtering for our RLS. If possible we want to write generic code in our cube.js which works for all models. For this, we need to inspect query to understand which model is used, but also access the definition of the model to dynamically decide which filters to add.

Thank you for your help!

This is how our queryRewrite looks today. We want to get rid of the cubes mapping, but rather access the definition of the cubes (customer_targets, entity_controlling) to check if they have joins which start with access_to_... (as a convention).

[...]
queryRewrite: (query, {securityContext}) => {

    let cubes = {
      customer_targets: ["access_to_advertisers"],
      entity_controlling: ["access_to_advertisers", "access_to_partners"],
    };
    
    const cubeNames = [
      ...(query.dimensions || []),
      ...(query.measures || []),
      ...((query.filters && query.filters.map((f) => f.member)) || []),
    ].map((e) => e.split('.')[0]);

    const uniqueCubeNames = [...new Set(cubeNames)];

    uniqueCubeNames.forEach((cube) => {
      query.filters.push({
        member: cube + '.network_id',
        operator: 'equals',
        values: [securityContext.networkId + ''],
      });

      if (cubes[cube]) {
        cubes[cube].forEach((accessCube) => {
          query.filters.push({
            member: accessCube + '.acl_user_id',
            operator: 'contains',
            values: [',' + securityContext.userId + '_' + securityContext.userType + ','],
          });
          query.filters.push({
            member: accessCube + '.network_id',
            operator: 'equals',
            values: [securityContext.networkId + ''],
          });
        });
      }
    });

    console.log("Query after rewrite: ", query);

    return query;
  },
[...]

siamak-haschemi avatar May 24 '23 19:05 siamak-haschemi

Hi @siamak-haschemi 👋 This is a very interesting question.

I think what you can do is to use fetch to query the /meta endpoint of the REST API and get the data model meta data. However, please keep in mind that you'd need to do it with the same JWT so you get the correct data model (in case you use multitenancy).

igorlukanin avatar Aug 31 '23 13:08 igorlukanin