Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: the samples endpoint supports filters and pagination #20683

Merged
merged 12 commits into from
Jul 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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))
Loading