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

types: Update Expression Typings #11956

Merged
merged 2 commits into from
Jun 21, 2022

Conversation

andreialecu
Copy link
Contributor

Summary

Fixes #11952

@Uzlopak
Copy link
Collaborator

Uzlopak commented Jun 20, 2022

Let me see

Copy link
Collaborator

@Uzlopak Uzlopak left a comment

Choose a reason for hiding this comment

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

We have to think about this more

types/expressions.d.ts Outdated Show resolved Hide resolved
}

type Path = string;
type Path = string | ObjectIdLike;
Copy link
Collaborator

Choose a reason for hiding this comment

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

No. Path is just a Path. Not ObjectIdLike.

Suggested change
type Path = string | ObjectIdLike;
type Path = string;

Copy link
Collaborator

Choose a reason for hiding this comment

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

I created a separate type, so that one day if we have good way to generate valid paths by mongoose Schema we would already have it properly encapsulated it.

@@ -2594,7 +2608,8 @@ declare module 'mongoose' {
export type ConditionalExpressionOperator =
Expression.Cond |
Expression.IfNull |
Expression.Switch;
Expression.Switch |
Expression.Exists;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Expression.Exists;

Copy link

@Jule- Jule- Jun 21, 2022

Choose a reason for hiding this comment

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

I am not aware of all changes but it seems that $exists is not accepted anymore by the typings.

Wherever you put it, this should work:

const result = await Model.aggregate([{
  $match: { optional: { $exists: true } }
}]);

mongoose@6.4.0:

Type '{ $exists: true; }' is not assignable to type 'Expression'.

@@ -2594,7 +2608,8 @@ declare module 'mongoose' {
export type ConditionalExpressionOperator =
Expression.Cond |
Expression.IfNull |
Expression.Switch;
Expression.Switch |
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Expression.Switch |
Expression.Switch;

@@ -2428,7 +2441,8 @@ declare module 'mongoose' {
DateExpression |
BinaryExpression |
FunctionExpression |
ObjectIdExpression;
ObjectIdExpression |
ConditionalExpressionOperator;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this is kind of wrong.

@andreialecu
Copy link
Contributor Author

@Uzlopak just wanted to get the ball rolling.

If you want to open your own PR (please!), feel free to. You can copy the tests from mine.

@Uzlopak
Copy link
Collaborator

Uzlopak commented Jun 20, 2022

I think there is a mixup. What you want to add is a Query Operator, but the expressions are for aggregations. I have to think how we can solve this without mixing it up.

@andreialecu
Copy link
Contributor Author

There's also a problem with booleans, like {$ne: true}, and I'd assume numbers as well.

Type '{ $ne: true; }' is not assignable to type 'Expression | undefined'.
              Types of property '$ne' are incompatible.
                Type 'true' is not assignable to type 'Expression | [Expression, Expression] | undefined'.

@Uzlopak
Copy link
Collaborator

Uzlopak commented Jun 20, 2022

Well it is wrong because in an aggregation pipeline $ne is an array with two values, which are compared.

@Uzlopak
Copy link
Collaborator

Uzlopak commented Jun 20, 2022

@andreialecu
Copy link
Contributor Author

Both are valid in different contexts, see: https://stackoverflow.com/a/15330673/114732

@andreialecu
Copy link
Contributor Author

From mongodb docs at https://www.mongodb.com/docs/manual/reference/operator/aggregation/match/#mongodb-pipeline-pipe.-match:

$match takes a document that specifies the query conditions. The query syntax is identical to the read operation query syntax; i.e. $match does not accept raw aggregation expressions. Instead, use a $expr query expression to include aggregation expression in $match.

@andreialecu
Copy link
Contributor Author

andreialecu commented Jun 20, 2022

I think $match is defined incorrectly now, and it needs to be something like this instead:

    export interface Match {
      /** [`$match` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/match/) */
      $match: FilterQuery<any>;
    }

It would be great if instead of any, T could be better passed down, but that seems to require a bit of additional work to wire up everywhere.

@Uzlopak
Copy link
Collaborator

Uzlopak commented Jun 20, 2022

I think we have to rename expressions.d.ts to aggregationpipelineexpressions.d.ts and create also corresponding types for the other operations and then decide how and which expressions are allowed when and where

@andreialecu
Copy link
Contributor Author

andreialecu commented Jun 20, 2022

I think the main issue is with $match being defined as using expressions when instead it's a regular filter query.

There's a special case for that one. I had to step away for a bit so I can't verify, but simply fixing that might fix most of the issues in one shot.

@andreialecu
Copy link
Contributor Author

Actually FilterQuery<T> won't work properly now that I think of it. It needs to be FilterQuery<any> because a previous step might do a projection which changes the shape of the document arbitrarily.

Co-authored-by: Uzlopak <aras.abbasi@googlemail.com>
@@ -1034,7 +1036,7 @@ declare module 'mongoose' {
*
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/ne/#mongodb-expression-exp.-ne
*/
$ne: Expression | [Expression, Expression];
$ne: Expression | [Expression, Expression] | null;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would just adding | null to Expression work better here? So you can use null in other places as well.

Copy link
Collaborator

@vkarpov15 vkarpov15 left a comment

Choose a reason for hiding this comment

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

I'll merge this for now to unblock @andreialecu .

However, there are still some issues with the expression typings. For one thing @Uzlopak , I think we'll have to add AnyObject, because the following code will still fail:

  {
    $match: {
      _id: new ObjectId('stringObjecId'),
      a: { $exists: true },
      b: null,
      c: 'test',
      d: { foo: 42 } // <-- valid, but current typings will fail
    }
  }

@vkarpov15 vkarpov15 added this to the 6.4.1 milestone Jun 21, 2022
@vkarpov15 vkarpov15 merged commit fdb303a into Automattic:master Jun 21, 2022
@Uzlopak
Copy link
Collaborator

Uzlopak commented Jun 21, 2022

I'll be honest:
I think we should revert the expressions PR. It needs more work to work properly.

@andreialecu
Copy link
Contributor Author

Indeed, this wasn't totally ready to merge - I forgot to set it to draft. I thought @Uzlopak would work on his PR.

I also wanted to suggest reverting the expressions PR, but it might not be necessary with this change:

    export interface Match {
      /** [`$match` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/match/) */
      $match: FilterQuery<any>;
    }

$match is supposed to be a regular filter; it's not an aggregation expression - I think that's where most of the problems originate. With this change, the scenario mentioned by @vkarpov15 should also work correctly.

I opened #11969 with a better fix

@andreialecu andreialecu mentioned this pull request Jun 22, 2022
@lucamodica
Copy link

Does $nin operator still exists? For the moment I have to workaround with

{ $not: { $in: [<expression>, <arrayExpression>] } }

@lucamodica
Copy link

I ask the same question for the $exists operator

@vkarpov15
Copy link
Collaborator

@lucamodica yes $nin still is an operator on the MongoDB server. Does $nin not work for you in Mongoose 6.4?

@lucamodica
Copy link

Nope, or at least both $nin and $exists are not recognized as Expression .

@andreialecu
Copy link
Contributor Author

#11969 should fix this.

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.

aggregate $match Error: Type 'ObjectId' is not assignable to type 'Expression'.
5 participants