Skip to content

Commit

Permalink
feat: the samples endpoint supports filters and pagination (#20683)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaoyongjie committed Jul 22, 2022
1 parent 3954535 commit f011aba
Show file tree
Hide file tree
Showing 13 changed files with 479 additions and 437 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ describe('Test datatable', () => {
});
it('Datapane loads view samples', () => {
cy.intercept(
'api/v1/explore/samples?force=false&datasource_type=table&datasource_id=*',
'datasource/samples?force=false&datasource_type=table&datasource_id=*',
).as('Samples');
cy.contains('Samples')
.click()
Expand Down
5 changes: 3 additions & 2 deletions superset-frontend/src/components/Chart/chartAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -602,10 +602,11 @@ export const getDatasourceSamples = async (
datasourceType,
datasourceId,
force,
jsonPayload,
) => {
const endpoint = `/api/v1/explore/samples?force=${force}&datasource_type=${datasourceType}&datasource_id=${datasourceId}`;
const endpoint = `/datasource/samples?force=${force}&datasource_type=${datasourceType}&datasource_id=${datasourceId}`;
try {
const response = await SupersetClient.get({ endpoint });
const response = await SupersetClient.post({ endpoint, jsonPayload });
return response.json.result;
} catch (err) {
const clientError = await getClientErrorObject(err);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import { SamplesPane } from '../components';
import { createSamplesPaneProps } from './fixture';

describe('SamplesPane', () => {
fetchMock.get(
'end:/api/v1/explore/samples?force=false&datasource_type=table&datasource_id=34',
fetchMock.post(
'end:/datasource/samples?force=false&datasource_type=table&datasource_id=34',
{
result: {
data: [],
Expand All @@ -40,8 +40,8 @@ describe('SamplesPane', () => {
},
);

fetchMock.get(
'end:/api/v1/explore/samples?force=true&datasource_type=table&datasource_id=35',
fetchMock.post(
'end:/datasource/samples?force=true&datasource_type=table&datasource_id=35',
{
result: {
data: [
Expand All @@ -54,8 +54,8 @@ describe('SamplesPane', () => {
},
);

fetchMock.get(
'end:/api/v1/explore/samples?force=false&datasource_type=table&datasource_id=36',
fetchMock.post(
'end:/datasource/samples?force=false&datasource_type=table&datasource_id=36',
400,
);

Expand Down
70 changes: 2 additions & 68 deletions superset/datasets/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@
from typing import Any
from zipfile import is_zipfile, ZipFile

import simplejson
import yaml
from flask import make_response, request, Response, send_file
from flask import request, Response, send_file
from flask_appbuilder.api import expose, protect, rison, safe
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_babel import ngettext
Expand All @@ -46,13 +45,11 @@
DatasetInvalidError,
DatasetNotFoundError,
DatasetRefreshFailedError,
DatasetSamplesFailedError,
DatasetUpdateFailedError,
)
from superset.datasets.commands.export import ExportDatasetsCommand
from superset.datasets.commands.importers.dispatcher import ImportDatasetsCommand
from superset.datasets.commands.refresh import RefreshDatasetCommand
from superset.datasets.commands.samples import SamplesDatasetCommand
from superset.datasets.commands.update import UpdateDatasetCommand
from superset.datasets.dao import DatasetDAO
from superset.datasets.filters import DatasetCertifiedFilter, DatasetIsNullOrEmptyFilter
Expand All @@ -63,7 +60,7 @@
get_delete_ids_schema,
get_export_ids_schema,
)
from superset.utils.core import json_int_dttm_ser, parse_boolean_string
from superset.utils.core import parse_boolean_string
from superset.views.base import DatasourceFilter, generate_download_headers
from superset.views.base_api import (
BaseSupersetModelRestApi,
Expand Down Expand Up @@ -93,7 +90,6 @@ class DatasetRestApi(BaseSupersetModelRestApi):
"bulk_delete",
"refresh",
"related_objects",
"samples",
}
list_columns = [
"id",
Expand Down Expand Up @@ -775,65 +771,3 @@ def import_(self) -> Response:
)
command.run()
return self.response(200, message="OK")

@expose("/<pk>/samples")
@protect()
@safe
@statsd_metrics
@event_logger.log_this_with_context(
action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.samples",
log_to_statsd=False,
)
def samples(self, pk: int) -> Response:
"""get samples from a Dataset
---
get:
description: >-
get samples from a Dataset
parameters:
- in: path
schema:
type: integer
name: pk
- in: query
schema:
type: boolean
name: force
responses:
200:
description: Dataset samples
content:
application/json:
schema:
type: object
properties:
result:
$ref: '#/components/schemas/ChartDataResponseResult'
401:
$ref: '#/components/responses/401'
403:
$ref: '#/components/responses/403'
404:
$ref: '#/components/responses/404'
422:
$ref: '#/components/responses/422'
500:
$ref: '#/components/responses/500'
"""
try:
force = parse_boolean_string(request.args.get("force"))
rv = SamplesDatasetCommand(pk, force).run()
response_data = simplejson.dumps(
{"result": rv},
default=json_int_dttm_ser,
ignore_nan=True,
)
resp = make_response(response_data, 200)
resp.headers["Content-Type"] = "application/json; charset=utf-8"
return resp
except DatasetNotFoundError:
return self.response_404()
except DatasetForbiddenError:
return self.response_403()
except DatasetSamplesFailedError as ex:
return self.response_400(message=str(ex))
80 changes: 0 additions & 80 deletions superset/datasets/commands/samples.py

This file was deleted.

84 changes: 3 additions & 81 deletions superset/explore/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,28 @@
# under the License.
import logging

import simplejson
from flask import g, make_response, request, Response
from flask import g, request, Response
from flask_appbuilder.api import BaseApi, expose, protect, safe

from superset.charts.commands.exceptions import ChartNotFoundError
from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod
from superset.dao.exceptions import DatasourceNotFound
from superset.explore.commands.get import GetExploreCommand
from superset.explore.commands.parameters import CommandParameters
from superset.explore.commands.samples import SamplesDatasourceCommand
from superset.explore.exceptions import (
DatasetAccessDeniedError,
DatasourceForbiddenError,
DatasourceSamplesFailedError,
WrongEndpointError,
)
from superset.explore.exceptions import DatasetAccessDeniedError, WrongEndpointError
from superset.explore.permalink.exceptions import ExplorePermalinkGetFailedError
from superset.explore.schemas import ExploreContextSchema
from superset.extensions import event_logger
from superset.temporary_cache.commands.exceptions import (
TemporaryCacheAccessDeniedError,
TemporaryCacheResourceNotFoundError,
)
from superset.utils.core import json_int_dttm_ser, parse_boolean_string

logger = logging.getLogger(__name__)


class ExploreRestApi(BaseApi):
method_permission_name = MODEL_API_RW_METHOD_PERMISSION_MAP
include_route_methods = {RouteMethod.GET} | {
"samples",
}
include_route_methods = {RouteMethod.GET}
allow_browser_login = True
class_permission_name = "Explore"
resource_name = "explore"
Expand Down Expand Up @@ -146,70 +135,3 @@ def get(self) -> Response:
return self.response(403, message=str(ex))
except TemporaryCacheResourceNotFoundError as ex:
return self.response(404, message=str(ex))

@expose("/samples", methods=["GET"])
@protect()
@safe
@event_logger.log_this_with_context(
action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.samples",
log_to_statsd=False,
)
def samples(self) -> Response:
"""get samples from a Datasource
---
get:
description: >-
get samples from a Datasource
parameters:
- in: path
schema:
type: integer
name: pk
- in: query
schema:
type: boolean
name: force
responses:
200:
description: Datasource samples
content:
application/json:
schema:
type: object
properties:
result:
$ref: '#/components/schemas/ChartDataResponseResult'
401:
$ref: '#/components/responses/401'
403:
$ref: '#/components/responses/403'
404:
$ref: '#/components/responses/404'
422:
$ref: '#/components/responses/422'
500:
$ref: '#/components/responses/500'
"""
try:
force = parse_boolean_string(request.args.get("force"))
rv = SamplesDatasourceCommand(
user=g.user,
datasource_type=request.args.get("datasource_type", type=str),
datasource_id=request.args.get("datasource_id", type=int),
force=force,
).run()

response_data = simplejson.dumps(
{"result": rv},
default=json_int_dttm_ser,
ignore_nan=True,
)
resp = make_response(response_data, 200)
resp.headers["Content-Type"] = "application/json; charset=utf-8"
return resp
except DatasourceNotFound:
return self.response_404()
except DatasourceForbiddenError:
return self.response_403()
except DatasourceSamplesFailedError as ex:
return self.response_400(message=str(ex))

0 comments on commit f011aba

Please sign in to comment.