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: add custom filter function #632

Open
wants to merge 6 commits into
base: development
Choose a base branch
from

Conversation

KevinRohlf
Copy link
Collaborator

@KevinRohlf KevinRohlf commented Nov 20, 2024

Implements #614

Proposed Changes

  • add a custom filter function

@KevinRohlf KevinRohlf requested a review from a team as a code owner November 20, 2024 15:42
Copy link

vercel bot commented Nov 20, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
mvg-portal ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 18, 2024 0:59am

@KevinRohlf KevinRohlf changed the base branch from main to development November 20, 2024 15:43
filters.config.js Outdated Show resolved Hide resolved
src/components/Search/Filter.tsx Outdated Show resolved Hide resolved
filters.config.js Outdated Show resolved Hide resolved
let searchTerm = text || ''
let nestedQuery
if (tags) {
filters.push(getFilterTerm('metadata.tags.keyword', tags))
} else if (gaiax) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question(blocking): Is this query not compatible with tags or why is it only applied if tags is falsy?

src/@types/aquarius/BaseQueryParams.d.ts Outdated Show resolved Hide resolved
filters.config.js Outdated Show resolved Hide resolved
src/@types/aquarius/BaseQueryParams.d.ts Outdated Show resolved Hide resolved
src/@utils/aquarius/index.ts Outdated Show resolved Hide resolved
src/@utils/aquarius/index.ts Outdated Show resolved Hide resolved
export function getFilter(...args: any[]) {
let filters = []
if (typeof args[0] === 'object') {
args[0].forEach((arg) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(blocking): In general prefer usage of for...of over forEach for readability and performance. More context: https://biomejs.dev/linter/rules/no-for-each/

This comment applies to all places in the code where forEach is being used.

…ery interface and FILTER_VALUES, update getSearchQuery function
Comment on lines 6 to 22
interface BoolFilter {
bool: BoolFilterQuery
}

interface BoolFilterQuery {
must: {
exists: {
field: string
}
}
must_not?: {
term: {
[key: string]: string
}
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(blocking): The BoolFilterQuery type is named to generally for what it does. Specifically these are the type definitions for the new must_exist and must_exits_and_not_empty filters of this PR. Naming these accordingly is suggested (e.g. MustExistQuery and MustNotTermQuery or similar)

I also suggest to rename the key identifier to field to better communicate what value is expected here.

Comment on lines 6 to 21
interface BoolFilter {
bool: BoolFilterQuery
}

interface BoolFilterQuery {
must: {
exists: {
field: string
}
}
must_not?: {
term: {
[key: string]: string
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(non-blocking): this is also a nice use-case for typescript generics

In our case, these filters should always be used on a field path that is to be defined by the user. We expect a certain behaviour though, e.g. something like the following could improve DX with TS, as it helps enforcing correct types (in this case the field path value).

type FieldPath = string

interface BoolFilter<T extends FieldPath> {
  bool: MustExistQuery<T> & MustNotTermQuery<T>
}

interface MustExistQuery<T extends FieldPath> {
  must: {
    exists: {
      field: T
    }
  }
}

interface MustNotTermQuery<T extends FieldPath> {
  must_not?: {
    term: {
      [field in T]: string
    }
  }
}

@@ -11,6 +28,7 @@ interface BaseQueryParams {
sortOptions?: SortOptions
aggs?: any
filters?: FilterTerm[]
boolFilter?: BoolFilter[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue(blocking): i don't think this is supported by elasticsearch (array of bool) and should be adjusted.

suggestion: we could treat it like filters, where we define what the BoolTerm should look like and then allow passing an array BoolTerm[] here.
Also possible is to only allow the defined type to be passed, e.g. BoolFilter

@@ -56,6 +57,39 @@ export function getFilterTerm(
}
}

export function getFilter(...args: any[]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue(blocking): we should try not to use any as type here. If it is needed, we need to add a comment disabling eslint for this line and describing why the any type is used

Comment on lines 64 to 65
const filter = arg.split('=')
filters = [...filters, filter]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(blocking): move this code to a named function and reuse it to increase readability

@@ -160,7 +197,8 @@ export function generateBaseQuery(
...(baseQueryParams.showSaas === false ? [saasFieldExists] : [])
]
}
}
},
...(baseQueryParams.boolFilter || [])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(non-blocking): use an empty object rather than empty array for better readability of the code.

let updatedFilters
if (option.queryPath) {
updatedFilters = filters[filterId].includes(
`${option.queryPath}=${option.value}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(blocking): make this re-usable by wrapping it into a named function. Can then be accessed in the various places in code (e.g. getFilterQueryString or similar)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also will get more readable once adapting existing filters to the new, more flexible structure and a lot of code can be removed here.

? {
...filters,
[filterId]: filters[filterId].filter(
(e) => e !== `${option.queryPath}=${option.value}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(blocking): avoid shorthand variable name and replace with more readable variant

Comment on lines 9 to 27
{
id: 'serviceType',
label: 'Service Type',
type: 'filterList',
options: [
{ label: 'datasets', value: FilterByTypeOptions.Data },
{ label: 'algorithms', value: FilterByTypeOptions.Algorithm },
{ label: 'saas', value: FilterByTypeOptions.Saas }
]
},
{
id: 'accessType',
label: 'Access Type',
type: 'filterList',
options: [
{ label: 'download', value: FilterByAccessOptions.Download },
{ label: 'compute', value: FilterByAccessOptions.Compute }
]
},
Copy link
Contributor

@moritzkirstein moritzkirstein Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(blocking): to reduce complexity and avoid having to define filters differently depending on the id we should simply move these filters over to the new specs. This would then look something like the example in the issue:

{
      id: 'serviceType',
      label: 'Service Type',
      type: 'filterList',
      // add a "global" query path that gets used as fallback if options have none defined
      queryPath: 'metadata.type', 
      options: [
        { label: 'datasets', value: FilterByTypeOptions.Data },
        { label: 'algorithms', value: FilterByTypeOptions.Algorithm },
        { label: 'saas', value: FilterByTypeOptions.Saas }
      ]
    },    
//...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants