Skip to content

Commit

Permalink
feat: support get request for charts
Browse files Browse the repository at this point in the history
  • Loading branch information
Marc-AntoineA committed Jun 28, 2024
1 parent c2f2598 commit 813df59
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 60 deletions.
4 changes: 2 additions & 2 deletions app/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
class DistributionChartType(BaseModel):
"""Describes an entry for a distribution chart"""

chart_type: Literal["DistributionChartType"]
chart_type: Literal["DistributionChartType"] = "DistributionChartType"
field: str


class ScatterChartType(BaseModel):
"""Describes an entry for a scatter plot"""

chart_type: Literal["ScatterChartType"]
chart_type: Literal["ScatterChartType"] = "ScatterChartType"
x: str
y: str

Expand Down
24 changes: 23 additions & 1 deletion app/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
SearchParameters,
SearchResponse,
SuccessSearchResponse,
ScatterChartType,
DistributionChartType,
)
from app.config import check_config_is_defined, settings
from app.postprocessing import process_taxonomy_completion_response
Expand Down Expand Up @@ -94,6 +96,23 @@ def search(search_parameters: Annotated[SearchParameters, Body()]):
return app_search.search(search_parameters)


def parse_charts_get(charts_params: str):
"""
Parse for get params are 'field' or 'xfield:yfield'
separated by ',' for Distribution and Scatter charts.
Directly the dictionnaries in POST request
"""
charts = []
for c in charts_params.split(','):
if ':' in c:
[x, y] = c.split(':')
charts.append(ScatterChartType(x=x, y=y))
else:
charts.append(DistributionChartType(field=c))
return charts


@app.get("/search")
def search_get(
q: GetSearchParamsTypes.q = None,
Expand All @@ -103,13 +122,15 @@ def search_get(
fields: GetSearchParamsTypes.fields = None,
sort_by: GetSearchParamsTypes.sort_by = None,
facets: GetSearchParamsTypes.facets = None,
charts: GetSearchParamsTypes.facets = None,
index_id: GetSearchParamsTypes.index_id = None,
) -> SearchResponse:
# str to lists
langs_list = langs.split(",") if langs else ["en"]
fields_list = fields.split(",") if fields else None
facets_list = facets.split(",") if facets else None

charts = parse_charts_get(charts) if charts else None
print(charts)
# create SearchParameters object
try:
search_parameters = SearchParameters(
Expand All @@ -121,6 +142,7 @@ def search_get(
sort_by=sort_by,
facets=facets_list,
index_id=index_id,
charts=charts
)
return app_search.search(search_parameters)
except ValidationError as e:
Expand Down
6 changes: 3 additions & 3 deletions frontend/public/off.html
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,9 @@
</div>
<div slot="col-3">
<!-- Graphs inside -->
<searchalicious-distribution-chart search-name="off" name="nutrition_grades"'></searchalicious-distribution-chart>
<searchalicious-distribution-chart search-name="off" name="ecoscore_grade"></searchalicious-distribution-chart>
<searchalicious-distribution-chart search-name="off" name="nova_groups"></searchalicious-distribution-chart>
<searchalicious-distribution-chart search-name="off" field="nutrition_grades"'></searchalicious-distribution-chart>
<searchalicious-distribution-chart search-name="off" field="ecoscore_grade"></searchalicious-distribution-chart>
<searchalicious-distribution-chart search-name="off" field="nova_groups"></searchalicious-distribution-chart>
<searchalicious-scatter-chart search-name="off" x="nutriscore_score" y="nutriments.fiber_100g"></searchalicious-scatter-chart>
</div>
</searchalicious-layout-page>
Expand Down
25 changes: 23 additions & 2 deletions frontend/src/mixins/search-chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import {Constructor} from './utils';
// eslint-disable-next-line
declare const vega: any;

interface ChartSearchParamPOST {
chart_type: string,
field?: string,
x?: string,
y?: string
}

export type ChartSearchParam = ChartSearchParamPOST | string;


export interface SearchaliciousChartInterface extends LitElement {
vegaInstalled: Boolean;

Expand Down Expand Up @@ -33,8 +43,19 @@ export const SearchaliciousChartMixin = <T extends Constructor<LitElement>>(
this.vegaInstalled = this.testVegaInstalled();
}

getName() {
return '';
/**
* Return the GET or POST param used for the API
*/
getSearchParam(_isGetRequest: boolean): ChartSearchParam {
throw new Error('Not implemented')
}

/**
* The name is used to get the right vega chart from
* API search Result
*/
getName(): string {
throw new Error('Not implemented')
}

override render() {
Expand Down
90 changes: 42 additions & 48 deletions frontend/src/mixins/search-ctl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
SearchaliciousHistoryInterface,
SearchaliciousHistoryMixin,
} from './history';
import { SearchaliciousDistributionChart, SearchaliciousScatterChart } from '../search-chart';
import { ChartSearchParam } from './search-chart';
// import {SearchaliciousChartInterface} from './search-chart';

export interface SearchParameters extends SortParameters {
Expand All @@ -32,7 +34,7 @@ export interface SearchParameters extends SortParameters {
index_id?: string;
facets?: string[];
params?: string[];
charts?: object[];
charts?: string | ChartSearchParam[]
}
export interface SearchaliciousSearchInterface
extends EventRegistrationInterface,
Expand All @@ -55,19 +57,6 @@ export interface SearchaliciousSearchInterface
selectTermByTaxonomy(taxonomy: string, term: string): void;
}

// We should not use GET if other params than those are present in the search request
const supportedGETParams = new Set([
'q',
'langs',
'page_size',
'page',
'fields',
'sort_by',
'facets',
'index_id',
]);

// name of search params as an array (to ease iteration)

export const SearchaliciousSearchMixin = <T extends Constructor<LitElement>>(
superClass: T
Expand Down Expand Up @@ -260,35 +249,31 @@ export const SearchaliciousSearchMixin = <T extends Constructor<LitElement>>(
}

/**
* Get the list of charts we want to request
* Get the list of charts params we want to request
*/
_charts(): object[] | undefined {
const distributionCharts = Array.from(
document.querySelectorAll(
_chartParams(isGetRequest: boolean): ChartSearchParam[] | string | undefined {
const chartsParams: ChartSearchParam[] = []

document.querySelectorAll(
`searchalicious-distribution-chart[search-name=${this.name}]`
)
).map((node) => ({
chart_type: 'DistributionChartType',
// @ts-ignore
field: node.name,
}));

const scatterCharts = Array.from(
document.querySelectorAll(
`searchalicious-scatter-chart[search-name=${this.name}]`
)
).map((node) => ({
chart_type: 'ScatterChartType',
// @ts-ignore
x: node.x,
// @ts-ignore
y: node.y,
}));

if (distributionCharts.length === 0 && scatterCharts.length === 0)
).forEach(item => {
const chartItem = item as SearchaliciousDistributionChart;
chartsParams.push(chartItem.getSearchParam(isGetRequest));
});

document.querySelectorAll(
`searchalicious-scatter-chart[search-name=${this.name}]`
).forEach(item => {
const chartItem = item as SearchaliciousScatterChart;
chartsParams.push(chartItem.getSearchParam(isGetRequest));
});

if (chartsParams.length === 0)
return undefined;
// @ts-ignore
return distributionCharts.concat(scatterCharts);

if (isGetRequest) return chartsParams.join(',')

return chartsParams;
}

/**
Expand All @@ -314,11 +299,8 @@ export const SearchaliciousSearchMixin = <T extends Constructor<LitElement>>(
_searchUrl(page?: number) {
// remove trailing slash
const baseUrl = this.baseUrl.replace(/\/+$/, '');
const params = this.buildParams(page);
const { params, needsPOST } = this.buildParams(page);
// we needs a POST if a parameter is not supported by GET
const needsPOST =
Object.keys(params).filter((key) => !supportedGETParams.has(key))
.length > 0;
const history = this.buildHistoryParams(params);
// remove empty values from params
// (do this after buildHistoryParams to be sure to have all parameters)
Expand Down Expand Up @@ -417,7 +399,10 @@ export const SearchaliciousSearchMixin = <T extends Constructor<LitElement>>(
* Build the params to send to the search API
* @param page
*/
buildParams = (page?: number): SearchParameters => {
buildParams = (page?: number) => {

let needsPOST = false;

const queryParts = [];
this.lastQuery = this.query;
if (this.query) {
Expand All @@ -440,7 +425,12 @@ export const SearchaliciousSearchMixin = <T extends Constructor<LitElement>>(
// sorting parameters
const sortElement = this._sortElement();
if (sortElement) {
Object.assign(params, sortElement.getSortParameters());
const sortParameters = sortElement.getSortParameters();
if (sortParameters) {
console.log('sort parameters', sortParameters)
needsPOST = true;
Object.assign(params, sortParameters);
}
}
// page
if (page) {
Expand All @@ -450,8 +440,12 @@ export const SearchaliciousSearchMixin = <T extends Constructor<LitElement>>(
if (this._facets().length > 0) {
params.facets = this._facets();
}
params.charts = this._charts();
return params;

const charts = this._chartParams(!needsPOST);
if (charts) {
params.charts = charts;
}
return { params, needsPOST };
};

/**
Expand Down
24 changes: 22 additions & 2 deletions frontend/src/search-chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,19 @@ export class SearchaliciousDistributionChart extends SearchaliciousResultCtlMixi
// All these properties will change when vega logic
// will be moved in API.
@property()
name = '';
field = '';

override getName() {
return this.name;
return this.field;
}

getSearchParam(isGetRequest: boolean) {
if (isGetRequest) return this.field;
else
return {
chart_type: 'DistributionChartType',
field: this.field
};
}

// Vega function assumes that rendered had been previously
Expand Down Expand Up @@ -51,6 +60,17 @@ export class SearchaliciousScatterChart extends SearchaliciousResultCtlMixin(
return `${this.x}:${this.y}`;
}

getSearchParam(isGetRequest: boolean) {
if (isGetRequest)
return `${this.x}:${this.y}`;
else
return {
chart_type: 'ScatterChartType',
x: this.x,
y: this.y
};
}

// Vega function assumes that rendered had been previously
// called.
override handleResults(event: SearchResultEvent) {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/search-sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ export class SearchaliciousSort extends SearchActionMixin(
/**
* Get sort parameters of selected option or return an empty Object
*/
getSortParameters(): SortParameters {
getSortParameters(): SortParameters | null {
const option = this.currentSortOption();
return option ? option.getSortParameters() : {};
return option ? option.getSortParameters() : null;
}

/**
Expand Down

0 comments on commit 813df59

Please sign in to comment.