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

[Feature Request] Custom operators #149

Closed
Diluka opened this issue Jul 9, 2019 · 9 comments · May be fixed by #253 or #568
Closed

[Feature Request] Custom operators #149

Diluka opened this issue Jul 9, 2019 · 9 comments · May be fixed by #253 or #568

Comments

@Diluka
Copy link
Contributor

Diluka commented Jul 9, 2019

This feature allow developers to define new operators.

For example:

  1. define a new operator json_contains template
(alias, values)=> `JSON_CONTAINS(${alias}, ${values})`
  1. use like filter=roles||json_contains||ROLE_A,ROLE_B
  2. generate
andWhere('JSON_CONTAINS(roles, :roles)',{roles: JSON.stringify(roles)})
@joeybenenati
Copy link

Is there any plan to implement this? This flexibility would nice as I'm now forked and manually adding postgis operators as I need.

@rgolea
Copy link

rgolea commented Aug 27, 2019

@joeybenenati how do you add postgis operators? Can you share some code? I need to use ST_DWithin but I'm not really sure how. Can you help?

@joeybenenati
Copy link

@rgolea

  1. add operator to ComparisonOperator and CondOperator type in packages/crud-request/lib/types/request-query.types.d.ts
  2. In packages/crud-typeorm/src/typeorm-crud.service.ts to the switch in mapOperatorsToQuery
case 'notnull':
        ...
        str = `${field} IS NOT NULL`;
        params = {};
        break;

      case 'intersects':
        str = `ST_Intersects(${field}, ST_GeomFromGeoJSON(:${param}))`;
        break;

      case 'between':
       ...

@rgolea
Copy link

rgolea commented Aug 27, 2019

@joeybenenati Wow! That was fast! Thank you very much!!! Maybe afterwards I can study the project better and do a PR to add new params.

Note for later:
Maybe setting an operator called custom and set inside CrudRequestOptions something called custom or maybe just in parameters so you can configure something like:

@Crud({
   params: {
       custom: {
            intersects: (
                  field: string,
                  param: any,
             ) => `ST_Intersects(${field}, ST_GeomFromGeoJSON(:${param}))`
       }
   }
})

And then just adding to the service something like:

case 'notnull':
        ...
        str = `${field} IS NOT NULL`;
        params = {};
        break;

      case 'custom':
        str = options.custom[operator?](field, param);
        break;

      case 'between':
       ...

It's a rough draft but maybe it's a start? @joeybenenati if you can, please tell me if this is something that you'd be interested in or maybe just help me guide the code (since I've just discovered this project recently and I haven't tested everything yet).

@rgolea
Copy link

rgolea commented Sep 11, 2019

@joeybenenati could you help me with testing this feature out? I will also add tests but at the moment I would like to know that it works. (Please see #253 )

@joeybenenati
Copy link

@rgolea sorry, I've since abandoned using this package for my current project. It's a great set of tools but I need a little more flexibility. I too had some trouble navigating and testing the project. I need to adhere to STAC API spec but would also like to incorporate a json based api query language simlar to loopback 3.

@Diluka
Copy link
Contributor Author

Diluka commented Feb 5, 2020

this validation(see below) is preventing custom operators. But we can reuse the built-in operators to change their behaviors. for example #150 (comment) changes eq and in

export function validateComparisonOperator(operator: ComparisonOperator): void {
if (!comparisonOperatorsList.includes(operator)) {
throw new RequestQueryException(
`Invalid comparison operator. ${comparisonOperatorsListStr} expected`,
);
}
}

@Diluka Diluka closed this as completed Feb 5, 2020
@rgolea
Copy link

rgolea commented Feb 5, 2020

@Diluka the PR I pushed would have fixed the problem (hopefully)

@prevostc
Copy link

prevostc commented Sep 15, 2020

If that helps, I was able to implement a custom operator by overriding mapOperatorsToQuery on the service

  protected mapOperatorsToQuery(cond: QueryFilter, param: any): { str: string; params: ObjectLiteral } {
    if (cond.field === "tags") {
      let str: string
      let params: ObjectLiteral = { [param]: cond.value }

      const field = this.getFieldWithAlias(cond.field)
      switch (cond.operator) {
        case "$cont":
          str = `${field} @> :${param}::jsonb`
          params = { [param]: `${JSON.stringify(cond.value)}` }
          break
        default:
          str = `${field} = :${param}::jsonb`
          break
      }
      return { str, params }
    } else {
      return super.mapOperatorsToQuery(cond, param)
    }
  }

This is a bit of a manual work, but it could be generalised. And it makes sense to override the service protected methods to add new functionality.

Maybe all that is needed is a "Custom operator" section on the wiki.

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