airbnb/caravel

View on GitHub
superset-frontend/src/explore/exploreUtils/getParsedExploreURLParams.ts

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

export interface Location {
  search: string;
  pathname: string;
}

// mapping { url_param: v1_explore_request_param }
const EXPLORE_URL_SEARCH_PARAMS = {
  form_data: {
    name: 'form_data',
    parser: (formData: string) => {
      const formDataObject = JSON.parse(formData);
      if (formDataObject.datasource) {
        const [datasource_id, datasource_type] =
          formDataObject.datasource.split('__');
        formDataObject.datasource_id = datasource_id;
        formDataObject.datasource_type = datasource_type;
        delete formDataObject.datasource;
      }
      return formDataObject;
    },
  },
  slice_id: {
    name: 'slice_id',
  },
  datasource_id: {
    name: 'datasource_id',
  },
  datasource_type: {
    name: 'datasource_type',
  },
  datasource: {
    name: 'datasource',
    parser: (datasource: string) => {
      const [datasource_id, datasource_type] = datasource.split('__');
      return { datasource_id, datasource_type };
    },
  },
  form_data_key: {
    name: 'form_data_key',
  },
  permalink_key: {
    name: 'permalink_key',
  },
  viz_type: {
    name: 'viz_type',
  },
  dashboard_id: {
    name: 'dashboard_id',
  },
};

const EXPLORE_URL_PATH_PARAMS = {
  p: 'permalink_key', // permalink
  table: 'datasource_id',
};

// search params can be placed in form_data object
// we need to "flatten" the search params to use them with /v1/explore endpoint
const getParsedExploreURLSearchParams = (search: string) => {
  const urlSearchParams = new URLSearchParams(search);
  return Array.from(urlSearchParams.keys()).reduce((acc, currentParam) => {
    const paramValue = urlSearchParams.get(currentParam);
    if (paramValue === null) {
      return acc;
    }
    let parsedParamValue;
    try {
      parsedParamValue =
        EXPLORE_URL_SEARCH_PARAMS[currentParam].parser?.(paramValue) ??
        paramValue;
    } catch {
      parsedParamValue = paramValue;
    }
    if (typeof parsedParamValue === 'object') {
      return { ...acc, ...parsedParamValue };
    }
    const key = EXPLORE_URL_SEARCH_PARAMS[currentParam]?.name || currentParam;
    return {
      ...acc,
      [key]: parsedParamValue,
    };
  }, {});
};

// path params need to be transformed to search params to use them with /v1/explore endpoint
const getParsedExploreURLPathParams = (pathname: string) =>
  Object.keys(EXPLORE_URL_PATH_PARAMS).reduce((acc, currentParam) => {
    const re = new RegExp(`/(${currentParam})/(\\w+)`);
    const pathGroups = pathname.match(re);
    if (pathGroups?.[2]) {
      return { ...acc, [EXPLORE_URL_PATH_PARAMS[currentParam]]: pathGroups[2] };
    }
    return acc;
  }, {});

export const getParsedExploreURLParams = (
  location: Location = window.location,
) =>
  new URLSearchParams(
    Object.entries({
      ...getParsedExploreURLSearchParams(location.search),
      ...getParsedExploreURLPathParams(location.pathname),
    })
      .map(entry => entry.join('='))
      .join('&'),
  );