Skip to content

ternary nullness logic implementation #113

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

Conversation

NathanQingyangXu
Copy link
Contributor

@NathanQingyangXu NathanQingyangXu commented Jul 21, 2025

https://jira.mongodb.org/browse/HIBERNATE-74

The most complex and challenging task in m3!

The following constraints are put into place for this PR:

  1. only find expression is invovled (as discussed previously, $expr is out of scope of m3)
  2. no field-wise comparison is involved (which shares the above reason for it is not supported by find expression)
  3. ternary logic scope is restrictive to filter, not to projection (m3's projection is still restrictive to entity fields, not ad-hoc expression)

The basic idea is to exclude null fields preemptively to emulate HQL/SQL's ternary nullness logic for and only for AstFieldOperationFilter translation (AstLogicalFilter won't be touched).

for instance, the following is the original Mql translation result containing JDBC placeholder (as the $match aggregation stage) for the from Book where title = :title HQL selection query):

{
  "$match": {
      {
        "title": {
          "$eq": {"$undefined: true}
        }
      }
  }
}

This PR will transform it as belows to exclude null title to emulate ternary logic

{
  "$match": {
    {
      "$and": [
        {
          "title": {
            "$eq": {"$undefined: true}
          }
        },
        {
          "title": {
            "$ne": null
          }
        }
      ]
    }
}

An example involving logical operator (corresponds to HQL: ... where country = :country and age > :age):

{
    "$match": {
      "$and": [
        {
          "$and": [
            {
              "country": {
                "$eq": "CANADA"
              }
            },
            {
              "country": {
                "$ne": null
              }
            }
          ]
        },
        {
          "$and": [
            {
              "age": {
                "$gt": 18
              }
            },
            {
              "age": {
                "$ne": null
              }
            }
          ]
        }
      ]
    }
  }

Note that we only replace file comparison expression with its nullness exclusion condition.

Why excluding null field during comparison could work? I give some reasons below:

  1. when HQL/SQL encounters a null field, NULL value would be generated and propergated all the way up until it either reaches the where clause top level or some internal or operator; regardless it will end up with false and won't contribute to the record to be returned; excluding null fields preemptively ends up with the same retrieval result; in this sense it is an indirect emulation.
  2. another natural alternative is to emulate ternary null logic using Mql's verbose counterpart, but it would end up with performance issue for it requires dynamic computing so ended up with linear scanning; the nullness exclusion approach will tap into existing field index without such perf issue

Existing SimpleSelectQueryIntegrationTests integration testing cases will showcase the new null-safe Mql translation results for they contain resulting Mql validation logic.

@NathanQingyangXu NathanQingyangXu force-pushed the HIBERNATE-74-new branch 4 times, most recently from 3932e42 to 3d627d3 Compare July 24, 2025 15:11
@NathanQingyangXu
Copy link
Contributor Author

NathanQingyangXu commented Jul 24, 2025

@vbabanin , I included your testing case as the SimpleSelectQueryIntegrationTests#testDoubleNegationWithOr(): https://github.com/mongodb/mongo-hibernate/pull/113/files#diff-4fa7f77a5946a460fb6bb05b949ecab9236434f6172a270f25919bec2f74f5f6. Thanks to your testing case so I simplified the implementation and I think current approach makes more sense.

@NathanQingyangXu
Copy link
Contributor Author

close this DRAFT PR for its implementation is based on some invalid assumption.

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.

1 participant