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(NODE-4964): support range indexes #533

Merged
merged 7 commits into from
Jan 23, 2023

Conversation

baileympearson
Copy link
Contributor

@baileympearson baileympearson commented Jan 19, 2023

This PR adds range index support in explicit encryption.

Changes included

  • ClientEncryption.encrypt() logic was refactored to a private helper to be shared between encrypt() and encryptExpression()
  • A new option, expressionMode, is passed down from _encrypt() into the bindings. This toggles whether or not we are encrypting an expression or a regular bson value.
  • maybeCallback was copied into the bindings
  • documentation was generated

JIRA LINK
https://jira.mongodb.org/browse/NODE-4964

@baileympearson baileympearson force-pushed the NODE-4964-add-range-index-support branch from def2095 to 0a1d1c2 Compare January 19, 2023 18:50
@@ -528,64 +528,89 @@ Value MongoCrypt::MakeExplicitEncryptionContext(const CallbackInfo& info) {
throw TypeError::New(Env(), "Parameter `value` must be a Buffer");
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I recommend hiding whitespace changes for this diff

bindings/node/src/mongocrypt.cc Outdated Show resolved Hide resolved
bindings/node/src/mongocrypt.cc Outdated Show resolved Hide resolved
bindings/node/src/mongocrypt.cc Show resolved Hide resolved
@baileympearson baileympearson force-pushed the NODE-4964-add-range-index-support branch 2 times, most recently from 1c2b7ba to f640102 Compare January 20, 2023 19:32
@baileympearson baileympearson force-pushed the NODE-4964-add-range-index-support branch from 810dc72 to 5f6dd92 Compare January 22, 2023 13:06
bindings/node/README.md Outdated Show resolved Hide resolved
bindings/node/README.md Outdated Show resolved Hide resolved
bindings/node/README.md Outdated Show resolved Hide resolved
bindings/node/lib/clientEncryption.js Outdated Show resolved Hide resolved
bindings/node/lib/clientEncryption.js Outdated Show resolved Hide resolved
bindings/node/src/mongocrypt.cc Outdated Show resolved Hide resolved
- move string comparison for `rangePreview` into C++
- clean up documentation for KMS providers
- remove _encrypt() and askForKMSProviders() from external docs
bindings/node/index.d.ts Outdated Show resolved Hide resolved
Comment on lines 56 to 57
result => callback(undefined, result),
error => callback(error)
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that this will make exceptions from the callback result in an unhandled rejection rather than an uncaught exception; that’s a visible behavioral change. You may want to do something like this instead:

Suggested change
result => callback(undefined, result),
error => callback(error)
result => process.nextTick(callback, undefined, result),
error => process.nextTick(callback, error)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Neal and I looked at this for a while and, while we believe you're right, we actually couldn't reproduce the issue.

async function wait() {
  await setTimeout(1000);
}
maybeCallback(() => wait(), () => { throw new Error("crashed process") });

Doesn't result in an UnhandledPromiseRejection

Copy link
Contributor

Choose a reason for hiding this comment

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

Are you sure? Running this code (as node test.js with Node.js 16 through 19 at least) results in the unhandled rejection handler being called:

function maybeCallback(promiseFn, callback) {
  const promise = promiseFn();
  if (callback == null) {
    return promise;
  }

  promise.then(
    result => callback(undefined, result),
    error => callback(error)
  );
  return;
}

async function wait() {
  await setTimeout(1000);
}

process.on('unhandledRejection', (...args) => console.log('unhandledRejection', args));

maybeCallback(() => wait(), () => { throw new Error("crashed process") });

Copy link
Contributor

Choose a reason for hiding this comment

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

ah, we were looking for the unhandledRejection console log message, ty! We should make this improvement here, we'll want to file a follow up to replicate it elsewhere we've wrapped callbacks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, you're right. For some reason, the unhandled promise isn't being printed as an unhandled promise (we should have listened for unhandled promises).

We filed a follow up ticket for the driver and legacy driver: https://jira.mongodb.org/browse/NODE-4996

Copy link
Contributor

Choose a reason for hiding this comment

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

The default mode for unhandled rejections was changed to throwing in Node.js 15, which is why I think you weren’t seeing this printed as a warning: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V15.md#throw-on-unhandled-rejections---33021

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We compared it with just rejecting a promise. It's interesting because there is a difference between the output when we just reject the promise and when we crash the process in maybe callback.

Maybe the error thrown inside the maybeCallback hits a different codepath than the promise rejection here. Maybe I'll try running NodeJS source and stepping through with a debugger 🤔.

But regardless, they're both unhandled promise rejections (and you can test this by adding back the unhandled rejection listener).

const { setTimeout } = require('timers/promises');

function maybeCallback(promiseFn, callback) {
  const promise = promiseFn();
  if (callback == null) {
    return promise;
  }

  promise.then(
    result => callback(undefined, result),
    error => callback(error)
  );
  return;
}


setTimeout(1000).then(() => console.log('program continued'));

maybeCallback(() => setTimeout(200), () => { throw new Error("crashed process") });

// (function rejects() {
	// return Promise.reject();
// })()	

bindings/node/test/clientEncryption.test.js Outdated Show resolved Hide resolved
bindings/node/test/clientEncryption.test.js Outdated Show resolved Hide resolved
bindings/node/test/clientEncryption.test.js Outdated Show resolved Hide resolved
bindings/node/test/clientEncryption.test.js Show resolved Hide resolved
@baileympearson
Copy link
Contributor Author

I linted our d.ts file, which might make the diff hard to read. It's in its own commit, so the changes to that file can either be viewed in other commits or I can revert that commit.

@nbbeeken nbbeeken merged commit 0ccb7b6 into master Jan 23, 2023
@nbbeeken nbbeeken deleted the NODE-4964-add-range-index-support branch January 23, 2023 21:45
@nbbeeken nbbeeken changed the title feat(NODE-4694): support range indexes feat(NODE-4964): support range indexes Jan 23, 2023
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